All*_*rbo 37 python django django-rest-framework
使用Django REST Framework,我想限制哪些值可以在创建中的相关字段中使用.
例如,考虑此示例(基于http://django-rest-framework.org/api-guide/filtering.html上的过滤示例,但更改为ListCreateAPIView):
class PurchaseList(generics.ListCreateAPIView)
model = Purchase
serializer_class = PurchaseSerializer
def get_queryset(self):
user = self.request.user
return Purchase.objects.filter(purchaser=user)
Run Code Online (Sandbox Code Playgroud)
在此示例中,如何确保在创建时,购买者可能只等于self.request.user,并且这是可浏览API渲染器中表单下拉列表中填充的唯一值?
All*_*rbo 37
我最终做了类似于Khamaileon在这里提出的建议.基本上我修改了我的序列化程序以查看请求,哪种气味有问题,但它完成了工作...这是它的外观(例如购买示例):
class PurchaseSerializer(serializers.HyperlinkedModelSerializer):
def get_fields(self, *args, **kwargs):
fields = super(PurchaseSerializer, self).get_fields(*args, **kwargs)
fields['purchaser'].queryset = permitted_objects(self.context['view'].request.user, fields['purchaser'].queryset)
return fields
class Meta:
model = Purchase
Run Code Online (Sandbox Code Playgroud)
allowed_objects是一个接受用户和查询的函数,并返回一个过滤的查询,该查询仅包含用户有权链接的对象.这似乎适用于验证和可浏览的API下拉字段.
dus*_*ris 14
我是这样做的:
class PurchaseList(viewsets.ModelViewSet):
...
def get_serializer(self, *args, **kwargs):
serializer_class = self.get_serializer_class()
context = self.get_serializer_context()
return serializer_class(*args, request_user=self.request.user, context=context, **kwargs)
class PurchaseSerializer(serializers.ModelSerializer):
...
def __init__(self, *args, request_user=None, **kwargs):
super(PurchaseSerializer, self).__init__(*args, **kwargs)
self.fields['user'].queryset = User._default_manager.filter(pk=request_user.pk)
Run Code Online (Sandbox Code Playgroud)
示例链接似乎不再可用,但通过阅读其他评论,我假设您正在尝试过滤用户与购买的关系。
如果我是对的,那么我可以说现在有一种官方方法可以做到这一点。使用 django rest 框架 3.10.1 测试。
class UserPKField(serializers.PrimaryKeyRelatedField):
def get_queryset(self):
user = self.context['request'].user
queryset = User.objects.filter(...)
return queryset
class PurchaseSeriaizer(serializers.ModelSerializer):
users = UserPKField(many=True)
class Meta:
model = Purchase
fields = ('id', 'users')
Run Code Online (Sandbox Code Playgroud)
这也适用于可浏览 API。
资料来源:
https://github.com/encode/django-rest-framework/issues/1985#issuecomment-328366412
我不喜欢必须为我需要访问用户数据的每个地方覆盖init方法的样式,或者在运行时限制查询集的实例.所以我选择了这个解决方案.
这是代码内联.
from rest_framework import serializers
class LimitQuerySetSerializerFieldMixin:
"""
Serializer mixin with a special `get_queryset()` method that lets you pass
a callable for the queryset kwarg. This enables you to limit the queryset
based on data or context available on the serializer at runtime.
"""
def get_queryset(self):
"""
Return the queryset for a related field. If the queryset is a callable,
it will be called with one argument which is the field instance, and
should return a queryset or model manager.
"""
# noinspection PyUnresolvedReferences
queryset = self.queryset
if hasattr(queryset, '__call__'):
queryset = queryset(self)
if isinstance(queryset, (QuerySet, Manager)):
# Ensure queryset is re-evaluated whenever used.
# Note that actually a `Manager` class may also be used as the
# queryset argument. This occurs on ModelSerializer fields,
# as it allows us to generate a more expressive 'repr' output
# for the field.
# Eg: 'MyRelationship(queryset=ExampleModel.objects.all())'
queryset = queryset.all()
return queryset
class DynamicQuersetPrimaryKeyRelatedField(LimitQuerySetSerializerFieldMixin, serializers.PrimaryKeyRelatedField):
"""Evaluates callable queryset at runtime."""
pass
class MyModelSerializer(serializers.ModelSerializer):
"""
MyModel serializer with a primary key related field to 'MyRelatedModel'.
"""
def get_my_limited_queryset(self):
root = self.root
if root.instance is None:
return MyRelatedModel.objects.none()
return root.instance.related_set.all()
my_related_model = DynamicQuersetPrimaryKeyRelatedField(queryset=get_my_limited_queryset)
class Meta:
model = MyModel
Run Code Online (Sandbox Code Playgroud)
这样做的唯一缺点是您需要显式设置相关的序列化器字段,而不是使用提供的自动字段发现ModelSerializer
.但是我希望默认情况下这样的东西在rest_framework中.
在 django Rest Framework 3.0 中,删除了 get_fields 方法。但您可以以类似的方式在序列化器的 init 函数中执行此操作:
class PurchaseSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Purchase
def __init__(self, *args, **kwargs):
super(PurchaseSerializer, self).__init__(*args, **kwargs)
if 'request' in self.context:
self.fields['purchaser'].queryset = permitted_objects(self.context['view'].request.user, fields['purchaser'].queryset)
Run Code Online (Sandbox Code Playgroud)
我添加了 if 检查,因为如果您在 get 方法的另一个序列化程序中使用 PurchaseSerializer 作为字段,则请求将不会传递到上下文。
归档时间: |
|
查看次数: |
16830 次 |
最近记录: |