Search code examples
djangomany-to-manycreate-view

Django ManyToMany from String in CreateView


What i want to do, is give the people to tag a post by writing in a charfield, separating the tags with ','.

now this is my model (just the part we care)

class Tag(models.Model):
    name = models.CharField(max_length=100, default='')


    def __unicode__(self):
        return "%s" % (self.name)


class Post(models.Model):
    .....
    tags = models.ManyToManyField(Tag,blank=True, null=True)

then i've a form

class PostForm(ModelForm):
...
    tags = forms.CharField(label=(u'Tags '))

    class Meta:
        model = Publication

    def __init__(self, *args, **kwargs):
        self.helper = FormHelper()
        self.helper.form_method = 'post'
        self.helper.add_input(Submit('submit', 'Invia'))
        self.helper.form_class = 'form-horizontal'

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

then i've my createView, to which i overridden the form_valid method to make string parsing

class PostAdd(CreateView):
    template_name = 'form.html'
    form_class = PostForm
    success_url='/'

    def form_valid(self, form):
        pub = form.save(commit=False)
        pub.tags=None
        pub.save()

        tags=str(self.request.POST.get('tags'))
        tags = tags.split(',')
        tl=[]
        for tag in tags:
            tl.append(Tag.objects.get_or_create(name=tag))
        pub.tags.add(tl)

        form.save_m2m()
        return HttpResponseRedirect(self.get_success_url())

what i did is to save the form with commit=False in order to change the value of the tags. I tried with None or [] but in all the cases what i've back is an error on the line of the pub.tags=None assignme:

'Post' instance needs to have a primary key value before a many-to-many relationship can be used.

Solution

  • Here you are settings "tags" attribute to None, but your publication does not have a Primary Key yet, so the many to many relationship is having a hard time.

    What you have to do is to save it first.

    You will find more about this here

    def form_valid(self, form):
        pub = form.save(commit=False)
        pub.save()
        pub.tags=None
    
    
        tags=str(self.request.POST.get('tags'))
        tags = tags.split(',')
        tl=[]
        for tag in tags:
            tl.append(Tag.objects.get_or_create(name=tag))
        pub.tags.add(tl)
        pub.save()
        form.save_m2m()
        return HttpResponseRedirect(self.get_success_url())