DRF 视图集 Returns 具有空值的查询集
DRF ViewSet Returns QuerySet With Empty Values
我有一个名为 "QueryCriteriaViewSet" 的 DRF 视图集,我在查询生成器中使用它,它允许用户 select 一个字段,然后从相关条件 select。因此,例如,用户可以 select "reg_status" 字段,然后根据 "Active" 和 "Inactive" 的相关条件 select。
当我 select 来自主 "person" 模型的字段时,这完全正常。但是当我 select 来自相关模型(如 "lookup_party" 模型)的字段时,我 运行 遇到了问题。奇怪的是,当我将查询集打印到控制台时,它工作得很好,但是当我调用 API 时,它 returns 一个空对象列表。
再举一个例子,这是我打电话时发生的情况:
api/querycriteria/?fields=reg_status
returns:
[
{"reg_status": "Active"},
{"reg_status": "Inactive"}
]
同时 api/querycriteria/?fields=party__party_name
returns:
[
{},
{},
{},
{},
{}
]
即使我 print(queryset)
在返回查询集之前打印了以下内容:
<QuerySet [{'party__party_name': None}, {'party__party_name': 'Democratic'},
{'party__party_name': 'Non-Partisan'}, {'party__party_name': 'Registered
Independent'}, {'party__party_name': 'Republican'}]>
这是完整的视图集:
class QueryCriteriaViewSet(DefaultsMixin, viewsets.ModelViewSet):
serializer_class = QueryCriteriaSerializer
def get_queryset(self):
fields = self.request.GET.get('fields', None)
queryset = Person.objects.values(fields).distinct()
print(queryset)
return queryset
def get_fields_to_display(self):
fields = self.request.GET.get('fields', None)
return fields.split(',') if fields else None
def get_serializer(self, instance=None, data=empty, many=False,
partial=False):
"""
Return the serializer instance that should be used for validating and
deserializing input, and for serializing output.
"""
serializer_class = self.get_serializer_class()
context = self.get_serializer_context()
fields = self.get_fields_to_display()
return serializer_class(instance, data=data,
many=many, partial=partial,
context=context, fields=fields)
如果有任何其他信息有帮助,请告诉我。
这是我的序列化程序:
from django.contrib.auth import get_user_model
from rest_framework import serializers
from rest_framework.reverse import reverse
from ..models.people import Person
from ..models.people_emails import Email
from ..models.people_addresses import Address
from ..models.people_phones import Phone
from ..models.people_tags import PersonTag
from ..models.people_elections import PersonElection
from ..models.people_districts import PersonDistrict
from ..models.people_attributes import Attribute
from .serializer_dynamic_fields import DynamicFieldsModelSerializer
from .serializer_tag import TagSerializer
from .serializer_email import EmailSerializer
from .serializer_address import AddressSerializer
from .serializer_phone import PhoneSerializer
from .serializer_election import ElectionSerializer
from .serializer_attribute import AttributeSerializer
from .serializer_district import DistrictSerializer
class QueryCriteriaSerializer(DynamicFieldsModelSerializer):
emails = EmailSerializer(many=True, required=False)
addresses = AddressSerializer(many=True, required=False)
phones = PhoneSerializer(many=True, required=False)
tags = TagSerializer(many=True, required=False)
elections = ElectionSerializer(many=True, required=False)
attributes = AttributeSerializer(many=True, required=False)
districts = DistrictSerializer(many=True, required=False)
class Meta:
model = Person
fields = ('id', 'elected_official', 'title', 'first', 'last', 'middle', 'suffix',
'full_name', 'birthdate', 'sex', 'website', 'deceased', 'registered', 'party',
'reg_date', 'reg_status', 'reg_state', 'county', 'match_id',
'date_added', 'date_updated', 'do_not_call', 'do_not_mail', 'do_not_email', 'do_not_text', 'emails',
'addresses', 'phones', 'tags', 'attributes', 'elections', 'districts')
这是 DynamicFieldsModelSerializer:
from django.contrib.auth import get_user_model
from rest_framework import serializers
class DynamicFieldsModelSerializer(serializers.ModelSerializer):
"""
A ModelSerializer that takes an additional `fields` argument that
controls which fields should be displayed.
"""
def __init__(self, *args, **kwargs):
# Don't pass the 'fields' arg up to the superclass
fields = kwargs.pop('fields', None)
# Instantiate the superclass normally
super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)
if fields is not None:
# Drop any fields that are not specified in the `fields` argument.
allowed = set(fields)
existing = set(self.fields)
for field_name in existing - allowed:
self.fields.pop(field_name)
好的,现在发现问题了,DynamicFieldsModelSerializer 仅在您传递给它的字段是序列化程序原始字段的子集时才起作用。
您应该以接受额外字段的方式使用序列化程序,如下所示:
class ExtraDynamicFieldsModelSerializer(serializers.ModelSerializer):
def __init__(self, *args, **kwargs):
extra_fields = kwargs.pop('fields', [])
self.extra_fields = set()
# Instantiate the superclass normally
super(ExtraDynamicFieldsModelSerializer, self).__init__(*args, **kwargs)
allowed = set(extra_fields)
existing = set(self.fields)
for field_name in existing - allowed:
self.fields.pop(field_name)
for field_name in allowed - existing:
self.extra_fields.add(field_name)
def to_representation(self, obj):
data = super().to_representation(obj)
for field in self.extra_fields:
data[field] = obj[field]
return data
我有一个名为 "QueryCriteriaViewSet" 的 DRF 视图集,我在查询生成器中使用它,它允许用户 select 一个字段,然后从相关条件 select。因此,例如,用户可以 select "reg_status" 字段,然后根据 "Active" 和 "Inactive" 的相关条件 select。
当我 select 来自主 "person" 模型的字段时,这完全正常。但是当我 select 来自相关模型(如 "lookup_party" 模型)的字段时,我 运行 遇到了问题。奇怪的是,当我将查询集打印到控制台时,它工作得很好,但是当我调用 API 时,它 returns 一个空对象列表。
再举一个例子,这是我打电话时发生的情况:
api/querycriteria/?fields=reg_status
returns:
[
{"reg_status": "Active"},
{"reg_status": "Inactive"}
]
同时 api/querycriteria/?fields=party__party_name
returns:
[
{},
{},
{},
{},
{}
]
即使我 print(queryset)
在返回查询集之前打印了以下内容:
<QuerySet [{'party__party_name': None}, {'party__party_name': 'Democratic'},
{'party__party_name': 'Non-Partisan'}, {'party__party_name': 'Registered
Independent'}, {'party__party_name': 'Republican'}]>
这是完整的视图集:
class QueryCriteriaViewSet(DefaultsMixin, viewsets.ModelViewSet):
serializer_class = QueryCriteriaSerializer
def get_queryset(self):
fields = self.request.GET.get('fields', None)
queryset = Person.objects.values(fields).distinct()
print(queryset)
return queryset
def get_fields_to_display(self):
fields = self.request.GET.get('fields', None)
return fields.split(',') if fields else None
def get_serializer(self, instance=None, data=empty, many=False,
partial=False):
"""
Return the serializer instance that should be used for validating and
deserializing input, and for serializing output.
"""
serializer_class = self.get_serializer_class()
context = self.get_serializer_context()
fields = self.get_fields_to_display()
return serializer_class(instance, data=data,
many=many, partial=partial,
context=context, fields=fields)
如果有任何其他信息有帮助,请告诉我。
这是我的序列化程序:
from django.contrib.auth import get_user_model
from rest_framework import serializers
from rest_framework.reverse import reverse
from ..models.people import Person
from ..models.people_emails import Email
from ..models.people_addresses import Address
from ..models.people_phones import Phone
from ..models.people_tags import PersonTag
from ..models.people_elections import PersonElection
from ..models.people_districts import PersonDistrict
from ..models.people_attributes import Attribute
from .serializer_dynamic_fields import DynamicFieldsModelSerializer
from .serializer_tag import TagSerializer
from .serializer_email import EmailSerializer
from .serializer_address import AddressSerializer
from .serializer_phone import PhoneSerializer
from .serializer_election import ElectionSerializer
from .serializer_attribute import AttributeSerializer
from .serializer_district import DistrictSerializer
class QueryCriteriaSerializer(DynamicFieldsModelSerializer):
emails = EmailSerializer(many=True, required=False)
addresses = AddressSerializer(many=True, required=False)
phones = PhoneSerializer(many=True, required=False)
tags = TagSerializer(many=True, required=False)
elections = ElectionSerializer(many=True, required=False)
attributes = AttributeSerializer(many=True, required=False)
districts = DistrictSerializer(many=True, required=False)
class Meta:
model = Person
fields = ('id', 'elected_official', 'title', 'first', 'last', 'middle', 'suffix',
'full_name', 'birthdate', 'sex', 'website', 'deceased', 'registered', 'party',
'reg_date', 'reg_status', 'reg_state', 'county', 'match_id',
'date_added', 'date_updated', 'do_not_call', 'do_not_mail', 'do_not_email', 'do_not_text', 'emails',
'addresses', 'phones', 'tags', 'attributes', 'elections', 'districts')
这是 DynamicFieldsModelSerializer:
from django.contrib.auth import get_user_model
from rest_framework import serializers
class DynamicFieldsModelSerializer(serializers.ModelSerializer):
"""
A ModelSerializer that takes an additional `fields` argument that
controls which fields should be displayed.
"""
def __init__(self, *args, **kwargs):
# Don't pass the 'fields' arg up to the superclass
fields = kwargs.pop('fields', None)
# Instantiate the superclass normally
super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)
if fields is not None:
# Drop any fields that are not specified in the `fields` argument.
allowed = set(fields)
existing = set(self.fields)
for field_name in existing - allowed:
self.fields.pop(field_name)
好的,现在发现问题了,DynamicFieldsModelSerializer 仅在您传递给它的字段是序列化程序原始字段的子集时才起作用。
您应该以接受额外字段的方式使用序列化程序,如下所示:
class ExtraDynamicFieldsModelSerializer(serializers.ModelSerializer):
def __init__(self, *args, **kwargs):
extra_fields = kwargs.pop('fields', [])
self.extra_fields = set()
# Instantiate the superclass normally
super(ExtraDynamicFieldsModelSerializer, self).__init__(*args, **kwargs)
allowed = set(extra_fields)
existing = set(self.fields)
for field_name in existing - allowed:
self.fields.pop(field_name)
for field_name in allowed - existing:
self.extra_fields.add(field_name)
def to_representation(self, obj):
data = super().to_representation(obj)
for field in self.extra_fields:
data[field] = obj[field]
return data