Как лучше всего расширить модель User (в комплекте с приложением аутентификации Django) с помощью настраиваемых полей? Я также, возможно, хотел бы использовать электронную почту в качестве имени пользователя (для целей аутентификации).
Я уже видел несколькоспособы, чтобы сделать это, но не могу решить, какой из них лучше.
@buffer - Первый вопрос, на который вы указали (stackoverflow.com/a/22856042/781695), теперь удален. Остальные еще в силе.
Чтобы использовать электронную почту вместо имени пользователя для аутентификации, полезно использовать Эта статья.
Мне очень приятно видеть, что этот вопрос был задан в 2008 году до того, как был выпущен Django @Farinha





Есть официальная рекомендация по хранение дополнительной информации о пользователях. Книга Django также обсуждает эту проблему в разделе Профили.
Наименее болезненный и действительно рекомендуемый Django способ сделать это - использовать свойство OneToOneField(User).
Extending the existing User model
…
If you wish to store information related to
User, you can use a one-to-one relationship to a model containing the fields for additional information. This one-to-one model is often called a profile model, as it might store non-auth related information about a site user.
Тем не менее, расширение django.contrib.auth.models.User и его замена тоже работает ...
Substituting a custom User model
Some kinds of projects may have authentication requirements for which Django’s built-in
Usermodel is not always appropriate. For instance, on some sites it makes more sense to use an email address as your identification token instead of a username.[Ed: Two warnings and a notification follow, mentioning that this is pretty drastic.]
Я бы определенно воздержался от изменения фактического класса User в исходном дереве Django и / или копирования и изменения модуля auth.
С помощью этого решения вы должны использовать ForeignKey для пользователя или профиля?
К вашему сведению, новый (1.0+) рекомендуемый метод - OneToOneField (User) docs.djangoproject.com/en/dev/topics/auth/…
Шон Райдер из PBS привел несколько действительно веских причин, по которым вам следует нет расширять django.contrib.auth.models.User. Вместо этого используйте OneToOneField (User).
user = models.ForeignKey(User, unique=True) это то же самое, что и user = models.OneToOneField(User)? Я думаю, конечный эффект такой же? Но, возможно, реализация в бэкэнде другая.
@pydanny: на самом деле он привел аргумент в пользу не преобладающий пользовательской модели
Может ли кто-нибудь сослаться на аргументы / доводы Шона Райдера?
@JeremyBlanchard: Я немного покопался, и лучшее, что я смог найти, - это один пункт из этого: birdhouse.org/blog/2010/09/13/djangocon-2010 "вам придется исправлять каждое повторно используемое приложение, которое вы вставляете"
@JeremyBlanchard: Полное видео здесь: blip.tv/djangocon/… Аргумент исправления - единственный, который он выдвигает; он не упомянул никаких других проблем и, похоже, предположил, что это не нарушает условия сделки (у них все еще есть часть этого кода в их системе).
@DaveForgac ссылка кажется неработающей, подробнее здесь docs.djangoproject.com/en/1.4/topics/auth/…
@SamStoelinga от: (docs.djangoproject.com/en/dev/ref/models/fields/#oneto onefield) Отношения один к одному. Концептуально это похоже на ForeignKey с unique = True, но «обратная» сторона отношения будет напрямую возвращать один объект.
Разве я не могу просто создать новый класс, унаследованный от django.contrib.auth.models.User, если мне нужно только несколько дополнительных полей для моего пользователя?
Не знаю, как вы, но меня OneToOneField(User) очень раздражает для больших проектов! я предпочитаю использовать O.O.P. (расширение) в моих проектах!
Ниже приведен еще один подход к расширению User. Я считаю, что это более ясно, легко и читабельно, чем два вышеуказанных подхода.
http://scottbarnham.com/blog/2008/08/21/exnding-the-django-user-model-with-inheritance/
Используя вышеуказанный подход:
Мне гораздо больше нравится подход Скотта, основанный на наследовании объекта User, а не непосредственно на модели. Кто-нибудь может сказать, не разумен ли такой подход?
@BozoJoe - Я только что столкнулся с этой проблемой при импорте данных дампа, которая, похоже, является следствием использования этого метода: stackoverflow.com/questions/8840068/…
Примечание: этот ответ устарел. см. другие ответы, если вы используете 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
Спасибо за ясный пример, обратите внимание, что def create_user .... не является частью класса UserProfile и должен быть выровнен по левому краю.
С этим решением следует ли другим моделям ForeignKey to User или UserProfile?
Другие модели должны использовать user = models.ForeignKey( User ) и получать объект профиля через user.get_profile(). Не забывайте о from django.contrib.admin.models import User.
Используя этот метод, мне нужно разделить, когда я получаю обычную информацию (имя, пароль) и пользовательскую, или есть способ сделать это сразу? То же самое для создания нового пользователя?
Может кто-нибудь объяснить аргументы, взятые create_user_profile ??
Этот ответ и комментарии устарели, например. AUTH_PROFILE_MODULE устарел, User
Настройка AUTH_PROFILE_MODULE и метод get_profile() на модели User будут удалены в Django 1.7.
Вы не должны ссылаться на / dev / в документации django, потому что ветвь / dev / документации всегда меняется. Ссылка, размещенная для #storing-additional-information-about-users, больше не относится к теме об этом.
Что ж, прошло какое-то время с 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
Функция create_user, похоже, не хранит имя пользователя, как так ?!
Потому что в этом примере email - это имя пользователя.
Вам нужно добавить unique=True в поле электронной почты, чтобы USERNAME_FIELD принял его
Привет, я пытался создать специального пользователя, как вы сказали, но не смог войти в систему, используя адрес электронной почты настраиваемого пользователя. не могли бы вы сказать почему?
Я не могу вам помочь без подробностей. Было бы лучше, если бы вы создали новый вопрос.
получаем следующую ошибку, когда мы запускаем syncd, что приводит к созданию суперпользователя: TypeError: create_superuser () получил неожиданный аргумент ключевого слова 'email'
Настраиваемые поля являются обычными полями модели, вы можете получить к ним доступ из шаблонов, например, используя. user.custom_field.
Новое в Django 1.5, теперь вы можете создать свою собственную пользовательскую модель (что, кажется, неплохо сделать в приведенном выше случае). Обратитесь к 'Настройка аутентификации в Django'
Вероятно, самая крутая новая функция в версии 1.5.
Да, в самом деле. Но помните, что этого следует избегать без необходимости. Внедрение собственного по причине, указанной в этом вопросе, вполне допустимо, хотя в случае, если вас устраивают задокументированные последствия. Для простого добавления полей связь с обычной моделью пользователя Рекомендовано.
Начиная с 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()
Если вы планируете использовать django_social_auth, я рекомендую использовать отношения OneToOne. НЕ используйте этот метод, иначе он испортит вашу миграцию.
@Nimo: Не могли бы вы уточнить или процитировать ссылку
@buffer, это было давно, но я думаю, что попытался объединить плагин django_social_auth и определить AUTH_USER_MODEL для пользователя социальной аутентификации. Затем, когда я запустил manage.py migrate, мое приложение испортилось. Когда вместо этого я использовал пользовательскую модель социальной аутентификации в качестве отношений OneToOne, описанных здесь: stackoverflow.com/q/10638293/977116
Вероятно, имеет отношение к Changing this setting after you have tables created is not supported by makemigrations and will result in you having to manually write a set of migrations to fix your schema Источник: docs.djangoproject.com/en/dev/topics/auth/customizing/…
Расширение модели пользователя Django (UserProfile) как профессионал
Я нашел это очень полезным: связь
Выписка:
from 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
Выполнено. Я не понимаю, почему -1. В этом случае лучше отредактировать, чем проголосовать против.
Вы можете просто расширить профиль пользователя, создавая новую запись каждый раз, когда пользователь создается с помощью сигналов сохранения сообщений Django.
from django.db.models.signals import *
from __future__ import unicode_literals
class UserProfile(models.Model):
user_name = models.OneToOneField(User, related_name='profile')
city = models.CharField(max_length=100, null=True)
def __unicode__(self): # __str__
return unicode(self.user_name)
def create_user_profile(sender, instance, created, **kwargs):
if created:
userProfile.objects.create(user_name=instance)
post_save.connect(create_user_profile, sender=User)
Это автоматически создаст экземпляр сотрудника при создании нового пользователя.
Если вы хотите расширить модель пользователя и хотите добавить дополнительную информацию при создании пользователя, вы можете использовать django-betterforms (http://django-betterforms.readthedocs.io/en/latest/multiform.html). Это создаст форму добавления пользователя со всеми полями, определенными в модели UserProfile.
from django.db.models.signals import *
from __future__ import unicode_literals
class UserProfile(models.Model):
user_name = models.OneToOneField(User)
city = models.CharField(max_length=100)
def __unicode__(self): # __str__
return unicode(self.user_name)
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 = ('user_name',)
class addUserMultiForm(MultiModelForm):
form_classes = {
'user':UserCreationForm,
'profile':ProfileForm,
}
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 = "add-user.html"
success_url = '/your-url-after-user-created'
def form_valid(self, form):
user = form['user'].save()
profile = form['profile'].save(commit=False)
profile.user_name = User.objects.get(username= user.username)
profile.save()
return redirect(self.success_url)
<!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>
from django.conf.urls import url, include
from appName.views import *
urlpatterns = [
url(r'^add-user/$', AddUser.as_view(), name='add-user'),
]
Привет и спасибо за этот ответ. Я все еще не понимаю, как связать все это вместе в urls.py .. какие-нибудь подсказки?
@sal Добавлен пример URL, который вы можете проверить сейчас
Спасибо!!. Это мне очень помогает. Хороший пример
@AtulYadav .. какую версию Django вы использовали?
Это то, что я делаю, и, на мой взгляд, это самый простой способ сделать это. определите диспетчер объектов для вашей новой настроенной модели, а затем определите свою модель.
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'
Это то, что я делаю, и это всегда срабатывает.
В настоящее время, начиная с Django 2.2, при запуске нового проекта рекомендуется создать пользовательскую модель, унаследованную от AbstractUser, а затем указать AUTH_USER_MODEL на модель.
Простой и эффективный подход - это models.py
from django.contrib.auth.models import User
class CustomUser(User):
profile_pic = models.ImageField(upload_to='...')
other_field = models.CharField()
Я бы никогда не использовал это решение. НО, как чистое и действительно простое решение, это лучший и самый правильный способ для чистого django.
Слишком поздно, но мой ответ предназначен для тех, кто ищет решение с последней версией 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()
Я становлюсь AttributeError: объект «Пользователь» не имеет ошибки атрибута «профиль» при срабатывании сигнала save_user_profile (instance.profile.save ()). Как ты это решил?
@fbzyx вы импортировали модель profile?
Попробуй это:
Создайте модель с именем Profile и укажите пользователю OneToOneField, а также укажите вариант related_name.
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)
Большинство ответов устарели / устарели. См. Stackoverflow.com/a/22856042/781695 и stackoverflow.com/q/14104677/781695 и stackoverflow.com/q/16880461/781695