有没有更好的方法将模型转换为格式良好的JSON字符串?

时间:2013-07-05 05:56:16

标签: python django json

我是Python和Django的新手,我只是按照Django Book上的教程,我根据教程创建了三个模型 - Publisher,Author,Book。现在我想获得所有书籍,并将它们编码为JSON字符串。 首先,我只使用djangoproject.com上找到的方法。这是代码:

from django.core import serializers

def getAllBooks(request):
    book_list = Book.objects.all()
    return HttpResponse(serializers.serialize("json", book_list), content_type="application/json")

它工作正常,但结果是这样的:

[
    {
        "pk": 1,
        "model": "books.book",
        "fields": {
            "publisher": 1,
            "title": "Book One",
            "authors" : [3, 4],
            "publication_date": "2013-07-01"
        }
    },
    {
        "pk": 2,
        "model": "books.book",
        "fields": {
            "publisher": 3,
            "title": "Book Two",
            "authors" : [5],
            "publication_date": "2013-07-05"
        }
    }
]

我们可以看到authorspublisher仅显示ID。然后我在djangoproject.com上阅读了那篇文章。最后,它引入了一个名为natural_key的方法。通过使用该方法,authors字段将如下所示:

 ....
    {
        "pk": 1,
        "model": "books.book",
        "fields": {
            "publisher": 1,
            "title": "Book One",
            "authors" : ["Douglas", "Adams"],
            "publication_date": "2013-07-01"
        }
    },
....

它更好,但仍然不是我想要的。我想要的是这个:

[
    {
    "publisher":{
        "website":"http://www.example.com/",
        "city":"SYD",
        "name":"Publisher",
        "country":"AU",
        "state":"NSW",
        "address":"1 Avenue"
    },
    "authors":[
        {
            "first_name":"Eric",
            "last_name":"Qian",
            "email":"eric@example.com"
        },
        {
            "first_name":"Eric2",
            "last_name":"Qian",
            "email":"eric2@example.com"
        }
    ],
    "publication_date":"01/07/2013",
    "title":"Book One"
    }
]

authorspublisher字段包含所有数据。我通过向所有模型添加一个名为JSONEncode的方法来实现这一目标:

from django.db import models

# Create your models here.
class Publisher(models.Model):
    name = models.CharField(max_length=30)
    address = models.CharField(max_length=50)
    city = models.CharField(max_length=60)
    state_province = models.CharField(max_length=30)
    country = models.CharField(max_length=50)
    website = models.URLField()

    def __unicode__(self):
        return self.name

    class Meta:
        ordering = ['name']

    def JSONEncode(self):
        #init a dictionary
        JSONData = {};
        #name
        JSONData['name'] = self.name
        #address
        JSONData['address'] = self.address
        #city
        JSONData['city'] = self.city
        #state_province
        JSONData['state'] = self.state_province
        #country
        JSONData['country'] = self.country
        #website
        JSONData['website'] = self.website
        #return the json data
        return JSONData

class Author(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=40)
    email = models.EmailField()

    def __unicode__(self):
        return u'%s %s' % (self.first_name, self.last_name)

    def JSONEncode(self):
        #init a dictionary
        JSONData = {};
        #first_name
        JSONData['first_name'] = self.first_name
        #last_name
        JSONData['last_name'] = self.last_name
        #email
        JSONData['email'] = self.email
        #return the json data
        return JSONData

class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField(Author)
    publisher = models.ForeignKey(Publisher)
    publication_date = models.DateField()

    def __unicode__(self):
        return self.title

    class Meta:
        ordering = ['title']

    def JSONEncode(self):
        #init a dictionary
        JSONData = {};
        #title
        JSONData['title'] = self.title
        #authors
        authors = []
        for author in self.authors.all():
        authors.append(author.JSONEncode())
        JSONData['authors'] = authors
        #publisher
        JSONData['publisher'] = self.publisher.JSONEncode()
        JSONData['publication_date'] = self.publication_date.strftime('%d/%m/%Y')
        #return the json data
        return JSONData

然后我修改books.views中的代码:

def getAllBooks(request):
    book_list = Book.objects.all()
    book_list_data = []
    for book in book_list:
        book_list_data.append(book.JSONEncode())
    return HttpResponse(json.dumps(book_list_data), content_type="application/json")

它的效果非常好,但缺点很明显 - 我必须为所有模型编写一个JSONEncode()函数。所以我想知道Django是否提供了更好的方法来做到这一点?提前谢谢!

2 个答案:

答案 0 :(得分:1)

您可以尝试使用Tastypiedjango-rest-framework。您可以自定义发出的JSON。虽然它增加了另一层复杂性,但从长远来看它可能会有所回报。

答案 1 :(得分:0)

  • 选项1为Django-piston。通过指定模型字段manually,您可以获得嵌套列表和外键。可能是获得你想要的最快的方法,最小的错误,但不是很灵活。

  • 选项2是否要由您自己以天真的方式进行模型序列化。对于每个模型,定义一个将自身转换为python字典的方法,然后在views.py中使用simplejson.dumps使其成为JSON。这种方法为您提供了完全控制和无限灵活性,可以决定您的JSON结构。稍后您可以使用多继承替换更优雅的解决方案来添加as_dict并定义自己的JsonResponse类。

示例:

# In models.py, add as_dict() method to all models
# Example for class Book
def as_dict(self):
    d = {
        "id": self.id,
        "publisher": self.publisher.as_dict(), # avoid this
        "title": self.title,        
        "publication_date": str(self.publication_date),  
        "publisher": self.publisher,  
        "authors": [author.as_dict() for author in self.authors.all()] # avoid this
    }

# then in views.py
def getAllBooks(request):
    book_list = [book.as_dict() for book in Book.objects.all().select_related()]
    return HttpResponse(simplejson.dumps(book_list), 
                        content_type="application/json")

<强>无论其

这两种方法都很脏。 您的数据库可能并且可能会因此而挣扎。 Django ORM将生成丑陋的SQL。最好是避免嵌套模型序列化。如果你真的需要它,别忘了select_related()。

祝你好运!