2

我是 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"
        }
    }
]

我们可以看到authors并且publisher只显示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"
    }
]

authors字段publisher包括所有数据。我通过向所有模型添加一个名为 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 是否提供了更好的方法来做到这一点?提前致谢!

4

2 回答 2

1

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

于 2013-07-05T06:10:02.777 回答
1
  • 选项 1 是Django-piston通过手动指定模型字段,您可以获得嵌套列表和外键跟随。可能是获得您想要的东西的最快方法,最小的错误,但不是很灵活。

  • 选项 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()。

祝你好运!

于 2013-07-05T07:16:38.663 回答