Search code examples
pythondjangoformsgeneric-foreign-key

Setting a Generic Foreign Key in Django while still sane


I'm banging my head against a wall trying to set a generic foreign key. Im going to post as much code as I possibly can and I'll try again in an hour.

I've read the documentation a million times but it doesn't seem to be helping.

Here is what I'm doing in my view.

def create_stream(request):
    stream_form = StreamForm()
    comment_form = CommentDataForm()

    if request.POST:    
        stream_form = StreamForm(request.POST)
        comment_form = CommentDataForm(request.POST)    
        if stream_form.is_valid() and comment_form.is_valid():

            attempt = comment_form.save()

            stream_form.save(commit=False)
            stream_form.content_object = attempt
            stream_form.save()

            return HttpResponseRedirect('/main/')
        else:
            HttpResponse('Nope')

    context = {'form1':stream_form, 'form2':comment_form}
    template = 'nregistration.html'
    return render(request, template, context)

The forms are all ModelForms (for ease of use and so I can use the save function). They look like this

class StreamForm(forms.ModelForm):
    class Meta:
        model = Stream
        exclude = ['object_id', 'content_object']

class CommentDataForm(forms.ModelForm):
    class Meta:
        model = CommentData

My relevant classes look like this

class Stream(models.Model):
    uid = models.CharField(max_length=20, null=True, blank=True)
    str_type = models.CharField(max_length=120, default='ABC')
    creator = models.ForeignKey(User, related_name="author", null=True, blank=True)
    parent = models.ForeignKey('self', related_name="child_of", null=True, blank=True)
    create_timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
    updated = models.DateTimeField(auto_now_add=False, auto_now=True)


    limit = models.Q(app_label='picture', model='commentdata') | models.Q(app_label='picture', model='repsonsedata')

    content_type = models.ForeignKey(ContentType,verbose_name='content page',limit_choices_to=limit,null=True,blank=True)
    object_id = models.PositiveIntegerField(verbose_name= 'related object',null=True)
    content_object = GenericForeignKey('content_type', 'object_id')

    def __unicode__(self):
        return self.uid 

    class Meta:
        unique_together = ('uid',)

class CommentData(models.Model):
    uid = models.CharField(max_length=20, null=True, blank=True)
    contents = models.CharField(max_length=120, default='ABC')  
    create_timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)

class ResponseData(models.Model):
    uid = models.CharField(max_length=20, null=True, blank=True)
    contents = models.CharField(max_length=120, default='ABC')  
    create_timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)

It all seems so simple but the content_type, object_id and content_object don't want to play ball. What I want to do is create an instance of the Comment Data form and assign it to the content_object type. I end up with an instance of both a stream and a comment data where the content_object returns none (as far as I can tell with HttpResponse) and the content_type and object id are both unset.

Is there any glaringly obvious/What a fool mistakes?


Solution

  • If you call save() with commit=False (in form object), then it will return an object that hasn’t yet been saved to the database. But you continue to work with the object form rather than the object of the model.

    Try this:

    stream_instance = stream_form.save(commit=False)
    stream_instance.content_object = attempt
    stream_instance.save()