我知道,这个问题在SO中已经多次被问过,但我读到的大部分答案都已过时(建议现已弃用的AUTH__PROFILE_MODULE
方法),或缺乏具体的例子。
所以,我阅读了Django文档[1,2],但我没有关于如何正确使用它的真实示例。
事实上,我的问题出现在通过表单创建(或更新)新用户时。显然创建了用户,但扩展中的字段都未设置。我知道Django文档说明:
这些配置文件模型在任何方面都不是特别的 - 它们只是恰好与User模型具有一对一链接的Django模型。因此,在创建用户时不会自动创建它们,但可以使用
django.db.models.signals.post_save
来创建或更新相关模型。
但是,我不知道如何在实践中做到这一点(我应该添加一个receiver
,如果' 是',哪一个)
目前,我有以下内容(为了简洁起见,摘自文档):
models.py
from django.contrib.auth.models import User
class Employee(models.Model):
user = models.OneToOneField(User)
department = models.CharField(max_length=100)
admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from my_user_profile_app.models import Employee
# Define an inline admin descriptor for Employee model
class EmployeeInline(admin.StackedInline):
model = Employee
can_delete = False
verbose_name_plural = 'employee'
# Define a new User admin
class UserAdmin(UserAdmin):
inlines = (EmployeeInline, )
# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
forms.py
class SignupForm(account.forms.SignupForm):
department = forms.CharField(label="Department", max_length=100)
class SettingsForm(account.forms.SignupForm):
department = forms.CharField(label="Department", max_length=100)
然后,在我的代码中,我像这样使用它:
u = User.objects.get(username='fsmith')
freds_department = u.employee.department
但是,注册和设置表单无法按预期运行,并且未记录departement
的新值。
欢迎任何提示!
答案 0 :(得分:16)
我已经查看了所有答案,但没有一个确实能解决我的问题(尽管你们中的一些人给了我很好的提示,以便找到正确的方向)。我将在这里总结一下我找到的解决问题的方法。
首先,我必须承认我没有告诉我关于我的问题的一切。我想在User
模型中插入额外的字段,并使用其他应用程序,例如Django的默认身份验证方案。因此,通过继承扩展默认User
并设置AUTH_USER_MODEL
是一个问题,因为其他Django应用程序停止正常工作(我相信他们没有使用user = models.OneToOneField(settings.AUTH_USER_MODEL)
但{{{ 1}})。
因为,我正在使用其他正在使用的应用程序进行正确重写太长了,我决定通过一对一字段添加这个额外的字段。但是,文档遗漏了几点,我想填写以下内容。
因此,这是一个完整的示例,使用相同模型向user = models.OneToOneField(User)
模型添加额外字段和其他应用程序。
首先,编写模型的描述,收集要添加到User
文件的额外字段:
models.py
然后,我们需要在每次创建from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User)
extra_field = models.CharField(max_length=100)
时触发添加对象UserProfile
。这是通过将此代码附加到User
文件中的正确信号来完成的:
receiver.py
现在,如果您希望能够通过管理界面对其进行修改,只需将其与from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
from my_user_profile_app.models import UserProfile
@receiver(post_save, sender=User)
def handle_user_save(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
文件中的常用UserAdmin
表单进行叠加即可。
admin.py
然后,现在是时候尝试将此额外字段与默认的Django身份验证应用程序混合使用。为此,我们需要添加一个额外字段,以便在from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from my_user_profile_app.models import UserProfile
# Define an inline admin descriptor for UserProfile model
class UserProfileInline(admin.StackedInline):
model = UserProfile
can_delete = False
# Define a new User admin
class UserAdmin(UserAdmin):
inlines = (UserProfileInline, )
# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
文件中填充SignupForm
和SettingsForm
继承:
forms.py
而且,我们还需要添加一些代码来显示并正确获取已添加到原始import account.forms
from django import forms
class SignupForm(account.forms.SignupForm):
extra_field = forms.CharField(label="Extra Field", max_length=100)
class SettingsForm(account.forms.SignupForm):
extra_field = forms.CharField(label="Extra Field", max_length=100)
模型的数据。这是通过继承到User
文件中的SignupView
和SettingsView
视图来完成的:
views.py
一旦一切就绪,它应该很好地工作(希望如此)。
答案 1 :(得分:7)
我在这个主题上挣扎了大约一年,直到我终于找到了一个我很满意的解决方案,而且我确切地知道你的意思是什么?有很多,但它没有&#39工作"。我曾尝试以不同的方式扩展User模型,我尝试过UserProfile方法,以及其他一些1-off解决方案。
我终于想出了如何简单地扩展AbstractUser类来创建我的自定义用户模型,这对我的许多项目都是一个很好的解决方案。
所以,让我澄清你上面的一条评论,你真的不应该在2个模型之间创建一个链接,这是普遍接受的" best"解决方案是根据您的需要使用一个继承自AbstractUser或AbstractBaseUser的模型。
让我感到兴奋的一件事是"扩展用户模型"没有把我带到我想要的地方,我需要Substitute the User Model,我确定你已经多次看过/读过,但可能没有吸收它(至少我知道我没有'吨)。
一旦掌握了它,那真的没有那么多代码,它也不是太复杂。
# models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
'''
Here is your User class which is fully customizable and
based off of the AbstractUser from auth.models
'''
my_custom_field = models.CharField(max_length=20)
def my_custom_model_method(self):
# do stuff
return True
此后有几件事需要注意,其中一些内容出现在django 1.7中。
首先,如果您希望管理页面看起来像以前一样,则必须使用UserAdmin
# admin.py
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin
# Register your models here.
admin.site.register(get_user_model(), UserAdmin)
另一件事是,如果您想要在模型文件中导入User类,则必须从设置中导入它,而不是使用get_user_model()。如果你碰到这个,它很容易修复,所以我只想给你一个抬头。
您可以查看我用于启动项目的seed project以获得使用自定义用户模型的完整但简单的项目。用户的东西在主应用程序中。
从那里所有注册和登录的工作方式与普通的Django用户相同,所以我不会详细介绍该主题。我希望这对你有所帮助,就像它帮助了我一样!
答案 2 :(得分:6)
我尽量避免扩展用户模型,如django docs中所述。
我用这个:
class UserExtension(models.Model):
user=models.OneToOneField(User, primary_key=True)
... your extra model fields come here
OneToOneField的文档:https://docs.djangoproject.com/en/1.7/topics/db/examples/one_to_one/
我看到了这些好处:
应该可以在不提供参数的情况下创建UserExtension
。所有字段都必须具有合理的默认值。
然后,您可以创建一个信号处理程序,在创建用户时创建UserExtension
个实例。
答案 3 :(得分:1)
我更喜欢扩展用户模型。例如:
class UserProfile(User):
def __unicode__(self):
return self.last_name + self.first_name
department = models.CharField(max_length=100)
class SignupForm(forms.Form):
username = forms.CharField(max_length=30)
first_name = forms.CharField(max_length=30)
last_name = forms.CharField(max_length=30)
department = forms.CharField(label="Department", max_length=100)
保存数据
form = UserRegistrationForm(request.POST)
if form.is_valid():
client = UserProfile()
client.username = username
client.set_password(password)
client.first_name = first_name
client.department = department
client.save()
检查验证表单后如何保存数据