我有一个代表房子的模型:
class House(models.Model):
name = models.CharField(...)
long = models.FloatField(...)
lat = models.FloatField(...)
和一个序列化程序,用于返回最基本的表示中的房屋列表:
class HouseSerializer(serializers.ModelSerializer):
class Meta:
model = House
fields = ('id', 'name')
和视图
class HouseList(generics.ListAPIView):
queryset = House.objects.all()
serializer_class = HouseSerializer
这很好用。我可以访问/api/house/
并看到json的房屋清单:
{
'id': 1,
'name': 'Big House'
},
{
'id': 1
'name': 'Small House',
}...
现在,我想在/api/maps/markers/
创建第二个视图/资源,将我的房屋作为Google-Map-Friendly标记列表返回:
{
'id': 1,
'long': ...,
'lat': ...,
'houseInfo': {
'title': "Big House",
}
} ...
我可以预见两种方法:
Response
之前简单地布置字段但是我没有采用任何方法,我明确了如何处理它,哪种方法更可取?
答案 0 :(得分:5)
回答1
在我看来,你需要两种 - 不同的视图和序列化器。
仅仅因为视图端点不是第一个的子网址,所以它们不相关 - 不同的视图,即使它们使用相同的模型。
不同的序列化程序 - 因为你有不同的字段布局。
不确定你的情况有多复杂,但无论如何,任何代码重复都可能由mixin解决。
回答2
取决于用例:
如果只是阅读数据,你应该没问题:
class HouseGoogleSerializer(HouseSerializer):
houseInfo = serializers.SerializerMethodField('get_house_info')
class Meta:
model = House
fields = [...]
def get_house_info(self, obj):
return {'title': obj.name}
其中HouseSerializer
是您的基本序列化程序。
答案 1 :(得分:1)
此代码来自正在运行的项目,并提供更多您要求的代码 但如果你想删除一些功能,可以很容易地适应你的需要。 当前的实现允许您:
如何在您的代码中使用:
案例1 (一个能够通过查询字符串选择序列化程序的网址)
class HouseSerializer(HouseSerializer):
houseInfo = serializers.SerializerMethodField('get_house_info')
class Meta:
model = House
def get_house_info(self, obj):
return {'title': obj.name}
class HouseList(DynamicSerializerMixin, generics.ListAPIView):
queryset = House.objects.all()
serializer_class = HouseSerializer
serializers_fieldsets = {'std': ('id', 'name'),
'google' : ('id', 'long', 'lat', 'houseInfo')}
案例2 (不同观点)
class HouseList(DynamicSerializerMixin, generics.ListAPIView):
queryset = House.objects.all()
serializer_class = HouseSerializer
serializers_fieldsets = {'std': ('id', 'name')}
class GoogleHouseList(DynamicSerializerMixin, generics.ListAPIView):
queryset = House.objects.all()
serializer_class = HouseSerializer
serializers_fieldsets = {'std': ('id', 'long', 'lat', 'houseInfo')}
==============
def serializer_factory(model, base=BaseHyperlinkedModelSerializer,
fields=None, exclude=None):
attrs = {'model': model}
if fields is not None:
attrs['fields'] = fields
if exclude is not None:
attrs['exclude'] = exclude
parent = (object,)
if hasattr(base, 'Meta'):
parent = (base.Meta, object)
Meta = type(str('Meta'), parent, attrs)
if model:
class_name = model.__name__ + 'Serializer'
else:
class_name = 'Serializer'
return type(base)(class_name, (base,), {'Meta': Meta, })
class DynamicSerializerMixin(object):
"""
Mixin that allow to limit the fields returned
by the serializer.
Es.
class User(models.Model):
country = models.ForeignKey(country)
username = models.CharField(max_length=100)
email = models.EmailField()
class UserSerializer(BaseHyperlinkedModelSerializer):
country = serializers.Field(source='country.name')
class MyViewSet(DynamicSerializerViewSetMixin, BaseModelViewSet):
model = User
serializer_class = UserSerializer
serializers_fieldsets = {'std': None,
'brief' : ('username', 'email')
}
this allow calls like
/api/v1/user/?serializer=brief
"""
serializers_fieldsets = {'std': None}
serializer_class = ModelSerializer
def get_serializer_class(self):
ser = self.request.QUERY_PARAMS.get('serializer', 'std')
fields = self.serializers_fieldsets.get(ser, 'std')
return serializer_factory(self.model,
self.serializer_class,
fields=fields)