【问题标题】:Correct set for the nested resources in TastypieTastypie 中嵌套资源的正确设置
【发布时间】:2015-01-15 18:04:23
【问题描述】:

我正在使用 Tastypie 以及以下资源和 Django 教程的相同模型。

from django.conf.urls import url
from django.views.decorators.csrf import csrf_exempt

from tastypie import fields
from tastypie.constants import ALL, ALL_WITH_RELATIONS
from tastypie.resources import ModelResource
from tastypie.utils import trailing_slash

from .models import Question, Choice


class ChoiceResource(ModelResource):
    class Meta:
        queryset = Choice.objects.all()
        resource_name = 'choice'

    def prepend_urls(self):
        return [
            url(r"^(?P<resource_name>%s)\.(?P<format>\w+)$" % self._meta.resource_name, self.wrap_view('dispatch_list'), name="api_dispatch_list"),
            url(r"^(?P<resource_name>%s)/schema\.(?P<format>\w+)$" % self._meta.resource_name, self.wrap_view('get_schema'), name="api_get_schema"),
            url(r"^(?P<resource_name>%s)/set/(?P<pk_list>\w[\w/;-]*)\.(?P<format>\w+)$" % self._meta.resource_name, self.wrap_view('get_multiple'), name="api_get_multiple"),
            url(r"^(?P<resource_name>%s)/(?P<pk>\w[\w/-]*)\.(?P<format>\w+)$" % self._meta.resource_name, self.wrap_view('dispatch_detail'), name="api_dispatch_detail"),
        ]

    def determine_format(self, request):
        """
        Used to determine the desired format from the request.format
        attribute.
        """
        if (hasattr(request, 'format') and
                request.format in self._meta.serializer.formats):
            return self._meta.serializer.get_mime_for_format(request.format)
        return super(ChoiceResource, self).determine_format(request)

    def wrap_view(self, view):
        @csrf_exempt
        def wrapper(request, *args, **kwargs):
            request.format = kwargs.pop('format', None)
            wrapped_view = super(ChoiceResource, self).wrap_view(view)
            return wrapped_view(request, *args, **kwargs)
        return wrapper


class QuestionResource(ModelResource):
    class Meta:
        queryset = Question.objects.all()
        resource_name = 'question'

    choices = fields.ToManyField(ChoiceResource, 'choices')

    def prepend_urls(self):
        return [
            url(r"^(?P<resource_name>%s)/(?P<pk>\w[\w/-]*)/choices\.(?P<format>\w+)$" % self._meta.resource_name, self.wrap_view('get_choices'), name="api_get_choices"),
            url(r"^(?P<resource_name>%s)\.(?P<format>\w+)$" % self._meta.resource_name, self.wrap_view('dispatch_list'), name="api_dispatch_list"),
            url(r"^(?P<resource_name>%s)/schema\.(?P<format>\w+)$" % self._meta.resource_name, self.wrap_view('get_schema'), name="api_get_schema"),
            url(r"^(?P<resource_name>%s)/set/(?P<pk_list>\w[\w/;-]*)\.(?P<format>\w+)$" % self._meta.resource_name, self.wrap_view('get_multiple'), name="api_get_multiple"),
            url(r"^(?P<resource_name>%s)/(?P<pk>\w[\w/-]*)\.(?P<format>\w+)$" % self._meta.resource_name, self.wrap_view('dispatch_detail'), name="api_dispatch_detail"),
        ]

    def determine_format(self, request):
        if (hasattr(request, 'format') and
                request.format in self._meta.serializer.formats):
            return self._meta.serializer.get_mime_for_format(request.format)
        return super(QuestionResource, self).determine_format(request)

    def wrap_view(self, view):
        @csrf_exempt
        def wrapper(request, *args, **kwargs):
            request.format = kwargs.pop('format', None)
            wrapped_view = super(QuestionResource, self).wrap_view(view)
            return wrapped_view(request, *args, **kwargs)
        return wrapper

    def get_choices(self, request, **kwargs):
        try:
            bundle = self.build_bundle(data={'pk': kwargs['pk']}, request=request)
            obj = self.cached_obj_get(bundle=bundle, **self.remove_api_resource_names(kwargs))
        except ObjectDoesNotExist:
            return HttpGone()
        except MultipleObjectsReturned:
            return HttpMultipleChoices("More than one resource is found at this URI.")

        choice_resource = ChoiceResource()
        return choice_resource.get_list(request, question_id=obj.pk)

当我请求 /api/v1/question.json 时,我得到了所有预期的问题,/api/v1/question/1.json 也是一样,但是当我请求 /api/v1/question/1/choices.json 时,我得到了所有的选择,而不仅仅是问题 1 中的那些。

我做错了什么?

【问题讨论】:

    标签: django tastypie nested-resources


    【解决方案1】:

    您正在调用 get_list 来过滤一次事件而不是 get_detail 另外,get_detail不要通过 `question_id´ 过滤 pk,请参见此处:https://github.com/toastdriven/django-tastypie/blob/master/tastypie/resources.py#L1303

    虽然,你为什么不使用美味派的实际网址呢? 根据食谱 (http://django-tastypie.readthedocs.org/en/latest/cookbook.html),您可以像这样创建资源:

    class QuestionResource(ModelResource):
        class Meta:
            queryset = Question.objects.all()
            resource_name = 'question'
            serializer = Serializer(formats=['json', 'xml', 'html'])
    

    然后,你可以调用/api/v1/question/1/?format=xml,这是更RESTful的方式。

    【讨论】:

    • 我想使用嵌套版本(用于学习目的),因为它将在未来的项目中更有用。另外,get_detail 不能作为一个 Question 可以有多个 Choice,就像 python 教程一样。另外,对于我在教程中使用的.format 格式。
    最近更新 更多