Расширение модели User с помощью пользовательских полей в Django - PullRequest
400 голосов
/ 04 сентября 2008

Какой лучший способ расширить модель User (в комплекте с приложением аутентификации Django) с помощью пользовательских полей? Я также хотел бы использовать электронную почту в качестве имени пользователя (в целях аутентификации).

Я уже видел несколько способов сделать это, но не могу решить, какой из них лучший.

Ответы [ 10 ]

229 голосов
/ 04 сентября 2008

Наименее болезненный и действительно рекомендуемый Django способ сделать это - использовать свойство OneToOneField(User).

Расширение существующей модели пользователя

& hellip;

Если вы хотите сохранить информацию, связанную с User, вы можете использовать отношение один к одному к модели, содержащей поля для дополнительной информации. Эту модель «один к одному» часто называют моделью профиля, поскольку она может хранить информацию, не связанную с аутентификацией, о пользователе сайта.

Тем не менее, расширение django.contrib.auth.models.User и вытеснение его также работает ...

Подстановка пользовательской модели пользователя

Некоторые проекты могут иметь требования к аутентификации, для которых встроенная модель Django User не всегда подходит. Например, на некоторых сайтах имеет смысл использовать адрес электронной почты в качестве идентификационного токена вместо имени пользователя.

[Ред .: После следуют два предупреждения и уведомление о том, что это довольно радикально .]

Я бы определенно держался подальше от изменения фактического класса User в вашем исходном дереве Django и / или копирования и изменения модуля auth.

219 голосов
/ 08 июня 2009

Примечание: этот ответ устарел. см. другие ответы, если вы используете Django 1.7 или более позднюю версию.

Вот как я это делаю.

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

Это создаст профайл пользователя при каждом сохранении пользователя, если он был создан. Затем вы можете использовать

  user.get_profile().whatever

Вот еще немного информации из документов

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

Обновление: Обратите внимание, что AUTH_PROFILE_MODULE устарело с версии 1.5: https://docs.djangoproject.com/en/1.5/ref/settings/#auth-profile-module

187 голосов
/ 29 сентября 2012

Ну, прошло некоторое время с 2008 года, и пришло время для нового ответа. Начиная с Django 1.5 вы сможете создавать пользовательский класс User. На самом деле, в то время, когда я пишу это, оно уже объединено с мастером, так что вы можете попробовать его.

Есть некоторая информация об этом в документах или, если вы хотите углубиться в это, в этом коммите .

Все, что вам нужно сделать, это добавить 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
43 голосов
/ 21 апреля 2013

Начиная с 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()
42 голосов
/ 04 сентября 2008

Существует официальная рекомендация по хранению дополнительной информации о пользователях . Книга Джанго также обсуждает эту проблему в разделе Профили .

22 голосов
/ 01 апреля 2009

Ниже представлен еще один подход к расширению пользователя. Я чувствую, что это более ясно, легко, читаемо, чем два подхода.

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

Используя вышеуказанный подход:

  1. вам не нужно использовать user.get_profile (). Newattribute для доступа к дополнительной информации относится к пользователю
  2. вы можете просто получить прямой доступ дополнительные новые атрибуты через user.newattribute
12 голосов
/ 25 июня 2016

Вы можете просто расширить профиль пользователя, создавая новую запись каждый раз, когда пользователь создается с помощью сигналов django post save

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'),
]
8 голосов
/ 13 апреля 2016

Расширение пользовательской модели Django (UserProfile) как Pro

Я нашел это очень полезным: ссылка

Выписка:

из django.contrib.auth.models import User

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
3 голосов
/ 12 марта 2013

Новое в Django 1.5, теперь вы можете создать свою собственную пользовательскую модель (что, пожалуй, лучше сделать в вышеупомянутом случае). См. «Настройка аутентификации в Django»

Вероятно, самая крутая новая функция в версии 1.5.

1 голос
/ 25 июля 2018

Это то, что я делаю, и, на мой взгляд, это самый простой способ сделать это. определите менеджер объектов для вашей новой настроенной модели, затем определите вашу модель.

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'

Это то, что я делаю, и это всегда работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...