Django-tastypie: SHOW 和 INDEX 操作的不同字段

创建于 2010-10-25  ·  40评论  ·  资料来源: django-tastypie/django-tastypie

大家好,是否可以根据操作显示不同的资源字段。

我想要它的原因是为了避免资源包含的所有 has_many 字段的索引操作负担。

例如,在作者索引视图中,我只想返回他的名字,但对于显示操作,我想包括所有书籍资源。

谢谢,
博扬

documentation feature

最有用的评论

我正在使用的一个简单解决方法是覆盖get_detailget_list方法来编辑这些字段。
这节省了实际获取字段数据然后从包中删除它的开销,但我不确定这个方法是否是线程安全的,因为看起来资源对象不是在每次 api 调用时创建的。
如果有人可以对此发表评论,那就太好了。

这是代码:

class ArticleResource(BaseModelResource):
    owner = fields.ToOneField(UserResource, 'owner', full=True)

    class Meta:
        resource_name = "articles"

    def get_list(self, request, **kwargs):
        self.fields.pop("comments", None)
        return super(ArticleResource, self).get_list(request, **kwargs)

    def get_detail(self, request, **kwargs):
        self.fields["comments"] = fields.ToManyField(CommentResource, 'comments', full=True)
        return super(ArticleResource, self).get_detail(request, **kwargs)

所有40条评论

+1
非常希望有这个功能:“明细栏”和“列表栏”可以分开

