【问题标题】:Change Values of User Model while it has OneToOneField Connection to another model in ModelForms django更改用户模型的值,同时它与 ModelForms django 中的另一个模型具有 OneToOneField 连接
【发布时间】:2017-12-20 23:29:01
【问题描述】:

我在使用 Django ModelForms 时遇到问题,这是其中之一

我想在 Django 中为用户模型添加一些额外的字段,因此在 models.py 中创建了一个 CustomeUser 模型

models.py

class CustomeUser(models.Model):
     user = models.OneToOneField(User)
     City = models.ForeignKey(City, on_delete=models.CASCADE, blank=True, null=True)
     Gender = models.ForeignKey(Gender, null=True, blank=True)
     DateOfBirth = models.DateField(null=True, blank=True)
     ProfilePicture = models.ImageField(verbose_name="Profile Picture", upload_to=user_directory_path, null=True, blank=True, max_length=255)
     Address = models.CharField(max_length=255, blank=True, null=True)
     def __str__(self):
         return str(self.user)

现在我想用 ModelForm 制作 EditProfileForm,这就是我所做的:

forms.py

class EditProfileForm(forms.ModelForm):
    firstname = forms.CharField(max_length=35,required=False)
    lastname = forms.CharField(max_length=35, required=False)
    cityid = forms.ModelChoiceField(queryset=City.objects.values('id').all(), required=False)
    genderid = forms.ModelChoiceField(queryset=Gender.objects.values('id').all(), required=False)
    dateofbirth = forms.DateField(required=False)
    profilepicture = forms.ImageField(required=False, max_length=255)
    address = forms.CharField(max_length=255, required=False)
    class Meta:
        model = CustomeUser
        fields = ['firstname' ,'lastname' ,'cityid' , 'genderid', 'dateofbirth', 'profilepicture', 'address' ]

我真的不知道如何以最好的方式做到这一点

【问题讨论】:

    标签: django python-3.x django-models django-forms


    【解决方案1】:

    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)
        bio = models.TextField(max_length=500, blank=True)
        location = models.CharField(max_length=30, blank=True)
        birth_date = models.DateField(null=True, 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()
    

    每当发生保存事件时,将 create_user_profilesave_user_profile 方法连接到 User 模型。这种信号称为post_save

    forms.py

    class UserForm(forms.ModelForm):
        class Meta:
            model = User
            fields = ('first_name', 'last_name', 'email')
    
    class ProfileForm(forms.ModelForm):
        class Meta:
            model = Profile
            fields = ('bio', 'location', 'birth_date')
    

    views.py

    @login_required
    @transaction.atomic
    def update_profile(request):
        if request.method == 'POST':
            user_form = UserForm(request.POST, instance=request.user)
            profile_form = ProfileForm(request.POST, instance=request.user.profile)
            if user_form.is_valid() and profile_form.is_valid():
                user_form.save()
                profile_form.save()
                messages.success(request, _('Your profile was successfully updated!'))
                return redirect('settings:profile')
            else:
                messages.error(request, _('Please correct the error below.'))
        else:
            user_form = UserForm(instance=request.user)
            profile_form = ProfileForm(instance=request.user.profile)
        return render(request, 'profiles/profile.html', {
            'user_form': user_form,
            'profile_form': profile_form
        })
    

    profile.html

    <form method="post">
      {% csrf_token %}
      {{ user_form.as_p }}
      {{ profile_form.as_p }}
      <button type="submit">Save changes</button>
    </form>
    

    您可以在单个数据库查询中预取相关数据:

    users = User.objects.all().select_related('profile')
    

    *您可以更改字段和类名,而不是使用配置文件

    【讨论】:

    • 你的意思是我必须使用两种形式而不是一次?
    • Tx Ebrahim 如果我通过管理控制台添加Profilelink,它会抱怨用户没有简历、位置和出生日期。有没有一种简单的方法来执行 2 ?另一个问题是:如果我想让用户拥有特殊形式的帐户(他们的 Customer 编号,例如 regex='\d{8}')和拥有“正常”无限制用户名的用户。
    • 我认为您尝试访问超级管理员的个人资料或您不保存个人资料信息的普通用户。
    • @Shaonshaonty 但配置文件在我的控制台管理类列表中......所以我应该能够从那里访问它,不是吗?
    猜你喜欢
    • 2010-10-24
    • 1970-01-01
    • 1970-01-01
    • 2016-11-10
    • 2016-01-18
    • 1970-01-01
    • 2014-06-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多