Django构建RESTful接口的简单性

10 投票
6 回答
6301 浏览
提问于 2025-04-15 15:59

我最近有一个新项目,想找个理由学习Django。通常我喜欢建立RESTful的服务器接口,也就是通过网址来获取一些资源,然后返回一些平台无关的数据,比如XML或JSON。这其实不需要框架也能做到,但像Ruby on Rails这样的框架可以很方便地根据你传入的网址类型,自动返回XML数据,这样就省了很多麻烦。

我想问的是,Django有没有类似的支持?我在网上查了一下,发现有一些可以在Django上使用的第三方“RESTful”代码,但我对这些不是很感兴趣。

如果Django不行,有没有其他的Python框架是专门为这个目的设计的?这样我就不用像在PHP中那样重新发明轮子了。

6 个回答

3

看看Piston吧,它是一个为Django设计的小框架,用来创建RESTful API。

最近,Eric Holscher在他的博客上写了一篇文章,详细介绍了使用Piston的一些好处:Django中的大问题,基本解决:API

4

(我不得不删掉一些明显的链接。)

piston 点个赞 - (上面的链接)。我之前用过 apibuilder(华盛顿时报的开源项目),但 Piston 对我来说更简单。对我来说最难的就是搞清楚我的API的URL结构,以及如何使用正则表达式。还有,我也用过 surlex,它让这项工作变得简单多了。

举个例子,使用这个 Group 模型(来自我们正在开发的时间表系统):

class Group(models.Model):
    """
    Tree-like structure that holds groups that may have other groups as leaves. 
    For example ``st01gp01`` is part of ``stage1``.
    This allows subgroups to work. The name is ``parents``, i.e.::

        >>> stage1group01 = Group.objects.get(unique_name = 'St 1 Gp01')
        >>> stage1group01
        >>> <Group: St 1 Gp01>
        # get the parents...
        >>> stage1group01.parents.all()
        >>> [<Group: Stage 1>]

    ``symmetrical`` on ``subgroup`` is needed to allow the 'parents' attribute to be 'visible'.
    """
    subgroup = models.ManyToManyField("Group", related_name = "parents", symmetrical= False, blank=True)
    unique_name = models.CharField(max_length=255)
    name = models.CharField(max_length=255)
    academic_year = models.CharField(max_length=255)
    dept_id = models.CharField(max_length=255)
    class Meta:
        db_table = u'timetable_group'
    def __unicode__(self):
        return "%s" % self.name

还有这个 urls.py 的片段(注意 surlex 让正则表达式宏的设置变得很简单):

from surlex.dj import surl
from surlex import register_macro
from piston.resource import Resource
from api.handlers import GroupHandler
group_handler = Resource(GroupHandler)

# add another macro to our 'surl' function
# this picks up our module definitions
register_macro('t', r'[\w\W ,-]+')

urlpatterns = patterns('',
# group handler
# all groups
url(r'^groups/$', group_handler),
surl(r'^group/<id:#>/$', group_handler),
surl(r'^group/<name:t>/$', group_handler),)

然后这个处理器默认会处理 JSON 输出,也可以处理 XML 和 YAML

class GroupHandler(BaseHandler):
    """
    Entry point for Group model
    """

    allowed_methods = ('GET', )
    model = Group
    fields = ('id', 'unique_name', 'name', 'dept_id', 'academic_year', 'subgroup')

    def read(self, request, id=None, name=None):
        base = Group.objects
        if id:
            print self.__class__, 'ID'
            try:
                return base.get(id=id)
            except ObjectDoesNotExist:
                return rc.NOT_FOUND
            except MultipleObjectsReturned: # Should never happen, since we're using a primary key.
                return rc.BAD_REQUEST
        else:
            if name:
                print self.__class__, 'Name'
                return base.filter(unique_name = name).all()
            else:
                print self.__class__, 'NO ID'
                return base.all()

如你所见,大部分处理器的代码都是在搞清楚 urlpatterns 中传递了哪些参数。

一些示例 URL 是 api/groups/api/group/3301/api/group/st1gp01/ - 这些都会输出 JSON

15

这件事可能很简单。

URL映射很容易构建,比如:

urlpatterns = patterns('books.views',
  (r'^books/$', 'index'),
  (r'^books/(\d+)/$', 'get'))

Django支持模型序列化,所以把模型转换成XML也很简单:

from django.core import serializers
from models import Book

data = serializers.serialize("xml", Book.objects.all())

把这两者结合起来,再加上装饰器,你就可以快速构建处理程序:

from django.http import HttpResponse
from django.shortcuts import get_object_or_404

def xml_view(func):
  def wrapper(*args, **kwargs):
    result = func(*args, **kwargs)
    return HttpResponse(serializers.serialize("xml", result),
        mimetype="text/xml")
  return wrapper

@xml_view
def index(request):
  return Books.objects.all()

@xml_view
def get(request, id):
  return get_object_or_404(Book, pk=id)

撰写回答