禁止直接分配到多对多集合的前端。使用 email_for_help. set()代替

我是新来的姜戈,没有发现任何关于这个问题的参考。当我在 Django 模型(models.py)中使用多对多字段时,我得到了这个错误。我想问题在于从表单(forms.py)分配 m2m 视场(views.py)。

如何分配 m2m 视场? (Django version 2.0python - 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)

视野,视野

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("/")

表格 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"]
102915 次浏览

You need to get the User object and then add it to emails_for_help field. You can't add an object to ManyToManyField when creating an instance. Have a look at the 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("/")

Another way of doing this is to use .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("/")

Or you can simply use .add() to add arbitrary number of objects.

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("/")

I tried all the above solutions and it doesn't work on Django 3.0 . So, I did my own research and came up with the solution. The solution is gonna be pretty simple. My answer is in general. Let us say there exists a form-field specialFieldName which is defined as a ManyToManyField in models.py .

Why did that error occur?

The options of this field which the user entered through the 'django form' are stored as a Queryset. In this scenario, we simply cannot assign this queryset to a ManyToManyField attribute during the creation of the object based on this queryset. This is the reason you are getting the above error.

So, we first create the object based on all the information we have got from the django-form, except the specialFieldName and then we use add() method to add all the elements of this queryset to the object we just created.

So, we need to iterate over this queryset.

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

Unfortunately, the loop doesn't iterate over all the members of the returnedQueryset (Read Why?). Thus, the above thing doesn't work. We gotta get a bit more advanced and use iterator() method instead.

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

Now it works fine.

(P.S. This was my first answer on Stackoverflow. Gratitude for all my mentors ;-))

I was getting the same error Direct assignment to the forward side of a many-to-many set is prohibited. Use plan_options.set() instead, when upgrading from an older Django version to Django 2.2 LTS.

However when I used .set() I got SyntaxError: can't assign to function call. For me the issue was fixed by adding _set:

existing_plan.plan_options_set = [x.pk for x in old_plan.plan_options.all()]

Try this code because i had the same problem while using 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("/")