【问题标题】:Direct assignment to the forward side of a many-to-many set is prohibited. Use emails_for_help.set() instead禁止直接分配到多对多集合的前端。改用 emails_for_help.set()
【发布时间】:2018-10-05 12:19:08
【问题描述】:

我是 Django 新手,没有找到有关此问题的任何参考资料。当我在 Django 模型 (models.py) 中使用多对多字段时出现此错误。我想问题是从表单(forms.py)中分配视图中的 m2m 字段(views.py)。

如何在视图中分配 m2m 字段? (Django version 2.0, python - 3.5)

models.py

class User(AbstractUser):
 username=models.CharField(max_length=20)
 email = models.EmailField(_('email address'), unique=True)


class Setupuser(models.Model):
 organization=models.CharField(max_length=200,blank=False,null=True)
 emails_for_help = models.ManyToManyField(User)

views.py

class Set_user(FormView):
 template_name="pkm_templates/set_up_user.html"
 form_class = Set_User_Form
 success_url = '/thanks/'

 def form_valid(self, form):
    org = form.cleaned_data.get('organization')
    emails = form.cleaned_data.get("emails_for_help")
    instance = Setupuser(organization=org,emails_for_help=emails)
    instance.save()
    return redirect("/")

forms.py

class Set_User_Form(ModelForm):
  emails_for_help = forms.ModelMultipleChoiceField(
    queryset=User.objects.all(),
    widget=forms.CheckboxSelectMultiple
  )

  class Meta:
    model = Setupuser
    fields = ["organization","emails_for_help"]

【问题讨论】:

    标签: python django django-orm manytomanyfield


    【解决方案1】:

    您需要获取User 对象,然后将其添加到emails_for_help 字段。创建实例时不能将对象添加到ManyToManyField。看看doc

    class Set_user(FormView):
        template_name="pkm_templates/set_up_user.html"
        form_class = Set_User_Form
        success_url = '/thanks/'
    
        def form_valid(self, form):
            org = form.cleaned_data.get('organization')
            emails = form.cleaned_data.get("share_email_with")
    
            users = User.objects.filter(email__in=emails)
            instance = Setupuser.objects.create(organization=org)
    
            for user in users:
                instance.emails_for_help.add(user)
    
            return redirect("/")
    

    另一种方法是使用.set()

    class Set_user(FormView):
        template_name="pkm_templates/set_up_user.html"
        form_class = Set_User_Form
        success_url = '/thanks/'
    
        def form_valid(self, form):
            org = form.cleaned_data.get('organization')
            emails = form.cleaned_data.get("share_email_with")
    
            users = User.objects.filter(email__in=emails)
            instance = Setupuser.objects.create(organization=org)
    
            instance.emails_for_help.set(users)
    
            return redirect("/")
    

    或者您可以简单地使用.add() 添加任意数量的对象。

    class Set_user(FormView):
        template_name="pkm_templates/set_up_user.html"
        form_class = Set_User_Form
        success_url = '/thanks/'
    
        def form_valid(self, form):
            org = form.cleaned_data.get('organization')
            emails = form.cleaned_data.get("share_email_with")
    
            users = User.objects.filter(email__in=emails)
            instance = Setupuser.objects.create(organization=org)
    
            instance.emails_for_help.add(*users)
    
            return redirect("/")
    

    【讨论】:

    • 我遇到了异常:-精确查找的 QuerySet 值必须使用切片限制为一个结果。
    • 您在emails 中有多个电子邮件地址吗?
    • 非常欢迎。并查看文档以获取更多详细信息。
    【解决方案2】:

    我尝试了上述所有解决方案,但它在 Django 3.0 上不起作用。所以,我做了自己的研究并提出了解决方案。 解决方案会很简单。我的回答是笼统的。 假设存在一个表单字段specialFieldName,它在models.py 中定义为ManyToManyField

    为什么会出现这个错误?

    用户通过“django 表单”输入的该字段的选项存储为查询集。在这种情况下,我们根本无法在基于此查询集创建对象期间将此查询集分配给ManyToManyField 属性。这就是您收到上述错误的原因。

    所以,我们首先根据我们从 django-form 获得的所有信息创建对象,除了specialFieldName,然后我们使用 add() 方法将此查询集的所有元素添加到我们刚刚的对象创建。

    所以,我们需要遍历这个查询集。

     returnedQueryset = form.cleaned_data.get('specialFieldName')
        dummyObject = ObjectModel.objects.create(..using all the info except specialFieldname..)
        for member in returnedQueryset:
            dummyObject.add(member)
    

    不幸的是,循环不会遍历返回的查询集的所有成员(阅读Why?)。因此,上面的事情不起作用。我们必须更高级一点,并改用 iterator() 方法。

    for member in returnedQueryset.iterator():
        dummyObject.add(member)
    

    现在可以正常使用了。

    (PS 这是我在 Stackoverflow 上的第一个答案。感谢我所有的导师 ;-))

    【讨论】:

    • 异常值:“dummyObject”对象没有属性“add”
    • 所以它应该是:dummyObject.attribute.add(member) 例如:Setupuser.emails_for_help.add(member)
    • 是的@DesertCamel。这件事可能是我们现在使用它的方式的更新。一年前我写这个答案时,它不存在。
    【解决方案3】:

    从旧 Django 版本升级到 Django 2.2 LTS 时,我遇到了同样的错误 Direct assignment to the forward side of a many-to-many set is prohibited. Use plan_options.set() instead

    但是,当我使用.set() 时,我得到了SyntaxError: can't assign to function call。 对我来说,通过添加 _set:

    解决了这个问题
    existing_plan.plan_options_set = [x.pk for x in old_plan.plan_options.all()]
    

    【讨论】:

      【解决方案4】:

      试试这个代码,因为我在使用 ManyToManyField 时遇到了同样的问题。

      class Set_user(FormView):
       template_name="pkm_templates/set_up_user.html"
       form_class = Set_User_Form
       success_url = '/thanks/'
      
       def form_valid(self, form):
          org = form.cleaned_data.get('organization')
          instance = Setupuser(organization=org,emails_for_help=emails)
          instance.save()
          instance.email.add(request.user.email)
          instance.save()
          return redirect("/")
      

      【讨论】:

        猜你喜欢
        • 2021-07-01
        • 2020-03-21
        • 2020-04-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-18
        • 2019-03-02
        • 1970-01-01
        相关资源
        最近更新 更多