Question

I have a model named Project containing three ManyToManyFields (member_student, supervisor and tag). One (tag) of which is excluded in the form and it has to be saved manually. So, in the view, I use save(commit=False) because I have to change some fields of the form. After changing the fields, the form is saved and I add the tags one by one. Then, when I call save_m2m to save ManyToManyField, I get the error given by the save_m2m line in views:

invalid literal for int() with base 10: 'a'

Here is my model.

class Tag(models.Model):
    name = models.CharField(unique=True, max_length=60)
    slug = models.SlugField(max_length=60, unique=True)

    def save(self, *args, **kwargs):
        if not self.id:
            self.slug = slugify(self.name)
        super(Tag, self).save(*args, **kwargs)


class Project(models.Model):
    '''Main Project uploading'''
    title = models.CharField(max_length=300)
    description = models.TextField(null=True)
    #year = models.ForeignKey(Year)
    tag = models.ManyToManyField(Tag)
    owner_student = models.ForeignKey(Student, related_name='member_student')
    member_student = models.ManyToManyField(Student, blank=True, null=True)
    supervisor = models.ManyToManyField(Supervisor, blank=True, null=True)
    subject = models.ForeignKey(Subject)
    main_document = models.FileField(upload_to='main_documents/')
    supporting_document = models.FileField(upload_to='supp_documents/', blank=True, null=True)
    source_code = models.FileField(upload_to='source_code/', blank=True, null=True)
    screenshot = models.ImageField(upload_to='screenshots/', blank=True, null=True)

This is the forms.py:

class ProjectForm(forms.ModelForm):
    class Meta:
        model = Project
        exclude = ['owner_student', 'slug', 'tag']           
    tag = forms.CharField(max_length=100)

Here is the View.

def add_project(request):
    parameters = {}
    if request.method =="POST":
        upload_form = ProjectForm(request.POST, request.FILES)
        if upload_form.is_valid():
            new_form = upload_form.save(commit=False)
            mystud = Student.objects.get(user=request.user)
            new_form.owner_student = mystud
            new_form.save()
            tags =  upload_form.cleaned_data['tag']
            tags = tags.split(',')
            for eachtag in tags:
                tag, created = Tag.objects.get_or_create(name=eachtag.strip())
                tag.save()
                new_form.tag.add(tag)
            upload_form.save_m2m()
            return HttpResponseRedirect(reverse(project_page, args=(new_form.slug,)))
        else:
            parameters["upload_form"] = upload_form
            return render_to_response('upload.html', parameters)
    else:
        upload_form = ProjectForm()
        parameters["upload_form"] = upload_form
        parameters["page_title"] = "Upload your Project"
        return render_to_response('upload.html', parameters)

So, my question is how can I save the tags as well as the two other ManyToManyField without getting error ? I guess the save_m2m function is giving error because of the tuple returned by get_or_create.

Was it helpful?

Solution

Don't use 'tag' as the name of the charfield on your form. That'll cause save_m2m to think it needs to use the values in the charfield to set the related 'tag' field on the object.

Internally, save_m2m goes through each many-to-many field in the model. It checks for the presence of data under that name in the form's cleaned_data dictionary, and if present has the model field object update record the contents using the field's save_form_data method. It trusts the form field to have returned the right type of Python object. In this case, your charfield is returning a string (as expected), but it's incorrect to assign a string to a many-to-many field.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top