+1(通过#44 重复)

在我看来,有两件事可以更轻松地在索引操作中获取数据子集:

  1. 使 full_dehydrate 为 index 和 get 方法使用不同的字段。 也许是这样的:

元:
index_exclude_fields = ['some_m2m_field']

这将允许我们保存一些数据库查询。

  1. 传递额外的“方法”参数来脱水。 这将允许自定义包,例如跳过索引中不需要的一些字段,我们希望节省一些带宽。

我没有评估 1. 会影响缓存。
你怎么认为?

同样在#48 中被欺骗,但每个问题都有值得关注的方面。

如果可以的话,我想推出这个功能,但我已经被淘汰了。 无论如何,它需要在那里以获得更好的文件支持,所以它必须得到解决。 将以此为目标 1.0。

在进一步检查我的用例之后,我建议将其实现为比仅显示/列表视图更灵活的东西。 我真正需要做的是采用这样的查询字符串标志:

&shape=[完整|简单|无]

并让输出反映用户选择的详细程度。 我寻找了一种方法来解决这个问题,但是由于在创建 ModelResource 类时包含/排除了字段,我无法想出任何方法来更改响应周期后期可用的内容。 此外,请求对象在我想要做出此类决定的过程中的步骤中不可用。

+1

我会首先在这里提到这个想法,因为它似乎与这个问题有关,但它可能需要独立出来。

如果开发了一种显示不同字段的机制,如果它也可以与身份验证集成在一起,那将会很有用。 能够公开更多/更少的字段取决于用户的权限将是非常强大的。 如果这已经可能,我还没有找到任何提及。

+1

+1

+1

+1

+1

+1

+1

除了列表/详细信息之外,我希望能够控制每个方法(POST、PUT、GET)上显示的字段(使用字段或排除)。

这是一种解决方法,请参见下面的示例:您不会从原始模型的资源模型(示例中的 UserResource)中排除任何内容,因此它在索引视图中会是完整的。 您必须进入包含您的子模型(BlogPostResource 中包含作者)的模型资源的脱水方法,然后删除包的元素。

例子:

class BlogPostResource(ModelResource):
     author = fields.ForeignKey(UserResource, 'author', full=True)
     ....
     class Meta:
         ...

def dehydrate(self, bundle):
         del bundle.data['author'].data['field_you_dont_wanna_show_here']
         del bundle.data['author'].data['field_you_dont_wanna_show_here']
         return bundle

因此,当您想列出用户时,您仍然可以获得所有字段,但是当您列出博客文章时,您可以例如只获取作者的名字和姓氏。

你怎么认为?

一个非常非常脏的解决方法的示例:不在 list_view 中显示项目字段,但在 detail_view 中显示,而无需访问资源本身,无需硬编码即可获取 url 本身应该是可行的,但还没有时间查看:

class CompanyResource(ModelResource):
       """
       Tastypie resource for Company
      """
       projects = fields.ToManyField('api.resources.ProjectResource',
                                  'projects',full=True)
       class Meta:
           queryset = Company.objects.all()
           resource_name = 'companies'

       def dehydrate(self, bundle):
           if bundle.request.path == "/api/v1/companies/":
               del bundle.data['projects']
           return bundle

+1

+1

+1

我也会跳上火车,坐火车会很好,但@ashwoods指出的内容足以让我

    def dehydrate(self, bundle):
        if self.get_resource_uri(bundle) == bundle.request.path:
            print "Detail"

        if self.get_resource_uri(bundle) != bundle.request.path:
            print "Not Detail - Could be list or reverse relationship."

        return bundle

所以我对此进行了更多思考,并提出了一些非常接近于让我做我认为@bmihelac正在寻找的事情。

使用@ashwoods提供的示例,假设我们只想显示项目字段,如果它是详细响应:

class CompanyResource(ModelResource):
    """
    Tastypie resource for Company
    """

    class Meta:
        queryset = Company.objects.all()
        resource_name = 'companies'
        additional_detail_fields = {'projects': fields.ToManyField('api.resources.ProjectResource', 'projects',full=True)}

    def dehydrate(self, bundle):
        # detect if detail
        if self.get_resource_uri(bundle) == bundle.request.path:
            # detail detected, include additional fields
            bundle = self.detail_dehydrate(bundle)

        return bundle

    # detail_dehydrate is basically full_dehydrate
    # except we'll loop over the additional_detail_fields
    # and we won't want to do the dehydrate(bundle) at the end
    def detail_dehydrate(self, bundle):
        """
        Given a bundle with an object instance, extract the information from it
        to populate the resource.
        """
        # Dehydrate each field.
        # loop over additional_detail_fields instead
        #for field_name, field_object in self.fields.items():
        for field_name, field_object in self._meta.additional_detail_fields.items():
            # A touch leaky but it makes URI resolution work.
            if getattr(field_object, 'dehydrated_type', None) == 'related':
                field_object.api_name = self._meta.api_name
                field_object.resource_name = self._meta.resource_name

            bundle.data[field_name] = field_object.dehydrate(bundle)

            # Check for an optional method to do further dehydration.
            method = getattr(self, "dehydrate_%s" % field_name, None)

            if method:
                bundle.data[field_name] = method(bundle)

        # dehydrating the bundle will create an infinite loop
        #bundle = self.dehydrate(bundle)
        return bundle

+1,暂时使用

+1

+1

#526 中的部分实现,不确定我是否已全部出售并且缺少测试/文档。

刚看到这张票......也喜欢上面onyxfish提到的“形状”方法......

想我在#526 中的解决方案有点有限,以防人们在其他情况下想要不同的“形状”......

脱水后删除字段的建议......我的全部原因是首先避免计算值。

但是,我喜欢 detail_dehydrate 钩子允许有条件地添加更多细节的想法。

看起来有两种可能的实现,包括测试和文档。 我在 #569 和 #538 中写了一个也执行类似的功能(#538 允许更多的灵活性,因为use_in可能是可调用的)。 我的实现添加了meta属性来控制此功能(与当前的fields属性一致),而 #538 向字段添加了一个属性。 两者似乎都有效,只是关于走哪条路的设计决定。 添加到元对我来说似乎是一致的,并且更容易使用,因为某些字段可以自动生成并且可能无法修改它们的初始化参数。 另一种选择是结合两个拉取请求并允许根据meta属性自动设置use_in参数,但是这似乎给 API 增加了不必要的复杂性。 感谢@issackelly向我指出相关的拉取请求。

[因为我是#538 背后的原始原因,这是对我的#526 的清理]
很有意义...... Meta 方法确实会与 ModelResource 的排除列表结合,等等......

正如我在另一张票中所说的那样,恕我直言,这样的“简单”解决方案足以满足 1.0 版本的需求……而更复杂的解决方案,例如“客户端可选择的‘形状’”可能是以后版本所需要的。 .

@funkybob同意,当然更复杂的解决方案对客户端会有所帮助,但是尽快包含此功能会很好,以便可以在 1.0 发布之前开始使用。

实际上在生产应用中使用 PR,我非常喜欢#538 提供的回调的灵活性。 我有几个用例,我必须在运行时根据权限隐藏资源。

这对我来说是不可能的 #569

你好,有消息吗? 那个公关让生活变得更轻松,谢谢!

使用@dericcrago 提供的 hack

+1

我正在使用的一个简单解决方法是覆盖get_detailget_list方法来编辑这些字段。
这节省了实际获取字段数据然后从包中删除它的开销,但我不确定这个方法是否是线程安全的,因为看起来资源对象不是在每次 api 调用时创建的。
如果有人可以对此发表评论,那就太好了。

这是代码:

class ArticleResource(BaseModelResource):
    owner = fields.ToOneField(UserResource, 'owner', full=True)

    class Meta:
        resource_name = "articles"

    def get_list(self, request, **kwargs):
        self.fields.pop("comments", None)
        return super(ArticleResource, self).get_list(request, **kwargs)

    def get_detail(self, request, **kwargs):
        self.fields["comments"] = fields.ToManyField(CommentResource, 'comments', full=True)
        return super(ArticleResource, self).get_detail(request, **kwargs)

+1

另一种解决方法是为详细信息和列表视图使用不同的资源:

from tastypie.resources import ModelResource
from django.contrib.auth.models import User

# detail will show everything except password
class UserResourceDetail(ModelResource):
    class Meta:
        queryset = User.objects.all()
    excludes = ('password',)
    resource_name = 'user'

# list will only show username & date_joined (and exclude password)
class UserResource(UserResourceDetail):
    class Meta(UserResourceDetail.Meta):
        fields = ('username', 'date_joined')
    get_detail = UserResourceDetail().get_detail

# ... register & use UserResource

+1

+1 @dnozay解决方法

+1 @dnozay ,真棒

请注意,如果您希望get_resource_uri与用户详细信息视图一起正常工作,则需要在定义UserResource后添加以下内容。

UserResourceDetail.get_resource_uri = UserResource().get_resource_uri

否则,所有详细响应中的resource_uri将为空。

可能相关:#1265

此页面是否有帮助?
0 / 5 - 0 等级