在 Django 1.7 中扩展用户配置文件
Extending User profile in Django 1.7
我知道,这个问题已经在 SO 中被问过很多次了,但是我读到的大部分答案要么已经过时(建议现在弃用的 AUTH__PROFILE_MODULE
方法),要么缺少具体示例。
因此,我阅读了 Django 文档 [1,2],但我缺少有关如何正确使用它的真实示例。
事实上,当通过表单创建(或更新)新用户时,我的问题就来了。用户显然已创建,但扩展中的字段均未设置。我知道 Django 文档说明:
These profile models are not special in any way - they are just Django models that happen to have a one-to-one link with a User model. As such, they do not get auto created when a user is created, but a django.db.models.signals.post_save
could be used to create or update related models as appropriate.
但是,我不知道如何在实践中做到这一点(我应该添加一个 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
的新值。
欢迎任何提示!
我更喜欢扩展用户模型。例如:
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()
验证表单后检查您如何保存数据
我为这个话题苦苦挣扎了大约一年,直到我终于找到了一个令我满意的解决方案,而且我很清楚你所说的 "there is a lot out there, but it doesn't work" 是什么意思。我尝试过以不同的方式扩展 User 模型,我尝试过 UserProfile 方法,以及其他一些一次性解决方案。
我终于想出了如何简单地扩展 AbstractUser class 来创建我的自定义用户模型,这对我的许多项目来说都是一个很好的解决方案。
所以,让我澄清一下你上面的评论之一,你真的 不应该 在两个模型之间创建一个 link,普遍接受的 "best" 解决方案是根据您的需要使用一种从 AbstractUser 或 AbstractBaseUser 继承的模型。
让我感到棘手的事情是 "Extending the User Model" 没有让我到达我想要的位置,我需要 Substitute the User Model,我相信你已经 seen/read 多次了, 但可能没有吸收它(至少我知道我没有)。
一旦你掌握了它的窍门,真的没有那么多代码,也不太复杂。
# 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)
另一件事是,如果您想在模型文件中导入用户 class,则必须从设置中导入它,而不是使用 get_user_model()。如果你 运行 喜欢这个,它很容易修复,所以我只是想提醒你一下。
您可以查看我的 seed project 我用来启动项目以获得使用自定义用户模型的完整但简单的项目。用户内容在主应用程序中。
从那里开始,所有注册和登录的工作方式与普通 Django 用户的工作方式相同,因此我不会详细讨论该主题。我希望这对你有帮助,就像对我有帮助一样!
我尽量避免扩展用户模型,如 django 文档中所述。
我用这个:
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/
我看到了这些好处:
- 相同的模式适用于其他模型(例如组)
- 如果你有 N 个应用,每个应用都可以自己扩展模型。
无需提供参数即可创建 UserExtension
。所有字段都必须具有合理的默认值。
然后您可以创建一个信号处理程序,如果创建了用户,它会创建 UserExtension
个实例。
我已经查看了所有答案,但 none 确实能解决我的问题(尽管你们中的一些人给了我很好的提示让我找到正确的方向)。我将在这里总结我找到的解决问题的方法。
首先,我必须承认我没有把我的问题全部说出来。我想在 User
模型中插入额外的字段并使用其他应用程序,例如 Django 的默认身份验证方案。因此,通过继承和设置 AUTH_USER_MODEL
扩展默认 User
是一个问题,因为其他 Django 应用程序停止正常工作(我相信他们没有使用 user = models.OneToOneField(settings.AUTH_USER_MODEL)
但 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)
然后,我们需要在每次创建User
时触发添加一个对象UserProfile
。这是通过将此代码附加到 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
文件中即可。
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)
那么,现在是时候尝试将这个额外的字段与默认的 Django 身份验证应用程序混合使用了。为此,我们需要在forms.py
文件中通过继承添加一个额外的字段来填写SignupForm
和SettingsForm
:
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
和 views.py
文件中的 SettingsView
视图来完成的:
import account.views
from my_user_profile_app.forms import Settings, SignupForm
from my_user_profile_app.models import UserProfile
class SettingsView(account.views.SettingsView):
form_class = SettingsForm
def get_initial(self):
initial = super(SettingsView, self).get_initial()
initial["extra_field"] = self.request.user.extra_field
return initial
def update_settings(self, form):
super(SettingsView, self).update_settings(form)
profile = self.request.user.userprofile
profile.extra_field = form_cleaned_data['extra_field']
profile.save()
class SignupView(account.views.SignupView):
form_class = SignupForm
def after_signup(self, form):
profile = self.created_user.userprofile
profile.extra_field = form_cleaned_data['extra_field']
profile.save()
super(SignupView, self).after_signup(form)
一旦一切就绪,它应该可以很好地工作(希望如此)。
我知道,这个问题已经在 SO 中被问过很多次了,但是我读到的大部分答案要么已经过时(建议现在弃用的 AUTH__PROFILE_MODULE
方法),要么缺少具体示例。
因此,我阅读了 Django 文档 [1,2],但我缺少有关如何正确使用它的真实示例。
事实上,当通过表单创建(或更新)新用户时,我的问题就来了。用户显然已创建,但扩展中的字段均未设置。我知道 Django 文档说明:
These profile models are not special in any way - they are just Django models that happen to have a one-to-one link with a User model. As such, they do not get auto created when a user is created, but a
django.db.models.signals.post_save
could be used to create or update related models as appropriate.
但是,我不知道如何在实践中做到这一点(我应该添加一个 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
的新值。
欢迎任何提示!
我更喜欢扩展用户模型。例如:
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()
验证表单后检查您如何保存数据
我为这个话题苦苦挣扎了大约一年,直到我终于找到了一个令我满意的解决方案,而且我很清楚你所说的 "there is a lot out there, but it doesn't work" 是什么意思。我尝试过以不同的方式扩展 User 模型,我尝试过 UserProfile 方法,以及其他一些一次性解决方案。
我终于想出了如何简单地扩展 AbstractUser class 来创建我的自定义用户模型,这对我的许多项目来说都是一个很好的解决方案。
所以,让我澄清一下你上面的评论之一,你真的 不应该 在两个模型之间创建一个 link,普遍接受的 "best" 解决方案是根据您的需要使用一种从 AbstractUser 或 AbstractBaseUser 继承的模型。
让我感到棘手的事情是 "Extending the User Model" 没有让我到达我想要的位置,我需要 Substitute the User Model,我相信你已经 seen/read 多次了, 但可能没有吸收它(至少我知道我没有)。
一旦你掌握了它的窍门,真的没有那么多代码,也不太复杂。
# 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)
另一件事是,如果您想在模型文件中导入用户 class,则必须从设置中导入它,而不是使用 get_user_model()。如果你 运行 喜欢这个,它很容易修复,所以我只是想提醒你一下。
您可以查看我的 seed project 我用来启动项目以获得使用自定义用户模型的完整但简单的项目。用户内容在主应用程序中。
从那里开始,所有注册和登录的工作方式与普通 Django 用户的工作方式相同,因此我不会详细讨论该主题。我希望这对你有帮助,就像对我有帮助一样!
我尽量避免扩展用户模型,如 django 文档中所述。
我用这个:
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/
我看到了这些好处:
- 相同的模式适用于其他模型(例如组)
- 如果你有 N 个应用,每个应用都可以自己扩展模型。
无需提供参数即可创建 UserExtension
。所有字段都必须具有合理的默认值。
然后您可以创建一个信号处理程序,如果创建了用户,它会创建 UserExtension
个实例。
我已经查看了所有答案,但 none 确实能解决我的问题(尽管你们中的一些人给了我很好的提示让我找到正确的方向)。我将在这里总结我找到的解决问题的方法。
首先,我必须承认我没有把我的问题全部说出来。我想在 User
模型中插入额外的字段并使用其他应用程序,例如 Django 的默认身份验证方案。因此,通过继承和设置 AUTH_USER_MODEL
扩展默认 User
是一个问题,因为其他 Django 应用程序停止正常工作(我相信他们没有使用 user = models.OneToOneField(settings.AUTH_USER_MODEL)
但 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)
然后,我们需要在每次创建User
时触发添加一个对象UserProfile
。这是通过将此代码附加到 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
文件中即可。
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)
那么,现在是时候尝试将这个额外的字段与默认的 Django 身份验证应用程序混合使用了。为此,我们需要在forms.py
文件中通过继承添加一个额外的字段来填写SignupForm
和SettingsForm
:
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
和 views.py
文件中的 SettingsView
视图来完成的:
import account.views
from my_user_profile_app.forms import Settings, SignupForm
from my_user_profile_app.models import UserProfile
class SettingsView(account.views.SettingsView):
form_class = SettingsForm
def get_initial(self):
initial = super(SettingsView, self).get_initial()
initial["extra_field"] = self.request.user.extra_field
return initial
def update_settings(self, form):
super(SettingsView, self).update_settings(form)
profile = self.request.user.userprofile
profile.extra_field = form_cleaned_data['extra_field']
profile.save()
class SignupView(account.views.SignupView):
form_class = SignupForm
def after_signup(self, form):
profile = self.created_user.userprofile
profile.extra_field = form_cleaned_data['extra_field']
profile.save()
super(SignupView, self).after_signup(form)
一旦一切就绪,它应该可以很好地工作(希望如此)。