首页 文章

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

提问于
浏览
382

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

我已经看过few ways这样做,但不能决定哪一个是最好的 .

10 回答

  • 218

    Django 1.5中的新功能,现在您可以创建自己的自定义用户模型(在上述情况下这似乎是件好事) . 请参阅'Customizing authentication in Django'

    可能是1.5版本上最酷的新功能 .

  • 181

    最痛苦的,实际上Django推荐的方法是通过 OneToOneField(User) 属性 .

    扩展现有用户模型...如果要存储与用户相关的信息,可以使用与包含这些字段的模型的一对一关系以获取其他信息 . 这种一对一模型通常称为配置文件模型,因为它可能存储有关站点用户的非身份验证相关信息 .

    也就是说,扩展 django.contrib.auth.models.User 并取代它也有效......

    替换自定义用户模型某些类型的项目可能具有Django的内置用户模型并不总是适合的身份验证要求 . 例如,在某些网站上,使用电子邮件地址作为识别令牌而不是用户名更有意义 . [编辑:两个警告和通知随后,提到这是非常激烈的 . ]

    我肯定会远离更改Django源代码树中的实际User类和/或复制和更改auth模块 .

  • 2

    Extending Django User Model (UserProfile) like a Pro

    我发现这非常有用:link

    An extract:

    来自django.contrib.auth.models导入用户

    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
    
  • 39

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

    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 中添加这行代码:

    AUTH_USER_MODEL = 'YourApp.User'
    

    这就是我所做的,它始终有效 .

  • 21

    从Django 1.5开始,您可以轻松扩展用户模型并在数据库上保留一个表 .

    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"))
    

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

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

    如果您想添加很多用户的偏好,OneToOneField选项可能是更好的选择 .

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

    from django.contrib.auth import get_user_model
    
    User = get_user_model()
    
  • 214

    好吧,自2008年以来已经过了一段时间,现在是时候回答一些问题了 . 从Django 1.5开始,您将能够创建自定义User类 . 实际上,在我写这篇文章的时候,它已经合并到了master中,所以你可以尝试一下 .

    docs中有一些关于它的信息,或者如果你想深入研究它,请在this commit中 .

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

    对于懒惰点击的人,这里的代码示例(取自docs):

    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
    
  • 10

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

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

    使用上述方法:

    • 您不需要使用user.get_profile() . newattribute来访问与用户相关的其他信息

    • 您可以通过user.newattribute直接访问其他新属性

  • 41

    有关storing additional information about users的官方建议 . Django Book还在Profiles部分讨论了这个问题 .

  • 7

    Note: this answer is deprecated. see other answers if you are using Django 1.7 or later.

    我就是这样做的 .

    #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'
    

    每次创建用户时,这将创建一个userprofile . 然后你可以使用

    user.get_profile().whatever
    

    以下是来自文档的更多信息

    http://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users

    Update: 请注意,自v1.5起 AUTH_PROFILE_MODULE 已弃用:https://docs.djangoproject.com/en/1.5/ref/settings/#auth-profile-module

  • 0

    您可以通过使用django post保存信号在每次创建用户时创建新条目来简单地扩展用户配置文件

    models.py

    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) . 这将创建一个用户添加表单,其中包含在userProfile模型中定义的所有字段 .

    models.py

    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)
    

    forms.py

    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,
        }
    

    views.py

    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)
    

    addUser.html

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>Title</title>
        </head>
        <body>
            <form action="." method="post">
                {% csrf_token %}
                {{ form }}     
                <button type="submit">Add</button>
            </form>
         </body>
    </html>
    

    urls.py

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

相关问题