我有模型:课程和带有中间连接模型coursetag的标签(用于多对多关系)。
在我的API中,TagResource显示标签以及课程数量。然后,当用户(通过API)请求特定标签时,他们会获得具有指定标签的所有课程的列表。所有这一切都很好......但是,我现在需要能够根据用户过滤课程(无论他们是否将user.is_staff设置为True)。
我可以让这个工作在标签列表API中显示正确的课程数量,但是我在选择特定标签时如何过滤课程时遇到了问题。
我的API资源如下:
class TagResource(ModelResource):
count = fields.IntegerField(readonly=True)
courses = fields.ToManyField('oppia.api.resources.CourseTagResource', 'coursetag_set', related_name='tag', full=True)
class Meta:
queryset = Tag.objects.filter(courses__isnull=False).distinct().order_by("name")
resource_name = 'tag'
allowed_methods = ['get']
fields = ['id','name']
authentication = ApiKeyAuthentication()
authorization = ReadOnlyAuthorization()
always_return_data = True
include_resource_uri = False
serializer = TagJSONSerializer()
def dehydrate_count(self,bundle):
if bundle.request.user.is_staff:
count = Course.objects.filter(tag__id=bundle.obj.id).count()
else:
count = Course.objects.filter(tag__id=bundle.obj.id, staff_only=False).count()
return count
class CourseResource(ModelResource):
class Meta:
queryset = Course.objects.all()
resource_name = 'course'
allowed_methods = ['get']
fields = ['id', 'title', 'version', 'shortname']
authentication = ApiKeyAuthentication()
authorization = ReadOnlyAuthorization()
serializer = CourseJSONSerializer()
always_return_data = True
include_resource_uri = True
class CourseTagResource(ModelResource):
course = fields.ToOneField('oppia.api.resources.CourseResource', 'course', full=True)
class Meta:
queryset = CourseTag.objects.all()
allowed_methods = ['get']
fields = ['id','course','tag']
include_resource_uri = False
authentication = ApiKeyAuthentication()
authorization = ReadOnlyAuthorization()
always_return_data = True
样本请求/响应如下:
对于标签列表(例如http://localhost/python/api/v1/tag/?username=XXXetc
),我得到了预期的响应:
{"meta": {"limit": 20, "next": null, "offset": 0, "previous": null, "total_count": 10}, "tags": [{"count": 1, "id": 8, "name": "34343434"}, {"count": 2, "id": 2, "name": "Education"}, {"count": 1, "id": 7, "name": "Engineering"}, {"count": 1, "id": 13, "name": "Ethiopia"}, {"count": 1, "id": 10, "name": "health"}, {"count": 5, "id": 1, "name": "Healthcare"}, {"count": 1, "id": 11, "name": "phone"}, {"count": 1, "id": 12, "name": "PNC"}, {"count": 1, "id": 6, "name": "Solar"}, {"count": 1, "id": 9, "name": "test"}]}
但是对于特定标签(例如http://localhost/python/api/v1/tag/13/?username=XXXetc
),我得到正确的计数(1门课程),但错误的课程列表(2门课程):
{"count": 1, "courses": [{"id": 2, "resource_uri": "/python/api/v1/course/2/", "shortname": "pnc", "title": {"en": "Postnatal Care"}, "url": "http://localhost/python/api/v1/course/2/download/", "version": "20131105085218"}, {"id": 30, "resource_uri": "/python/api/v1/course/30/", "shortname": "anc2", "title": {"en": "Antenatal Care v2"}, "url": "http://localhost/python/api/v1/course/30/download/", "version": "20131106162547"}], "id": 13, "name": "Ethiopia"}
我试图使用与此处给出的方法类似的方法:How to filter ToManyField of django-tastypie by request.user?但我无法弄清楚如何应用lambda函数,具体取决于user.is_staff。
我还试图在CourseResource和CourseTagResource上设置授权限制,但这似乎没有任何区别。
有关信息,我使用的是tastypie 0.9.16和Django 1.5。
任何帮助/指针都非常感激,关于我是否采取正确方法的任何建议都会有所帮助 - 我不确定我是否应该查看课程模型权限呢?
由于
答案 0 :(得分:0)
我终于想出了一种方法来实现我想要的......它不漂亮,肯定不会推荐这种方法,但它对我有用。
我最终删除了TagResource中的ToManyField,然后使用以下命令覆盖API详细信息URI:
def prepend_urls(self):
return [
url(r"^(?P<resource_name>%s)/(?P<pk>\w[\w/-]*)%s$" % (self._meta.resource_name, trailing_slash()), self.wrap_view('tag_detail'), name="api_tag_detail"),
]
def tag_detail(self, request, **kwargs):
self.is_authenticated(request)
self.throttle_check(request)
pk = kwargs.pop('pk', None)
try:
tag = self._meta.queryset.get(pk = pk)
except Tag.DoesNotExist:
raise NotFound(_(u'Tag not found'))
if request.user.is_staff:
courses = Course.objects.filter(tag=tag, is_archived=False).order_by("title")
else:
courses = Course.objects.filter(tag=tag, is_archived=False,is_draft=False).order_by("title")
course_data = []
cr = CourseResource()
for c in courses:
bundle = cr.build_bundle(obj=c,request=request)
d = cr.full_dehydrate(bundle)
course_data.append(bundle.data)
response = HttpResponse(content=json.dumps({'id':pk,'count':courses.count(),'courses':course_data,'name':tag.name}),content_type="application/json; charset=utf-8")
return response
如果有人有更好的方法,那么我很乐意听到......