【问题标题】:Django Forms saving request.user in ManyToMany fieldsDjango Forms 在 ManyToMany 字段中保存 request.user
【发布时间】:2018-12-07 12:51:00
【问题描述】:

我有一个可以添加用户的简单组模型。

class Group(models.Model):
    name = models.CharField(max_length=50)
    users = models.ManyToManyField(settings.AUTH_USER_MODEL)
    created_by = models.ForeignKey(
             settings.AUTH_USER_MODEL, on_delete=models.CASCADE, 
             related_name='admin_on_group')

    date_created = models.DateTimeField(auto_now_add=True)
    date_modifies = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.name

我有一个基本的CreateView 用于该组。创建组的登录用户将保存在字段created_by 中。但是,我还想在users 字段中保存相同的登录用户,以便他可以作为该组的普通成员参与。问题是视图最终只保存了登录用户,而从表单字段users 传入的其他用户没有保存。

例如,如果一个名为“george”的用户创建了一个组,那么他也应该添加到created_byusers 中。截至目前,当我在表单中选择其他用户时,只有乔治会保存在两个字段中。

class GroupCreateView(CreateView):

    form_class = GroupForm
    template_name = "groups/group_create.html"

    def form_valid(self, form):
        form = form.save(commit=False)
        form.created_by = self.request.user

        form.save()

        # Apparently you can only add M2M relationships saves after first            
        # saving
        form.users.add(User.objects.get(pk = self.request.user.pk))
        return HttpResponseRedirect(reverse('group_list'))

    def get_form_kwargs(self):
        kwargs = super(GroupCreateView, self).get_form_kwargs()
        kwargs['user'] = self.request.user

        return kwargs

我有一个具有以下大纲的 modelForm。 注意:下面self.fields['users'] 中传递的初始数据也不会显示。我还使用了一个将 phone_number 作为 USERNAME_FIELD 的自定义模型。 self.fields['users'] 中传递的查询集有效。

class UserModelChoiceField(forms.ModelMultipleChoiceField):
    def label_from_instance(self, obj):
        return obj.get_full_name()


class GroupForm(forms.ModelForm):

    class Meta:
        model = Group
        fields = ('name', 'users', )

    def __init__(self, *args, **kwargs):
        # popping the user from kwargs dictionary that has been 
        # passed in CreateView
        user = kwargs.pop('user', None)

        self.user = user  # setting self.user to be equal to user above

        super(GroupForm, self).__init__(*args, **kwargs)

        self.fields['users'] = UserModelChoiceField(
               queryset=User.objects.exclude(phone_number=str(user)),
               initial=User.objects.get(phone_number=str(user))
        )

【问题讨论】:

  • 我猜你需要在添加用户后再次调用保存。 mygroup=form.save() mygroup.users.add(User.objects.get(pk = self.request.user.pk)) mygroup.save()
  • 注意,对User.objects.get(pk = self.request.user.pk) 进行额外查询是没有意义的。就像你已经使用的一样使用self.request.userform.users.add(self.request.user)
  • 另一个改进代码的建议——我会使用queryset=User.objects.exclude(pk=user.pk),因为使用str(user) 进行过滤很脆弱。使用initial=User.objects.get(phone_number=str(user)) 毫无意义,因为该用户被排除在查询集中,因此不会成为表单中的选项。如果您确实将 initial 设置为其他内容,我认为它应该是一个列表,因为它是一个多选字段(我对此不是 100% 确定)。

标签: python django django-forms django-views django-class-based-views


【解决方案1】:

由于你已经saved the formcommit=False,你需要在保存实例后调用表单的save_m2m()方法来保存多对多数据。

def form_valid(self, form):
    instance = form.save(commit=False)
    instance.created_by = self.request.user
    instance.save()
    form.save_m2m()
    # Apparently you can only add M2M relationships saves after first            
    # saving
    instance.users.add(self.request.user)
    return HttpResponseRedirect(reverse('group_list'))

请注意,我已将该行更改为 instance = form.save(commit=False),以便更清楚地表明 save() 返回一个实例,以便您仍然可以访问该表单。

【讨论】:

  • 谢谢!!!这样就解决了保存问题。我将尝试获取材料来理解为什么我应该使用实例以及为什么我应该在保存其他 ForiegnKey 关系之后将实例保存到 M2M 关系中。我什至不需要表单字段中用户的初始值。谢谢!
  • 正如我上面所说,您的初始数据没有意义——您已将该用户从查询集中排除。
猜你喜欢
  • 2012-03-08
  • 1970-01-01
  • 2017-10-18
  • 2011-09-06
  • 2020-09-29
  • 1970-01-01
  • 1970-01-01
  • 2019-02-15
  • 2017-04-06
相关资源
最近更新 更多