【问题标题】:Exposing "virtual" field in a tastypie view?在美味的视图中暴露“虚拟”字段?
【发布时间】:2011-09-13 03:36:44
【问题描述】:

我想使用tastepie创建一个视图来暴露某些相同类型的对象,但是有以下两个三个曲折:

  1. 我需要使用三个单独的查询来获取对象;
  2. 我需要添加一个在底层模型中不存在的字段,该字段的值取决于它来自哪个查询;和
  3. 数据将针对每个用户(因此我需要连接到获取请求的方法之一)。

我不清楚如何连接到 sweetpie 生命周期来实现这一点。添加“虚拟”字段的推荐方法是使用脱水方法,它只知道它正在运行的捆绑包。

更糟糕的是,没有正式的方式来加入查询集。

如果我能让tastepie 接受查询集以外的东西,我的问题就会消失。在这种情况下,我可以将我的对象的子类列表传递给它,并添加额外的字段。

我愿意接受任何其他明智的解决方案。

编辑:添加扭曲 3 - 每个用户的数据。

【问题讨论】:

    标签: ajax django tastypie


    【解决方案1】:

    在上一个版本中,您应该覆盖脱水方法,例如

    def dehydrate(self, bundle):
        bundle.data['full_name'] = bundle.obj.get_full_name()
        return bundle
    

    【讨论】:

    • 实际的问题是在dehydrate()中访问request并不总是可行的。请求应该存储在bundle.request,但它实际上之前没有,现在修复了吗?
    • 使用 bundle.request 从今天开始在开发版本上工作
    【解决方案2】:

    在这里偶然发现了类似的问题。就我而言,列表中的项目可以由用户“检查”。

    • 当一个项目被 AJAX 检索到时,它的检查状态与资源一起作为普通字段返回。
    • 将项目保存到服务器后,资源中的“已选中”字段将存储在用户会话中。

    首先我认为hydrate()dehydrate() 方法最适合这项工作,但结果发现在这些方法中访问request 对象存在问题。所以我选择了alter_data_to_serialize()obj_update()。我认为没有必要覆盖obj_create(),因为我认为第一次创建项目时无法检查它。

    这是代码,但请注意它尚未经过适当测试。

    class ItemResource(ModelResource):
        def get_object_checked_status(self, obj, request):
            if hasattr(request, 'session'):
                session = request.session
                session_data = session.get(get_item_session_key(obj), dict())
                return session_data.get('checked', False)
            return False
    
        def save_object_checked_status(self, obj, data, request):
            if hasattr(request, 'session'):
                session_key = get_item_session_key(obj)
                session_data = request.session.get(session_key, dict())
                session_data['checked'] = data.pop('checked', False)
                request.session[session_key] = session_data
    
        # Overridden methods
        def alter_detail_data_to_serialize(self, request, bundle):
            # object > resource
            bundle.data['checked'] = \
                self.get_object_checked_status(bundle.obj, request)
            return bundle
    
        def alter_list_data_to_serialize(self, request, to_be_serialized):
            # objects > resource
            for bundle in to_be_serialized['objects']:
                bundle.data['checked'] = \
                    self.get_object_checked_status(bundle.obj, request)
            return to_be_serialized
    
        def obj_update(self, bundle, request=None, **kwargs):
            # resource > object
            save_object_checked_status(bundle.obj, bundle.data, request)
            return super(ItemResource, self)\
                .obj_update(bundle, request, **kwargs)
    
    def get_item_session_key(obj): return 'item-%s' % obj.id
    

    【讨论】:

      【解决方案3】:

      好的,这就是我的解决方案。代码如下。

      注意事项:

      1. 工作基本上都是在obj_get_list完成的。这就是我运行查询的地方,可以访问请求。
      2. 我可以从obj_get_list返回一个列表。
      3. 如果我希望它们可用,我可能必须覆盖与其他操作相对应的所有其他 obj_* 方法(如 obj_getobj_create 等)。
      4. 因为我在Meta 中没有queryset,所以我需要提供一个object_class 来告诉tastepie 的内省提供哪些字段。
      5. 要公开我的“虚拟”属性(我在obj_get_list 中创建),我需要为其添加一个字段声明。
      6. 我已经注释掉了过滤器和授权限制,因为我现在不需要它们。如果需要,我需要自己实现它们。

      代码:

      from tastypie.resources import ModelResource
      from tastypie import fields
      from models import *
      import logging
      
      logger = logging.getLogger(__name__)
      
      
      class CompanyResource(ModelResource):
          role = fields.CharField(attribute='role')
      
      
          class Meta:
              allowed_methods = ['get']
              resource_name = 'companies'
              object_class = CompanyUK
              # should probably have some sort of authentication here quite soon
      
      
          #filters does nothing. If it matters, hook them up
          def obj_get_list(self, request=None, **kwargs):
      #         filters = {}
      
      #         if hasattr(request, 'GET'):
      #             # Grab a mutable copy.
      #             filters = request.GET.copy()
      
      #         # Update with the provided kwargs.
      #         filters.update(kwargs)
      #         applicable_filters = self.build_filters(filters=filters)
      
              try:
                  #base_object_list = self.get_object_list(request).filter(**applicable_filters)
                  def add_role(role):
                      def add_role_company(link):
                          company = link.company
                          company.role = role
                          return company
                      return add_role_company
      
                  director_of = map(add_role('director'), DirectorsIndividual.objects.filter(individual__user=request.user))
                  member_of   = map(add_role('member'),   MembersIndividual.objects.filter(individual__user=request.user))
                  manager_of  = map(add_role('manager'),  CompanyManager.objects.filter(user=request.user))
      
                  base_object_list = director_of + member_of + manager_of
                  return base_object_list #self.apply_authorization_limits(request, base_object_list)
              except ValueError, e:
                  raise BadRequest("Invalid resource lookup data provided (mismatched type).")
      

      【讨论】:

      • 在这里偶然发现了类似的问题。只是要注意,您还可以覆盖 alter_detail_data_to_serialize()alter_list_data_to_serialize() 以添加“虚拟”字段。
      【解决方案4】:

      你可以这样做(未测试):

      def alter_list_data_to_serialize(self, request, data):
      
          for index, row in enumerate(data['objects']):
      
              foo = Foo.objects.filter(baz=row.data['foo']).values()
              bar = Bar.objects.all().values()
      
              data['objects'][index].data['virtual_field'] = bar
      
          return data
      

      【讨论】:

        猜你喜欢
        • 2020-05-18
        • 2020-07-21
        • 2011-03-26
        • 1970-01-01
        • 1970-01-01
        • 2014-01-12
        • 2011-04-02
        • 2020-11-09
        • 1970-01-01
        相关资源
        最近更新 更多