Расширение модели 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/
Используя вышеуказанный подход:
- вам не нужно использоватьuser.get_profile().newattribute для доступа к дополнительной информации, связанной с пользователем
- вы можете просто напрямую получить доступ к дополнительным новым атрибутам через 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/