使用自定义字段扩展User模型(与Django的身份验证应用程序捆绑在一起)的最佳方法是什么?我也可能希望使用该电子邮件作为用户名(用于身份验证)。
答案 0 :(得分:229)
最不痛苦的,实际上Django推荐的方法是通过OneToOneField(User)
属性。
Extending the existing User model
...
如果您希望存储与
User
相关的信息,可以使用one-to-one relationship到包含这些字段的模型以获取更多信息。这种一对一模型通常称为配置文件模型,因为它可能存储有关站点用户的非身份验证相关信息。
那就是说,延长django.contrib.auth.models.User
并取代它也有效......
Substituting a custom User model
某些类型的项目可能具有Django的内置
User
模型并不总是适合的身份验证要求。例如,在某些网站上,使用电子邮件地址作为您的身份识别令牌而不是用户名更为合理。[编辑:两个警告和一个通知,提到这是非常激烈。]
我肯定会远离更改Django源代码树中的实际User类和/或复制和更改auth模块。
答案 1 :(得分:219)
注意:此答案已弃用。如果您使用的是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
更新:请注意,自v1.5以来AUTH_PROFILE_MODULE
已被弃用:https://docs.djangoproject.com/en/1.5/ref/settings/#auth-profile-module
答案 2 :(得分:187)
嗯,自2008年以来已经过了一段时间,现在是时候回答一些问题了。从Django 1.5开始,您将能够创建自定义User类。实际上,在我写这篇文章的时候,它已经合并到了master中,所以你可以尝试一下。
docs中有关于它的一些信息,或者如果你想深入研究它,请this commit。
您所要做的就是将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
答案 3 :(得分:43)
从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()
答案 4 :(得分:42)
关于storing additional information about users的官方建议。 Django Book还在Profiles部分讨论了这个问题。
答案 5 :(得分:22)
以下是另一种扩展用户的方法。 我觉得它比以上两种方法更清晰,更容易,更易读。
http://scottbarnham.com/blog/2008/08/21/extending-the-django-user-model-with-inheritance/
使用上述方法:
答案 6 :(得分:12)
您可以通过使用django post save signals创建用户时,通过创建新条目来简单地扩展用户配置文件
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模型中定义的所有字段。
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)
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,
}
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)
<!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='addDistributor'),
]
答案 7 :(得分:8)
像Pro一样扩展Django用户模型(UserProfile)
我发现这非常有用:link
摘录:
来自django.contrib.auth.models导入用户
if exists (
select 1 from People WHERE FirstName = 'Jack'
union all
SELECT 1 Surname FROM People
WHERE Surname = 'Smith'
)
BEGIN
print 'first Condition '
END
ELSE
BEGIN
print 'Second Condition '
END
答案 8 :(得分:3)
Django 1.5中的新功能,现在您可以创建自己的自定义用户模型(在上述情况下这似乎是件好事)。请参阅'Customizing authentication in Django'
可能是1.5版本中最酷的新功能。
答案 9 :(得分:3)
在 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 和 migrate,就会成功完成。
答案 10 :(得分:1)
This is what i do and it's in my opinion simplest way to do this. define an object manager for your new customized model then define your model.
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
Dont forget to add this line of code in your settings.py
:
AUTH_USER_MODEL = 'YourApp.User'
This is what i do and it always works.
答案 11 :(得分:1)
为时已晚,但我的答案是那些使用最新版本的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()
答案 12 :(得分:0)
当前从Django 2.2开始,推荐的启动新项目的方法是创建一个自AbstractUser继承的自定义用户模型,然后将AUTH_USER_MODEL指向该模型。
答案 13 :(得分:0)
简单有效的方法是 models.py
from django.contrib.auth.models import User
class CustomUser(User):
profile_pic = models.ImageField(upload_to='...')
other_field = models.CharField()
答案 14 :(得分:0)
试试这个:
创建一个名为 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)