简体   繁体   English

从Tastypie 0.9.11升级到0.11 obj_get_list

[英]Upgrading from Tastypie 0.9.11 to 0.11 obj_get_list

Code that worked in api.py With Python 2.6, Django 1.4.1, Tastypie 0.9.11 (Running on 2.6.32-48-generic-pae #110-Ubuntu SMP) 在api.py中使用Python 2.6,Django 1.4.1,Tastypie 0.9.11的代码(在2.6.32-48-generic-pae#110-Ubuntu SMP上运行)

class DriveResource(CommonModelResource):
    driver = fields.ForeignKey(DriverResource, 'driver')
    bus = fields.ForeignKey(BusResource, 'bus')
    route = fields.ForeignKey(RouteResource, 'route')

    class Meta(CommonModelResource.Meta):
        queryset = Drive.objects.all()
        allowed_methods = ['get', 'put']
        excludes = ('bus_location',)
        filtering = {
            'updated': ('gt', 'gte', 'lt', 'lte', 'exact'),
            'id': ('exact',),
        }

    def get_object_list(self, request):
        whole_list = super(DriveResource, self).get_object_list(request)
        todays_day_name = datetime.now().strftime('%w')
        filtered_list = whole_list.filter(driver__user=request.user).filter(day=todays_day_name)
        return filtered_list

    def dehydrate_driver(self, bundle):
        return bundle.obj.driver.person_id

    def dehydrate_bus(self, bundle):
        return bundle.obj.bus.number

    def dehydrate_route(self, bundle):
        return bundle.obj.route.id

    def hydrate_bus_location(self, bundle):
        # Guard against the method being called twice
        if not hasattr(bundle, 'geopoint_processed'):
            lon = bundle.data['bus_location'][0] / 1e6
            lat = bundle.data['bus_location'][1] / 1e6
            bundle.data['bus_location'] = Point(lon, lat)
            bundle.geopoint_processed = True
        return bundle


class DriveFullResource(CommonModelResource):
    driver = fields.ForeignKey(DriverResource, 'driver', full=True, blank=True, null=True)
    bus = fields.ForeignKey(BusResource, 'bus', full=True, blank=True, null=True)
    route = fields.ForeignKey(RouteResource, 'route', full=True)

    class Meta(CommonModelResource.Meta):
        queryset = Drive.objects.all()
        resource_name = 'drive'
        allowed_methods = ['get', 'put']
        excludes = ('bus_location',)

    def obj_get_list(self, request=None, **kwargs):
        whole_list = super(DriveFullResource, self).obj_get_list(request, **kwargs)
        todays_day_name = datetime.now().strftime('%w')
        filtered_list = whole_list.filter(driver__user=request.user).filter(day=todays_day_name)
        return filtered_list

    def hydrate_bus_location(self, bundle):
        # Guard against the method being called twice
        if not hasattr(bundle, 'geopoint_processed'):
            lon = bundle.data['bus_location'][0] / 1e6
            lat = bundle.data['bus_location'][1] / 1e6
            bundle.data['bus_location'] = Point(lon, lat)
            bundle.geopoint_processed = True
        return bundle

    def put_detail(self, request, **kwargs):
        deserialized = self.deserialize(request, request.raw_post_data, format=request.META.get('CONTENT_TYPE', 'application/json'))
        deserialized = self.alter_deserialized_detail_data(request, deserialized)
        bundle = self.build_bundle(data=dict_strip_unicode_keys(deserialized), request=request)

        try:
            drive = Drive.objects.get(pk=kwargs['pk'])
            bundle = self.hydrate_bus_location(bundle)
            drive.bus_location = bundle.data['bus_location']
            drive.save()
            return http.HttpNoContent()
        except:
            return http.HttpBadRequest()

Does not work with Python 2.6, Django 1.5, Tastypie 0.11 (Running on Centos 5) 不适用于Python 2.6,Django 1.5,Tastypie 0.11(在Centos 5上运行)

Calling server with : https://api.server.com/api/full/drive/?format=json&limit=50&user=12345 呼叫伺服器: https : //api.server.com/api/full/drive/?format=json&limit=50&user=12345

I tried changing to: 我尝试更改为:

def obj_get_list(self, bundle, **kwargs):
    request = bundle.request
    whole_list = super(DriveFullResource, self).get_object_list(request)
    todays_day_name = datetime.now().strftime('%w')
    filtered_list = whole_list.filter(driver__user=request.user).filter(day=todays_day_name)
    return filtered_list

and

def obj_get_list(self, bundle, **kwargs):
    request = bundle.request
    whole_list = super(DriveFullResource, self).obj_get_list(bundle, **kwargs)
    todays_day_name = datetime.now().strftime('%w')
    filtered_list = whole_list.filter(driver__user=request.user).filter(day=todays_day_name)
    return filtered_list

Still get error messages of the type below: 仍然会收到以下类型的错误消息:

{"error_message": "obj_get_list() got multiple values for keyword
argument 'bundle'", "traceback": "Traceback (most recent call
last):\n\n  File
\"/usr/lib/python2.6/site-packages/tastypie/resources.py\", line 195,
in wrapper\n\n  File
\"/usr/lib/python2.6/site-packages/tastypie/resources.py\", line 426,
in dispatch_list\n\n  File
\"/usr/lib/python2.6/site-packages/tastypie/resources.py\", line 458,
in dispatch\n\n  File
\"/usr/lib/python2.6/site-packages/tastypie/resources.py\", line 1266,
in get_list\n\n  File
\"/home/django_projects/project/src/routes/api.py\", line 110, in
obj_get_list\n    request = bundle.request\n\nTypeError:
obj_get_list() got multiple values for keyword argument 'bundle'\n"}

{"error_message": "obj_get_list() got multiple values for keyword
argument 'bundle'", "traceback": "Traceback (most recent call
last):\n\n  File
\"/usr/lib/python2.6/site-packages/tastypie/resources.py\", line 195,
in wrapper\n\n  File
\"/usr/lib/python2.6/site-packages/tastypie/resources.py\", line 426,
in dispatch_list\n\n  File
\"/usr/lib/python2.6/site-packages/tastypie/resources.py\", line 458,
in dispatch\n\n  File
\"/usr/lib/python2.6/site-packages/tastypie/resources.py\", line 1266,
in get_list\n\n  File
\"/home/django_projects/project/src/routes/api.py\", line 114, in
obj_get_list\n    return filtered_list\n\nTypeError: obj_get_list()
got multiple values for keyword argument 'bundle'\n"}

I tested the method on Tastypie 0.11 and seems to work ok. 我在Tastypie 0.11上测试了该方法,并且工作正常。 But in my opinion you are taking wrong and error prone approach. 但是我认为您正在采用容易出错和容易出错的方法。 I prepared solution that will eliminate them. 我准备了可以消除它们的解决方案。

Problem definition 问题定义
You didn't defined what is your code supposed to do. 您没有定义代码应该做什么。 Reviewing code I assume you want to have resource that returns object for currently logged user and filtered by day name. 查看代码,我假设您想拥有返回当前登录用户的对象并按日期名称过滤的资源。 In other words you want to limit access to resource - And this is.. I think you know, authorization. 换句话说,您想限制对资源的访问-这是..我想您知道,授权。

Why not obj_get_list? 为什么不使用obj_get_list?
You see that Tastypie obj_get_list is quite Django ORM specific and not documented well. 您将看到Tastypie obj_get_list相当Django的ORM具体的,而不是记录良好。 I don't really know how to use it. 我真的不知道如何使用它。 I wouldn't dare to deal with it. 我不敢处理。

Solution
Let's define Authorization class for your resource: 让我们为您的资源定义Authorization类:

from datetime import datetime

from tastypie.authorization import Authorization


class DriverAuthorization(Authorization):
    def read_list(self, object_list, bundle):
        todays_day_name = datetime.now().strftime('%w')
        return object_list.filter(driver__user=bundle.request.user,
                                  day=todays_day_name)

    def read_detail(self, object_list, bundle):
        todays_day_name = datetime.now().strftime('%w')
        return bundle.obj.day == todays_day_name and bundle.obj.driver.user == bundle.request.user

    def create_list(self, object_list, bundle):
        return []

    def create_detail(self, object_list, bundle):
        return False

    def update_list(self, object_list, bundle):
        return []

    def update_detail(self, object_list, bundle):
        object_before_update = object_list.get(pk=bundle.obj.pk)
        return object_before_update.driver.user == bundle.request.user

    def delete_list(self, object_list, bundle):
        return []

    def delete_detail(self, object_list, bundle):
        return False

Now attach authorization to resource: 现在将授权附加​​到资源:

class DriveResource(CommonModelResource):
    driver = fields.ForeignKey(DriverResource, 'driver')
    bus = fields.ForeignKey(BusResource, 'bus')
    route = fields.ForeignKey(RouteResource, 'route')

    class Meta(CommonModelResource.Meta):
        queryset = Drive.objects.all()
        allowed_methods = ['get', 'put']
        excludes = ('bus_location',)
        authorization = DriverAuthorization()
        filtering = {
            'updated': ('gt', 'gte', 'lt', 'lte', 'exact'),
            'id': ('exact',),
        }

    def dehydrate_driver(self, bundle):
        return bundle.obj.driver.person_id

    def dehydrate_bus(self, bundle):
        return bundle.obj.bus.number

    def dehydrate_route(self, bundle):
        return bundle.obj.route.id

    def hydrate_bus_location(self, bundle):
        # Guard against the method being called twice
        if not hasattr(bundle, 'geopoint_processed'):
            lon = bundle.data['bus_location'][0] / 1e6
            lat = bundle.data['bus_location'][1] / 1e6
            bundle.data['bus_location'] = Point(lon, lat)
            bundle.geopoint_processed = True
        return bundle

Benefits 优点
1. Code now is much more clearer to read 1.现在,代码更加清晰易读
2. You have control on what user can do or cannot do in one place. 2.您可以控制用户在一处可以做什么或不能做什么。
3. No obj_get_list means no more problems. 3.没有obj_get_list意味着没有更多问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM