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

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

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

17 ответов

Решение

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

Расширение существующей модели 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/

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

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

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

Все, что вам нужно сделать, это добавить 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 может оказаться лучшим выбором.

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

from django.contrib.auth import get_user_model

User = get_user_model()

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

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

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

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

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

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

Расширение пользовательской модели 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

в Django версии 3.0+ это очень просто.

в Models.py

      from django.db import models
from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
extra_field=models.CharField(max_length=40)

в settings.py

сначала зарегистрируйте свое новое приложение, а затем после

AUTH_PASSWORD_VALIDATORS добавить

      AUTH_USER_MODEL ='users.CustomUser'

а затем просто зарегистрируйте модель в админке, а затем просто запустите makemigrations и выполните миграцию, и она будет успешно завершена.

Слишком поздно, но мой ответ для тех, кто ищет решение с последней версией Django.

models.py:

from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver


class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    extra_Field_1 = models.CharField(max_length=25, blank=True)
    extra_Field_2 = models.CharField(max_length=25, blank=True)


@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)

@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
    instance.profile.save()

вы можете использовать его в таких шаблонах:

<h2>{{ user.get_full_name }}</h2>
<ul>
  <li>Username: {{ user.username }}</li>
  <li>Location: {{ user.profile.extra_Field_1 }}</li>
  <li>Birth Date: {{ user.profile.extra_Field_2 }}</li>
</ul>

И в views.py как это:

def update_profile(request, user_id):
    user = User.objects.get(pk=user_id)
    user.profile.extra_Field_1 = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit...'
    user.save()

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

Django позволяет расширить пользовательскую модель по умолчанию с помощью AbstractUser .

Примечание. Сначала создайте дополнительную модель поля, которую вы хотите добавить в пользовательскую модель, затем запустите команду python manage.py makemigrations и python manage.py migrate .

сначала запустите ---> python manage.py makemigrations, затем

второй запуск python manage.py migrate

Шаг:- создайте модель с дополнительными полями, которые вы хотите добавить в пользовательскую модель Django по умолчанию (в моем случае я создал CustomUser

модель.py

      from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.


class CustomUser(AbstractUser):
    mobile_no = models.IntegerField(blank=True,null=True)
    date_of_birth = models.DateField(blank=True,null=True)

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

      #settings.py

AUTH_USER_MODEL = 'myapp.CustomUser'

наконец-то зарегистрировала модель CustomUser в admin.py #admin.py

      @admin.register(CustomUser)
class CustomUserAdmin(admin.ModelAdmin):
    list_display = ("username","first_name","last_name","email","date_of_birth", "mobile_no")

затем запустите команду python manage.py makemigrations

затем python manage.py migrate

затем python manage.py создает суперпользователя

теперь вы можете увидеть модель пользователя по умолчанию, расширенную с помощью (mobile_no,date_of_birth)

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

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

Я рекомендую , которая более настраиваема, чем .

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

  • можно добавить дополнительные поля.
  • можно удалить поля по умолчанию.
  • можно изменить значение по умолчанию и аутентификацию на и аутентификацию.
  • должна быть первая миграция в базу данных, иначе возникнет ошибка.

*Вы можете увидеть мой ответ , объясняющий, как настроить и аутентификацию с помощью AbstractUser или AbstractBaseUser и PermissionsMixin , а также мой ответ и мой ответ , объясняющий разницу междуAbstractUserиAbstractBaseUser.

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

  • можно добавить дополнительные поля.
  • невозможно удалить поля по умолчанию.
  • невозможно изменитьusernameи аутентификация дляemailиpasswordаутентификация.
  • не обязательно это должна быть первая миграция в базу данных.

*Вы можете увидеть мой ответ , объясняющий, как расширить модель пользователя , чтобы добавить дополнительные поля с помощью OneToOneField() .

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

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'

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

Простой и эффективный подход - models.py

from django.contrib.auth.models import User
class CustomUser(User):
     profile_pic = models.ImageField(upload_to='...')
     other_field = models.CharField()

Попробуй это:

Создайте модель под названием Profile и сослаться на пользователя с помощью OneToOneField и предоставить возможность.

models.py

      from django.db import models
from django.contrib.auth.models import *
from django.dispatch import receiver
from django.db.models.signals import post_save

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='user_profile')

    def __str__(self):
        return self.user.username

@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
    try:
        if created:
            Profile.objects.create(user=instance).save()
    except Exception as err:
        print('Error creating user profile!')

Теперь для прямого доступа к профилю с помощью User объект вы можете использовать related_name.

views.py

      from django.http import HttpResponse

def home(request):
    profile = f'profile of {request.user.user_profile}'
    return HttpResponse(profile)

В настоящее время, начиная с Django 2.2, при запуске нового проекта рекомендуется создать пользовательскую модель, унаследованную от AbstractUser, а затем указать AUTH_USER_MODEL на модель.

Источник: https://docs.djangoproject.com/en/2.2/topics/auth/customizing/

Другие вопросы по тегам