在Django 1.7中扩展用户配置文件

per*_*ror 9 django django-models

我知道,这个问题在SO中已经被多次提出过了,但我读到的大部分答案都已过时(建议现在已弃用的AUTH__PROFILE_MODULE方法),或缺乏具体的例子.

所以,我读了Django文档[ 1,2 ],但我缺乏关于如何正确使用它一个真实的例子.

事实上,我的问题出现在通过表单创建(或更新)新用户时.显然创建了用户,但扩展中的字段都未设置.我知道Django文档说明:

这些配置文件模型在任何方面都不是特别的 - 它们只是恰好与User模型具有一对一链接的Django模型.因此,在创建用户时不会自动创建它们,但django.db.models.signals.post_save可以使用a 来根据需要创建或更新相关模型.

但是,我不知道如何在实践中这样做(我应该添加aa receiver,如果' ',哪一个).

现在,我有以下内容(为了简洁起见,从文档中获取):

文件 models.py

from django.contrib.auth.models import User

class Employee(models.Model):
  user = models.OneToOneField(User)
  department = models.CharField(max_length=100)
Run Code Online (Sandbox Code Playgroud)

文件 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)
Run Code Online (Sandbox Code Playgroud)

文件 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)
Run Code Online (Sandbox Code Playgroud)

然后,在我的代码中,我使用它像这样:

u = User.objects.get(username='fsmith')
freds_department = u.employee.department
Run Code Online (Sandbox Code Playgroud)

但是,"注册和设置"表单无法按预期运行,并且departement未记录新值.

任何暗示都是受欢迎的!

per*_*ror 16

我已经查看了所有的答案,但没有一个确实能解决我的问题(尽管你们中的一些人给了我很好的提示,以便找到正确的方向).我将在这里总结一下我找到的解决问题的方法.

首先,我不得不承认我没有说出我的问题.我想在User模型中插入额外的字段并使用其他应用程序,例如Django的默认身份验证方案.因此,User通过继承和设置扩展默认值AUTH_USER_MODEL是一个问题,因为其他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)
Run Code Online (Sandbox Code Playgroud)

然后,我们需要在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)
Run Code Online (Sandbox Code Playgroud)

现在,如果您希望能够通过管理界面对其进行修改,只需将其与文件中的常用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)
Run Code Online (Sandbox Code Playgroud)

然后,现在是时候尝试将此额外字段与默认的Django身份验证应用程序混合使用.为此,我们需要添加一个额外的字段来填充文件中SignupFormSettingsForm直接继承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)
Run Code Online (Sandbox Code Playgroud)

而且,我们还需要添加一些代码来显示并正确获取已添加到原始User模型的数据.这是通过继承到文件中SignupViewSettingsView视图来完成的views.py:

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)
Run Code Online (Sandbox Code Playgroud)

一旦一切就绪,它应该很好地工作(希望如此).


aww*_*ter 7

我在这个主题上挣扎了大约一年,直到我终于找到了一个我很满意的解决方案,而且我确切地知道你的意思是"那里有很多,但它不起作用".我曾尝试以不同的方式扩展User模型,我尝试过UserProfile方法,以及其他一些一次性解决方案.

我终于想出了如何简单地扩展AbstractUser类来创建我的自定义用户模型,这对我的许多项目来说都是一个很好的解决方案.

所以,让我澄清你上面的一条评论,你真的应该在2个模型之间创建链接,普遍接受的"最佳"解决方案是根据您的需要从AbstractUser或AbstractBaseUser继承一个模型.

让我觉得一个棘手的问题是"扩展用户模型"没有让我到达我想要的地方,我需要替换用户模型,我确信你已经多次看到/读过,但可能没有吸收它(至少我知道我没有).

一旦你掌握了它,那真的没有那么多代码,它也不是太复杂.

# 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
Run Code Online (Sandbox Code Playgroud)

在此之后有几件事需要注意,其中一些在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)
Run Code Online (Sandbox Code Playgroud)

另一件事是,如果您想要在模型文件中导入User类,则必须从设置中导入它,而不是使用get_user_model().如果你碰到这个,很容易修复,所以我只想给你一个抬头.

您可以查看我用于启动项目的种子项目,以获得使用自定义用户模型的完整但简单的项目.用户的东西在主应用程序中.

从那里所有注册和登录的工作方式与普通的Django用户相同,所以我不会详细介绍该主题.我希望这对你有所帮助,就像它帮助了我一样!


gue*_*tli 6

我试图避免扩展用户模型,如django文档中所述.

我用这个:

class UserExtension(models.Model):
    user=models.OneToOneField(User, primary_key=True)
    ... your extra model fields come here
Run Code Online (Sandbox Code Playgroud)

OneToOneField的文档:https://docs.djangoproject.com/en/1.7/topics/db/examples/one_to_one/

我看到了这些好处:

  • 相同的模式适用于其他模型(例如,组)
  • 如果你有N个应用程序,每个应用程序都可以自己扩展模型.

UserExtension应该可以在不提供参数的情况下创建.所有字段必须具有合理的默认值.

然后,您可以创建一个信号处理程序,在创建UserExtension用户时创建实例.