Solución:
Puede crear una subclase de ListSerializer y sobrescribir el to_representation
método.
Por defecto el to_representation
llamadas a métodos data.all()
en el conjunto de consultas anidado. Entonces, efectivamente necesitas hacer data = data.filter(**your_filters)
antes de que se llame al método. Luego, debe agregar su ListSerializer subclasificado como list_serializer_class en el meta del serializador anidado.
- subclase ListSerializer, sobrescribiendo
to_representation
y luego llamar super - agregar ListSerializer subclasificado como meta
list_serializer_class
en el serializador anidado
Aquí está el código relevante para su muestra.
class FilteredListSerializer(serializers.ListSerializer):
def to_representation(self, data):
data = data.filter(user=self.context['request'].user, edition__hide=False)
return super(FilteredListSerializer, self).to_representation(data)
class EditionSerializer(serializers.ModelSerializer):
class Meta:
list_serializer_class = FilteredListSerializer
model = Edition
class QuestionnaireSerializer(serializers.ModelSerializer):
edition = EditionSerializer(read_only=True)
company = serializers.StringRelatedField(read_only=True)
class Meta:
model = Questionnaire
Probé muchas soluciones de SO y otros lugares.
Encontré solo una solución funcional para Django 2.0 + DRF 3.7.7.
Defina un método en el modelo que tenga una clase anidada. Elabore un filtro que se adapte a sus necesidades.
class Channel(models.Model):
name = models.CharField(max_length=40)
number = models.IntegerField(unique=True)
active = models.BooleanField(default=True)
def current_epg(self):
return Epg.objects.filter(channel=self, end__gt=datetime.now()).order_by("end")[:6]
class Epg(models.Model):
start = models.DateTimeField()
end = models.DateTimeField(db_index=True)
title = models.CharField(max_length=300)
description = models.CharField(max_length=800)
channel = models.ForeignKey(Channel, related_name="onair", on_delete=models.CASCADE)
.
class EpgSerializer(serializers.ModelSerializer):
class Meta:
model = Epg
fields = ('channel', 'start', 'end', 'title', 'description',)
class ChannelSerializer(serializers.ModelSerializer):
onair = EpgSerializer(many=True, read_only=True, source="current_epg")
class Meta:
model = Channel
fields = ('number', 'name', 'onair',)
Presta atencion a source="current_epg"
y entenderás el punto.
Si bien todas las respuestas anteriores funcionan, encuentro el uso de Django’s Prefetch
objetar la forma más fácil de todas.
Di un Restaurant
obj tiene una gran cantidad de MenuItem
s, algunos de los cuales son is_remove == True
, y solo desea los que no se eliminan.
En RestaurantViewSet
, haz algo como
from django.db.models import Prefetch
queryset = Restaurant.objects.prefetch_related(
Prefetch('menu_items', queryset=MenuItem.objects.filter(is_removed=False), to_attr="filtered_menu_items")
)
En RestaurantSerializer
, haz algo como
class RestaurantSerializer(serializers.ModelSerializer):
menu_items = MenuItemSerializer(source="filtered_menu_items", many=True, read_only=True)