Home > Back-end >  Can not add ManyToManyFields using froms.py in django
Can not add ManyToManyFields using froms.py in django

Time:10-07

I am trying to add data in a model using django forms but getting

Direct assignment to the forward side of a many-to-many set is prohibited. Use tag.set() instead. Please help me solve this. I am using multiselect field to send data to views.py.

models.py

class Tags(models.Model):
    tag = models.CharField(max_length=100)

    def __str__(self):
        return self.tag

    class Meta:
        verbose_name_plural = 'Tags'

class Post(models.Model):
    ...
    author = models.ForeignKey(User, verbose_name='Author', on_delete=models.CASCADE)
    feature_image = models.ImageField(upload_to='blog/', verbose_name='Add Feature Image')
    tag = models.ManyToManyField(Tags, related_name='post_tags', verbose_name='Add Tags')
    

    def __str__(self):
        return self.title

forms.py

class PostForm(forms.ModelForm):
    ...
    class Meta:
        model = models.Post
        fields = [...]

views

def adminNewPostView(request):
    form = forms.PostForm()
    
    if request.method == 'POST':
        ...
        tags = request.POST.getlist('tagName')
        form = forms.PostForm(request.POST, request.FILES)
        if form.is_valid():
            
            post = form.save(commit=False)
            post.author = request.user
            post.category = cat
            if subcat:
                post.sub_categories = subcat
            if subfil:
                post.filter_option = subfil

            add_tags = models.Tags.objects.filter(tag__in=tags)

            for tl in add_tags:
                post.tag = tl # Getting Error here

            post.save()

         
            return HttpResponseRedirect(reverse('blog_app:index'))

Error

Direct assignment to the forward side of a many-to-many set is prohibited. Use tag.set() instead.

CodePudding user response:

views.py

def adminNewPostView(request):
    form = forms.PostForm()
    
    if request.method == 'POST':
        ...
        tags = request.POST.getlist('tagName')
        form = forms.PostForm(request.POST, request.FILES)
        if form.is_valid():
            
            post = form.save(commit=False)
            post.author = request.user
            post.category = cat
            if subcat:
                post.sub_categories = subcat
            if subfil:
                post.filter_option = subfil

            post.save()
            add_tags = models.Tags.objects.filter(tag__in=tags)

            for tl in add_tags:
                post.tag.add(tl) # new
         
            return HttpResponseRedirect(reverse('blog_app:index'))

to learn more about this please refer to https://docs.djangoproject.com/en/dev/ref/models/relations/
or here https://docs.djangoproject.com/en/2.2/topics/db/examples/many_to_many/#many-to-many-relationships
there is also an other way of doing it.like this

def adminNewPostView(request):
    form = forms.PostForm()
    
    if request.method == 'POST':
        ...
        tags = request.POST.getlist('tagName')
        form = forms.PostForm(request.POST, request.FILES)
        if form.is_valid():
            
            post = form.save(commit=False)
            post.author = request.user
            post.category = cat
            if subcat:
                post.sub_categories = subcat
            if subfil:
                post.filter_option = subfil
            post.save()
            add_tags = models.Tags.objects.filter(tag__in=tags)

            post.tag.add(*add_tags) # new

            

         
            return HttpResponseRedirect(reverse('blog_app:index'))

CodePudding user response:

A Django form can handle ManyToManyFields itself, but can only do that with .save_m2m() or .save() without using commit=False: first it needs to save the Post object since it needs the primary key of that Post object to link the object to other items.

If your PostForm uses the tag field:

class PostForm(forms.ModelForm):
    …
    class Meta:
        model = models.Post
        #          ↓ tag field
        fields = ['tag', 'other', 'fields']

then we can let the form do the work for us:

from django.shortcuts import redirect

def adminNewPostView(request):
    form = forms.PostForm()
    
    if request.method == 'POST':
        …
        tags = request.POST.getlist('tagName')
        form = forms.PostForm(request.POST, request.FILES)
        if form.is_valid():
            if subcat:
                form.instance.sub_categories = subcat
            if subfil:
                form.instance.filter_option = subfil
            form.instance.author = request.user
            form.instance.category = cat
            form.save()
            return redirect('blog_app:index')
  • Related