Getting mongoengine and django rest framework to play nice

user1876508 picture user1876508 · Jun 20, 2013 · Viewed 7k times · Source

I am wondering how I can get mongoengine and djangoRESTframework to work with each other. Currently, my model is

from mongoengine import *
import datetime

class Blog(Document):
    post_id = IntField(unique=True)
    title = StringField(max_length=144, required=True)
    date_created = DateTimeField(default=datetime.datetime.now)
    body = StringField(required=True)

and I have the serializer defined as

from rest_framework.views import APIView
from rest_framework.response import Response
from .models import *

class BlogList(APIView):
    """
    Lists all blog posts, or creates a new post
    """
    def get(self, request, format=None):
        posts = Blog.objects.to_json()
        return Response(posts)

But I am receiving the error

TypeError at /blog/

__init__() takes exactly 1 argument (2 given)

Request Method:     GET
Request URL:    http://127.0.0.1:8000/blog/
Django Version:     1.5.1
Exception Type:     TypeError
Exception Value:    

__init__() takes exactly 1 argument (2 given)

which gives the following traceback

response = callback(request, *callback_args, **callback_kwargs)

Answer

Nicolas Cortot picture Nicolas Cortot · Jun 20, 2013

Django REST Framework is intended to work well with Django's models. As MongoEngine is not a replacement for Django's Models, you will need to define a few more functions for it to play nice with Django Rest framework.

If you need a framework build for MongoEngine, you might want to take a look at django-tastypie-mongoengine instead.

If you prefer to use Django REST Framework it's perfectly feasible though. Your BlogList class is actually a View, not a Serializer. First, define a serializer class:

from rest_framework import serializers
from .models import Blog

class BlogSerializer(serializers.Serializer):
    post_id = serializers.IntegerField()
    title = serializers.CharField(max_length=144)
    date_created = serializers.DateTimeField(required=False)
    body = serializers.CharField()

    def restore_object(self, attrs, instance=None):
        if instance is not None:
            for k, v in attrs.iteritems():
                setattr(instance, k, v)
            return instance
        return Blog(**attrs)

Since the MongoEngine Document is not a Django Model instance, you need to create the objects yourself instead of inheriting from serializers.ModelSerializer. That is why the restore_object method is here. From the documentation: Given a dictionary of deserialized field values, [it will] either update an existing model instance, or create a new model instance.

Then you can define your view, e.g.

from rest_framework import generics
from .models import Blog

class BlogList(generics.ListCreateAPIView):
    serializer_class = BlogSerializer

    def get_queryset(self):
        return Blog.objects

Again, Django REST Framework expects a few things of a standard Django models which are not verified by MongoEngine Documents, hence the need to redefine the get_queryset method.

Then in your urls.py, add:

url(r'^blog/', BlogList.as_view(), name='blog-list'),