Используя фреймворк Django REST, как я могу настроить так, чтобы поле было исключено из одного представления, но включено в другое, без особого раздувания кода?
Например, если бы у меня были эти модели, как я мог бы убедиться, что в одном представлении отображается только название дома, а в другом - все его свойства. Кроме того, как я могу отобразить имя риэлтора, а не только его идентификатор, когда я запрашиваю дом?
class Realtor(models.Model):
name = models.CharField(max_length=100)
class House(models.Model):
name = models.CharField(max_length=100)
address = models.TextField()
price = models.DecimalField(max_digits=10, decimal_places=2)
realtor = models.ForeignKey(Realtor, related_name='houses', on_delete=models.CASCADE)
Вам нужно будет определить ModelSerializer для каждого случая :
# serializers.py
from rest_framework import serializers
from models import House, Realtor
class BaseHouseSerializer(serializers.ModelSerializer):
class Meta:
model = House
fields = ["name"]
class RealtorSerializer(serializers.ModelSerializer):
class Meta:
model = Realtor
fields = ["name"]
class DetailedHouseSerializer(serializers.ModelSerializer):
realtor = RealtorSerializer() # Using nested serializer
class Meta:
model = House
fields = "__all__"
Затем используйте эти сериализаторы в своих представлениях:
from rest_framework import generics
from serializers import BaseHouseSerializer, DetailedHouseSerializer
from models import House, Realtor
class HouseList(generics.ListAPIView):
queryset = House.objects.all()
serializer_class = BaseHouseSerializer
class DetailedHouseList(generics.ListAPIView):
queryset = House.objects.all()
serializer_class = DetailedHouseSerializer
Это зависит от того, насколько настраиваемым вы хотите сделать свой код.
Ответ Пьера Куи прост и хорош, однако, если вы хотите больше контроля, вы можете создать класс динамического сериализатора и использовать его следующим образом:
from rest_framework import serializers
from .models import Realtor, House
class DynamicSerializer(serializers.ModelSerializer):
def __init__(self, *args, **kwargs):
fields = kwargs.pop('fields', None)
super().__init__(*args, **kwargs)
if fields is not None:
allowed = set(fields)
for field_name in list(self.fields):
if field_name not in allowed:
self.fields.pop(field_name)
class HouseSerializer(DynamicSerializer):
realtor = serializers.SerializerMethodField(read_only=True)
price = serializers.FloatField()
class Meta:
model = House
fields = ['id', 'name', 'address', 'price', 'realtor']
def get_realtor(self, obj):
realtor_fields = self.context.get("realtor_fields", ['id', 'name']) #or whatever you want here
return RealtorSerializer(obj.realtor, context=self.context, fields=realtor_fields).data
class RealtorSerializer(DynamicSerializer):
houses = serializers.SerializerMethodField(read_only=True)
class Meta:
model = Realtor
fields = ['id', 'name', 'houses']
def get_houses(self, obj):
house_fields = self.context.get('house_fields', ['name'])
return HouseSerializer(obj.houses.all(), many=True, context=self.context, fields=house_fields).data
Это пример, в котором вы можете найти всех риэлторов, но будут видны только названия домов и цены. Если вы получите все дома, вы увидите только имена риэлторов.
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Realtor, House
from .serializers import RealtorSerializer, HouseSerializer
class RealtorsGetCreate(APIView):
def get(self, request):
realtors = Realtor.objects.all()
serializer = RealtorSerializer(realtors, many=True, context={"house_fields":["name", "price"]})
return Response(serializer.data)
def post(self, request):
new_realtor = Realtor.objects.create(name=request.data.get("name"))
new_realtor.save()
return Response(201)
class HousesGetCreate(APIView):
def get(self, request):
houses = House.objects.all()
serializer = HouseSerializer(houses, many=True context={"realtor_fields":["name"]},)
return Response(serializer.data)
def post(self, request):
realtor = Realtor.objects.get(id=request.data.get("realtor_id"))
new_house = House.objects.create(
address = request.data.get("address"),
name = request.data.get("name"),
price = request.data.get("price"),
realtor = realtor
)
new_house.save()
return Response(201)
Этот код обеспечивает большую гибкость на случай, если вам это понадобится. (А вам это, скорее всего, понадобится)