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

StackOverflow https://stackoverflow.com/questions/44109

Вопрос

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

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

Это было полезно?

Решение

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

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

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

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

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

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

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

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

Другие советы

Примечание:этот ответ устарел.смотрите другие ответы, если вы используете 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'

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

  user.get_profile().whatever

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

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

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

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

Кое-какая информация об этом есть в Документы или, если вы хотите копнуть глубже, в этот коммит.

Все, что вам нужно сделать, это добавить AUTH_USER_MODEL к настройкам с указанием пути к пользовательскому классу пользователя, который расширяет либо AbstractBaseUser (более настраиваемая версия) или AbstractUser (более или менее старый пользовательский класс вы можете расширить).

Для людей, которым лень кликать, вот пример кода (взят из Документы):

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, вы можете легко расширить пользовательскую модель и сохранить единую таблицу в базе данных.

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.

Примечание для людей, разрабатывающих сторонние библиотеки:если вам нужно получить доступ к классу user, помните, что люди могут изменить его.Используйте официальный помощник, чтобы получить нужный класс

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/

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

  1. вам не нужно использовать user.get_profile().новый атрибут для доступа к дополнительной информации , относящейся к пользователю
  2. вы можете просто напрямую получить доступ к дополнительным новым атрибутам через user.новый атрибут

Вы можете просто расширить профиль пользователя, создавая новую запись каждый раз при создании пользователя с помощью сигналов 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)

Это автоматически создаст экземпляр employee при создании нового пользователя.

Если вы хотите расширить модель пользователя и хотите добавить дополнительную информацию при создании пользователя, вы можете использовать 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'),
]

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

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

Выдержка из:

из 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

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

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

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

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'

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top