Skip to content

Instantly share code, notes, and snippets.

@windhamwong
Last active November 17, 2015 20:24
Show Gist options
  • Save windhamwong/5c94b0330d3ab9e85f2f to your computer and use it in GitHub Desktop.
Save windhamwong/5c94b0330d3ab9e85f2f to your computer and use it in GitHub Desktop.
List-Dict field programming guide for Tastypie with MongoDB

#Introduction:

When working with MongoDB, list and dict objects are often used for storing dynamic size of data. However, the original tastypie and DRF do not support serialising these fields into JSON. Thus, some overriding functions are required in order to make them work. This gist presents the guideline for how to handle list objects in Django using Tastypie.

Requirement:

  1. Django-nonrel
  2. djangotoolbox
  3. django-mongodb-engine
  4. tastypie
  5. MongoDB 3

#Problem: When working with list-dict objects in Django, the serialised list-dict object is transformed into string object instead of list, i.e. "[{...},{...}]". Although parsing the string back into list and dict objects is possible, it is extremely inefficient and insecure.

#Settings:

###settings.py

DATABASES = {
    'default': {
        'ENGINE': 'django_mongodb_engine',
        'NAME': 'db',
        'HOST': '192.168.1.2',
        'PORT': '27017',
        'USER': 'user',
        'PASSWORD': 'pass',
    }
}

#Database fields:

{
    "_id" : ObjectId("563cd5b25b10aa7d24c12fd0"),
    "map" : "prontera",
    "item" : [
        {
            "count" : NumberInt(1),
            "price" : NumberInt(800000),
            "type" : NumberInt(4),
            "ID" : NumberInt(2203),
            "extra" : "眼鏡"
        },
        {
            "count" : NumberInt(1),
            "price" : NumberInt(800000),
            "type" : NumberInt(4),
            "ID" : NumberInt(2271),
            "extra" : "眼鏡頭飾"
        },
    ],
    "name" : "寒瑀煙",
    "VID" : NumberInt(1621182),
    "title" : "卡;裝",
    "y" : NumberInt(113),
    "x" : NumberInt(139),
    "update" : ISODate("2015-11-17T21:25:38.644+0000"),
    "server" : "moonlight"
}

#Models:

###models.py

class shopItemsObject(models.Model):
    ID = models.PositiveSmallIntegerField(max_length=8,)
    price = models.PositiveSmallIntegerField(max_length=9,)
    count = models.PositiveSmallIntegerField(max_length=6,)
    extra = models.CharField(max_length=32,)
    _type = models.PositiveSmallIntegerField(max_length=3,)
    class Meta:
        verbose_name = "item"

class shopsObject(models.Model):
    _id = models.CharField(max_length=32,)
    map = models.CharField(max_length=32,)
    name = models.CharField(max_length=30,)
    VID = models.PositiveSmallIntegerField(max_length=8,)
    title = models.CharField(max_length=60,)
    x = models.PositiveSmallIntegerField(max_length=3,)
    y = models.PositiveSmallIntegerField(max_length=3,)
    update = models.DateTimeField(auto_now_add=True)
    server = models.CharField(max_length=30,)
    item = ListField((EmbeddedModelField(shopItemsObject)))
    #It is not ListField(DictField()) because all objects are stored as
    #dict, thus EmbeddedModelField would represent the whole dict object.
    class Meta:
        verbose_name = "shop"
        db_table = "shop"

###resources.py

#This resource object is used to parse the item objects stored in 'item'
#field
class shopItemsObjectResource(ModelResource):
    class Meta:
        object_class = shopItemsObject
        #Here is used for getting the fields in every 'item'
        fields = ['count', 'type', 'ID', 'extra', 'price']

#This resource object is the main resource used for getting the whole
#entity with the 'item' field.
class shopsObjectResource(ModelResource):
    item = ListField(models.ForeignKey(shopItemsObject))
    class Meta:
        queryset = shopsObject.objects.order_by('-update').all()
        resource_name = 'shop'
        item = ListField()
        fields = ['name', 'VID', 'title', 'x', 'y', 'update', 'server', 'item']
        serializer = Serializer(formats=['json'])
        limit = 10
        max_limit = 20
        ordering = ['-update']
    def dehydrate(self, data):
        #Initialise a resource object for every 'item' object
        items_res = shopItemsObjectResource()
        #Call build_bundle for each of the 'item' object
        items_data = [items_res.build_bundle(obj) for obj in data.obj.item]
        for single in items_data:
            #transform every 'item' object into JSON?
            items_res.full_dehydrate(single)
        #Store back to the data bundle
        data.data['item'] = items_data
        return data
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment