【问题标题】:Django - User and User Profile form creating two profiles instead of oneDjango - 用户和用户配置文件表单创建两个配置文件而不是一个
【发布时间】:2017-04-17 15:44:24
【问题描述】:

当我提交包含用户信息(用户名、电子邮件、密码)和用户个人资料(名字和姓氏)的注册表单并在我的views.py 中调用form.save()profileform.save() 等保存时那么一切似乎都很好,我没有收到任何错误。

但是,当我进入 Django Admin 时,我看到用户配置文件和配置文件已分别保存。

所以有两个不同的配置文件,一个包含我在表单中输入的用户名,另一个包含名字和姓氏(如图所示)。

这是我的观点.py:

def signup(request):
    if request.method == 'POST':
        form = UserRegistrationForm(data=request.POST)
        profileform = UserRegistrationProfileForm(data=request.POST)
        if form.is_valid() and profileform.is_valid():
            user = form.save()
            profileform.save()
            if user is not None:
                if user.is_active:
                    user_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
                    return redirect('/dashboard/')
    else:
        form = UserRegistrationForm()
        profileform = UserRegistrationProfileForm()
    return render(request, 'signup-user.html', {'form': form, 'profileform': profileform})

Forms.py(用于表单的配置文件部分):

class UserRegistrationProfileForm(forms.ModelForm):
    user_fname = forms.CharField(#)
    user_lname = forms.CharField(#)

    class Meta:
        model = UserProfileModel
        fields = ['user_fname', 'user_lname']

    def clean(self):
        #...

    def save(self, commit=True):
        profile = super(UserRegistrationProfileForm, self).save(commit=False)
        if commit:
            profile.save()
        return profile

Models.py(用于配置文件,包括接收器信号):

class UserProfileModel(models.Model): # For the Company Employees
    user = models.OneToOneField(UserModel, related_name='userprofilemodel', on_delete=models.CASCADE, blank=True, null=True)
    user_fname = models.CharField(max_length=30, verbose_name='First Names')
    user_lname = models.CharField(max_length=30, verbose_name='Last Name')

    class Meta:
        verbose_name = 'Profile'

    def __unicode__(self):
        #...

    def save(self, *args, **kwargs):
        super(UserProfileModel, self).save(*args, **kwargs)

    @receiver(post_save, sender=UserModel)
    def create_user_profile(sender, instance, created, **kwargs):
        if created:
            UserProfileModel.objects.create(user=instance)

    @receiver(post_save, sender=UserModel)
    def save_user_profile(sender, instance, **kwargs):
        instance.userprofilemodel.save()

不确定我做错了什么?我希望表单创建一个用户配置文件,其中包含用户实例作为用户,以及名字和姓氏。

关于我哪里出错了有什么想法吗?

更新

这是UserRegistrationForm 类:

class UserRegistrationForm(forms.ModelForm):
    #

    class Meta:
        model = UserModel
        fields = ['related_company_slug', 'username', 'user_email', 'password', 'passwordrepeat']

    def clean(self):
        #

    def save(self, commit=True):
        self.check_company
        user = super(UserRegistrationForm, self).save(commit=False)
        user.set_password(self.cleaned_data.get('password'))
        user.is_active = True
        if commit:
            user.save()
        return user

【问题讨论】:

  • 我们能看到UserRegistrationForm 类吗?
  • 我已经更新了我的问题@MattCremeens

标签: python django


【解决方案1】:

您应该摆脱这些信号。他们没有做任何有用的事情,并且可能是重复的原因。

相反,您需要做一些事情来告诉表单您正在创建的配置文件属于您刚刚创建的用户:

user = form.save()
profile = profileform.save(commit=False)
profile.user = user
profile.save()

您还应该摆脱表单和模型上的保存方法 - 定义一个唯一作用是调用超级方法的覆盖方法是没有意义的。

同样,您可以去掉对user is not Noneuser.is_active 的检查;您知道用户存在并且处于活动状态,因为您刚刚创建了它。

【讨论】:

  • 我的个人资料表单没有用户字段,我该如何调整它以适应这个?
  • 我不明白你的评论。我不认为您的表单有用户字段。您应该按原样使用此代码。
  • 太棒了,谢谢!事实证明,信号是问题所在。
【解决方案2】:

实际上,imo 最好始终为每个用户提供个人资料。为了实现这个你使用的发布/预保存信号是有意义的。例如,当用户刚刚在系统中注册时,将自动创建新用户的配置文件 代码会很简单:

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    # your fields

@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)

另外,如果您已经拥有没有配置文件的用户池,并且想要为他们创建配置文件,您可以使用数据迁移,如果您需要此类数据迁移的代码,请参阅post in my blog

【讨论】:

  • 请披露您与该网站的任何从属关系
  • @Riker 如我的个人资料所示,我是该网站的所有者
  • 虽然链接在这里是可以容忍的,只要它们是有用的,他们就会皱眉头,特别是如果你的所有帖子都包含指向同一个站点的链接。我建议您阅读How not to be a spammer 以了解更多关于社区的想法
  • 请注意,如果您想宣传自己的产品/博客,您必须在回答中披露您的隶属关系,否则您的回答可能会被标记为垃圾邮件。请阅读How to not be a spammer
  • @CalvT,感谢您的解释,我会考虑的!尽管如此,我真诚地相信我的回答可能有助于解决问题的根本原因,并详细回答问题“我不确定我做错了什么?”,这是我的最佳实践,我想分享它,链接也有助于指出不应超载答案的信息。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-01
  • 1970-01-01
相关资源
最近更新 更多