Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GenericForeignKey, ContentType and DjangoRestFramework

I am working on an discussion app in Django, that has Threads, Posts, Replies and Votes. Votes uses Generic Foreign Keys and Content Types to ensure a user can only vote once on a specific Thread/Post/Reply.

Vote model looks like this:

VOTE_TYPE = (
    (-1, 'DISLIKE'),
    (1, 'LIKE'),
)

class Vote(models.Model):
    user = models.ForeignKey(User)
    content_type = models.ForeignKey(ContentType,
        limit_choices_to={"model__in": ("Thread", "Reply", "Post")}, 
        related_name="votes")
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')
    vote = models.IntegerField(choices=VOTE_TYPE)

    objects = GetOrNoneManager()

    class Meta():
        unique_together = [('object_id', 'content_type', 'user')]

Vote Serializer:

class VoteSerializer(serializers.ModelSerializer):
    class Meta:
        model = Vote

The view to handle a vote:

@api_view(['POST'])
def discussions_vote(request):

if not request.user.is_authenticated():
    return Response(status=status.HTTP_404_NOT_FOUND)

data = request.DATA

if data['obj_type'] == 'thread':
    content_type = ContentType.objects.get_for_model(Thread)

    print content_type.id

    info = {
        'content_type': content_type.id,
        'user': request.user.id,
        'object_id': data['obj']['id']
    }

    vote = Vote.objects.get_or_none(**info)

    info['vote'] = data['vote']

    ser = VoteSerializer(vote, data=info)

    if ser.is_valid():
        print "Valid"
    else:
        pprint.pprint(ser.errors)

return Response()

request.DATA content:

{u'vote': -1, 
u'obj_type': u'thread', 
u'obj': 
    {
    ...
    u'id': 7, 
    ...
    }
}

When I vote, Django Rest Framework serializer throws an error:

Model content type with pk 149 does not exist.  

149 is the correct id for the ContentType for the Thread model, according to

print content_type.id

I'm pretty much at a loss at what could be causing this...

like image 855
chrisg Avatar asked Feb 27 '14 13:02

chrisg


People also ask

What is GenericForeignKey?

In Django, a GenericForeignKey is a feature that allows a model to be related to any other model in the system, as opposed to a ForeignKey which is related to a specific one.

How does Django ContentTypes work?

You probably have already seen Django's ContentTypes and wondered how to use it or what is it for anyway. Basically it's a built in app that keeps track of models from the installed apps of your Django application. And one of the use cases of the ContentTypes is to create generic relationships between models.


1 Answers

The issue is probably that you have a generic foreign key in there, which could be linked to any type of model instance, so there's no default way of REST framework determining how to represent the serialized data.

Take a look at the docs on GFKs in serializers here, hopefully it should help get you started... http://www.django-rest-framework.org/api-guide/relations#generic-relationships

If you're still finding it problematic then simply drop out of using serializers altogether, and just perform the validation explicitly in the view, and return a dictionary of whatever values you want to use for the representation.

like image 194
Tom Christie Avatar answered Oct 02 '22 02:10

Tom Christie