#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.
- Django-nonrel
- djangotoolbox
- django-mongodb-engine
- tastypie
- 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