使用Django中的自定义字段扩展用户模型

Extending the User model with custom fields in Django

使用自定义字段扩展用户模型(与Django的身份验证应用程序捆绑在一起)的最佳方法是什么?我也可能想使用电子邮件作为用户名(用于身份验证)。

我已经看到了一些方法,但无法决定哪一种是最好的。


Django推荐的最不痛苦的方法是通过OneToOneField(User)属性。

Extending the existing User model

If you wish to store information related to User, you can use a one-to-one relationship to a model containing the fields for additional information. This one-to-one model is often called a profile model, as it might store non-auth related information about a site user.

也就是说,扩展EDOCX1[1]并取代它也有效…

Substituting a custom User model

Some kinds of projects may have authentication requirements for which Django’s built-in User model is not always appropriate. For instance, on some sites it makes more sense to use an email address as your identification token instead of a username.

[Ed: Two warnings and a notification follow, mentioning that this is pretty drastic.]

我绝对不会更改Django源代码树中的实际用户类和/或复制和更改auth模块。


注意:此答案已弃用。如果您使用的是django 1.7或更高版本,请参阅其他答案。

我就是这样做的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#in models.py
from django.contrib.auth.models import User
from django.db.models.signals import post_save

class UserProfile(models.Model):  
    user = models.OneToOneField(User)  
    #other fields here

    def __str__(self):  
          return"%s's profile" % self.user  

def create_user_profile(sender, instance, created, **kwargs):  
    if created:  
       profile, created = UserProfile.objects.get_or_create(user=instance)  

post_save.connect(create_user_profile, sender=User)

#in settings.py
AUTH_PROFILE_MODULE = 'YOURAPP.UserProfile'

这将在每次保存用户时创建一个用户配置文件(如果已创建)。然后你可以使用

1
  user.get_profile().whatever

这是从医生那里得到的更多信息

http://docs.djangoproject.com/en/dev/topics/auth/存储有关用户的其他信息

更新:请注意,由于v1.5:https://docs.djangoproject.com/en/1.5/ref/settings/auth profile module,因此不推荐使用AUTH_PROFILE_MODULE


好吧,从2008年以来已经过去了一段时间,现在是时候换个新答案了。自Django1.5以来,您将能够创建自定义用户类。实际上,在我写这个的时候,它已经合并到master中了,所以你可以试试看。

在文档中有一些关于它的信息,或者如果您想深入了解它,在这个提交中。

您所要做的就是将AUTH_USER_MODEL添加到带有自定义用户类路径的设置中,它可以扩展AbstractBaseUser(更可自定义的版本)或AbstractUser(您可以扩展多少个旧的用户类)。

对于那些懒于点击的人,下面是代码示例(取自文档):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
from django.db import models
from django.contrib.auth.models import (
    BaseUserManager, AbstractBaseUser
)


class MyUserManager(BaseUserManager):
    def create_user(self, email, date_of_birth, password=None):
       """
        Creates and saves a User with the given email, date of
        birth and password.
       """
        if not email:
            raise ValueError('Users must have an email address')

        user = self.model(
            email=MyUserManager.normalize_email(email),
            date_of_birth=date_of_birth,
        )

        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, username, date_of_birth, password):
       """
        Creates and saves a superuser with the given email, date of
        birth and password.
       """
        u = self.create_user(username,
                        password=password,
                        date_of_birth=date_of_birth
                    )
        u.is_admin = True
        u.save(using=self._db)
        return u


class MyUser(AbstractBaseUser):
    email = models.EmailField(
                        verbose_name='email address',
                        max_length=255,
                        unique=True,
                    )
    date_of_birth = models.DateField()
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)

    objects = MyUserManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['date_of_birth']

    def get_full_name(self):
        # The user is identified by their email address
        return self.email

    def get_short_name(self):
        # The user is identified by their email address
        return self.email

    def __unicode__(self):
        return self.email

    def has_perm(self, perm, obj=None):
       "Does the user have a specific permission?"
        # Simplest possible answer: Yes, always
        return True

    def has_module_perms(self, app_label):
       "Does the user have permissions to view the app `app_label`?"
        # Simplest possible answer: Yes, always
        return True

    @property
    def is_staff(self):
       "Is the user a member of staff?"
        # Simplest possible answer: All admins are staff
        return self.is_admin


由于django 1.5,您可以轻松地扩展用户模型并在数据库中保留一个表。

1
2
3
4
5
6
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.utils.translation import ugettext_lazy as _

class UserProfile(AbstractUser):
    age = models.PositiveIntegerField(_("age"))

还必须将其配置为设置文件中的当前用户类

1
2
# supposing you put it in apps/profiles/models.py
AUTH_USER_MODEL ="profiles.UserProfile"

如果你想增加很多用户的偏好,OneTooneField选项可能是一个更好的选择。

开发第三方库的人员注意:如果您需要访问用户类,请记住,用户可以更改它。使用官方助手获得正确的课程

1
2
3
from django.contrib.auth import get_user_model

User = get_user_model()


关于存储有关用户的附加信息,有一个官方建议。Django的书也在章节简介中讨论了这个问题。


下面是扩展用户的另一种方法。我觉得它比上述两种方法更清晰、更容易阅读。

http://scottbarnham.com/blog/2008/08/21/extending-the-django-user-model-with-inheritance/

使用上述方法:

  • 你不需要使用user.get_profile().newattribute访问附加信息与用户相关
  • 您可以直接访问其他新属性通过user.newattribute

  • 每次使用django post save信号创建用户时,只需创建一个新条目即可扩展用户配置文件。

    型号.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    from django.db.models.signals import *
    from __future__ import unicode_literals

    class userProfile(models.Model):

        userName = models.OneToOneField(User, related_name='profile')
        city = models.CharField(max_length=100, null=True)

        def __unicode__(self):  # __str__
            return unicode(self.userName)

    def create_user_profile(sender, instance, created, **kwargs):
        if created:
        userProfile.objects.create(userName=instance)

    post_save.connect(create_user_profile, sender=User)

    这将在创建新用户时自动创建员工实例。

    如果希望扩展用户模型并希望在创建用户时添加更多信息,可以使用django betterforms(http://django betterforms.readthedocs.io/en/latest/multiform.html)。这将创建一个用户添加表单,其中包含在用户配置文件模型中定义的所有字段。

    型号.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from django.db.models.signals import *
    from __future__ import unicode_literals

    class userProfile(models.Model):

        userName = models.OneToOneField(User)
        city = models.CharField(max_length=100)

        def __unicode__(self):  # __str__
            return unicode(self.userName)

    。表格.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    from django import forms
    from django.forms import ModelForm
    from betterforms.multiform import MultiModelForm
    from django.contrib.auth.forms import UserCreationForm
    from .models import *

    class profileForm(ModelForm):

        class Meta:
            model = Employee
            exclude = ('userName',)


    class addUserMultiForm(MultiModelForm):
        form_classes = {
            'user':UserCreationForm,
            'profile':profileForm,
        }

    视图.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    from django.shortcuts import redirect
    from .models import *
    from .forms import *
    from django.views.generic import CreateView

    class addUser(CreateView):
        form_class = addUserMultiForm
        template_name ="addUser.html"
        success_url = '/your url after user created'

        def form_valid(self, form):
            user = form['user'].save()
            profile = form['profile'].save(commit=False)
            profile.userName = User.objects.get(username= user.username)
            profile.save()
            return redirect(self.success_url)

    。添加用户.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="UTF-8">
            Title
        </head>
        <body>
            <form action="." method="post">
                {% csrf_token %}
                {{ form }}    
                <button type="submit">Add</button>
            </form>
         </body>
    </html>

    号网址.py

    1
    2
    3
    4
    5
    from django.conf.urls import url, include
    from appName.views import *
    urlpatterns = [
            url(r'^add-user/$', addUser.as_view(), name='addDistributor'),
    ]


    像专业人员一样扩展django用户模型(userprofile)

    我发现这个非常有用:链接

    摘录:

    从django.contrib.auth.models导入用户

    1
    2
    3
    4
    5
    6
    class Employee(models.Model):
        user = models.OneToOneField(User)
        department = models.CharField(max_length=100)

    >>> u = User.objects.get(username='fsmith')
    >>> freds_department = u.employee.department


    Django1.5中的新功能,现在您可以创建自己的自定义用户模型(在上述情况下,这似乎是一件好事)。请参阅"在Django中自定义身份验证"

    可能是1.5版本中最酷的新功能。


    这就是我所做的,在我看来,这是最简单的方法。为新的自定义模型定义对象管理器,然后定义模型。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    from django.db import models
    from django.contrib.auth.models import PermissionsMixin, AbstractBaseUser, BaseUserManager

    class User_manager(BaseUserManager):
        def create_user(self, username, email, gender, nickname, password):
            email = self.normalize_email(email)
            user = self.model(username=username, email=email, gender=gender, nickname=nickname)
            user.set_password(password)
            user.save(using=self.db)
            return user

        def create_superuser(self, username, email, gender, password, nickname=None):
            user = self.create_user(username=username, email=email, gender=gender, nickname=nickname, password=password)
            user.is_superuser = True
            user.is_staff = True
            user.save()
            return user



      class User(PermissionsMixin, AbstractBaseUser):
        username = models.CharField(max_length=32, unique=True, )
        email = models.EmailField(max_length=32)
        gender_choices = [("M","Male"), ("F","Female"), ("O","Others")]
        gender = models.CharField(choices=gender_choices, default="M", max_length=1)
        nickname = models.CharField(max_length=32, blank=True, null=True)

        is_active = models.BooleanField(default=True)
        is_staff = models.BooleanField(default=False)
        REQUIRED_FIELDS = ["email","gender"]
        USERNAME_FIELD ="username"
        objects = User_manager()

        def __str__(self):
            return self.username

    不要忘记在您的settings.py中添加这一行代码:

    1
    AUTH_USER_MODEL = 'YourApp.User'

    这就是我所做的,它总是有效的。