Используя фреймворк 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)

Этот код обеспечивает большую гибкость на случай, если вам это понадобится. (А вам это, скорее всего, понадобится)

Вернуться на верх