Django用户模型,添加功能

30
我想要给Django的默认用户模型添加一个新功能,以便检索与其相关的Model类型的列表。
像这样的Foo模型:
class Foo(models.Model):
    owner = models.ForeignKey(User, related_name="owner")
    likes = models.ForeignKey(User, related_name="likes")

........

    #at some view
    user = request.user
    foos= user.get_related_foo_models()

如何实现这一目标?


2
知道,但我不想添加自定义字段,只是想要一个函数而不改变原始的用户模型。 - Hellnar
1
http://docs.djangoproject.com/en/1.2/ref/models/relations/#django.db.models.fields.related.RelatedManager - alex vasi
4个回答

46

你可以给User添加一个方法。

from django.contrib import auth
auth.models.User.add_to_class('get_related_foo_models', get_related_foo_models)

请确保将此代码放置在models.py或其他在Django启动时被导入的文件中。


6
我相信Monkey Patching通常是不受欢迎的。请参见此处的讨论:http://stackoverflow.com/a/965859/406157 - Jeremy Blanchard
1
OneToOneField 绝对是处理这个问题的正确方式。 - Derek Adair
1
@DerekAdair 我们正在讨论向类中添加一个方法。使用OneToOneField需要修改数据库,这是完全不必要的,以实现添加方法的目标。 - Louis
@Louis,仅仅因为你能够这样做,并不意味着你应该这样做,这种方法存在许多副作用。在某些情况下,这些副作用可以忽略不计,但OneToOneField是实现这一目的的“正确”方式。我想我的评论最好表述为:“这几乎总是应该这样做的方式”。 - Derek Adair
1
@DerekAdair,你很难找到我写的任何一篇文章中有这样的论点:“你应该这样做,因为你可以这样做”。 - Louis

14

这是对@Lakshman Prasad答案的更新。下面是一个完整的例子:

在你的apps中的任何一个位置创建一个名为monkey_patching.py的文件:

#app/monkey_patching.py
from django.contrib.auth.models import User 

def get_user_name(self):
    if self.first_name or self.last_name:
        return self.first_name + " " + self.last_name
    return self.username

User.add_to_class("get_user_name",get_user_name)

并将其导入到应用程序的__init__.py文件中。例如:

#app/__init__.py
import monkey_patching

点赞。感谢您的努力完善答案。 - lprsd

4

根据文档中所述,替换用户模型并不罕见: https://docs.djangoproject.com/es/1.9/topics/auth/customizing/#substituting-a-custom-user-model,因此,在考虑这一点时,最好使用以下代码获取用户模型类:

from django.contrib.auth import get_user_model
UserModel = get_user_model()

之后,你可以像 @Lakshman Prasad 建议的那样使用这个 UserModel 来添加功能:UserModel.add_to_class('get_related_foo_models', get_related_foo_models)
为了让代码只执行一次,我更喜欢使用Django应用程序配置类(https://docs.djangoproject.com/es/1.9/ref/applications/),因此一个完整的工作示例将是:
# myapp/__init__.py
default_app_config = 'myapp.apps.MyAppConfig'

# myapp/apps.py
from django.apps import AppConfig
from django.contrib.auth import get_user_model


class MyAppConfig(AppConfig):
    name = 'myapp'
    verbose_name = 'MyApp'

    def ready(self):
        # Add some functions to user model:
        def custom_function(self):
            # Do whatsoever
            pass

        UserModel = get_user_model()
        UserModel.add_to_class('custom_function', custom_function)

新的链接到自定义用户文档 https://docs.djangoproject.com/en/3.1/topics/auth/customizing/#using-a-custom-user-model-when-starting-a-project - Peter Chaula

2
您可以使用代理模型来向用户模型添加方法,而无需更改其类。
from django.contrib.auth import models

class UserProxy(models.User):
    class Meta:
        proxy = True
    
    def get_related_foo_models(self):
        pass

在视图中获取代理模型的实例 - models.UserProxy.objects.get(pk=request.user.pk)

若要立即从请求中获取代理模型的实例,则需要创建一个自定义的ModelBackend,如此问题所述 - Django - User proxy model from request

来源:https://docs.djangoproject.com/en/4.1/topics/db/models/#proxy-models


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接