Wie filtert man in Django Rest Framework einen Serializer, wenn er in einem anderen Serializer verschachtelt ist?
Meine Filter werden in den DRF-Viewsets festgelegt. Wenn Sie jedoch einen Serializer aus einem anderen Serializer aufrufen, wird der Viewset des verschachtelten Serializers nie aufgerufen, sodass die verschachtelten Ergebnisse ungefiltert angezeigt werden.
Ich habe versucht, einen Filter für das ursprüngliche Ansichten-Set hinzuzufügen, aber es scheint die verschachtelten Ergebnisse nicht zu filtern, da die verschachtelten Ergebnisse als separate, vordefinierte Abfrage aufgerufen werden. (Der verschachtelte Serializer ist eine umgekehrte Suche.)
Ist es möglich, eine get_queryset () - Überschreibung im verschachtelten Serializer selbst hinzuzufügen (aus dem Viewset zu verschieben), um den Filter dort hinzuzufügen? Ich habe das auch ohne Glück versucht.
Dies ist, was ich versucht habe, aber es scheint nicht einmal aufgerufen zu werden:
class QuestionnaireSerializer(serializers.ModelSerializer):
edition = EditionSerializer(read_only=True)
company = serializers.StringRelatedField(read_only=True)
class Meta:
model = Questionnaire
def get_queryset(self):
query = super(QuestionnaireSerializer, self).get_queryset(instance)
if not self.request.user.is_staff:
query = query.filter(user=self.request.user, edition__hide=False)
return query
Sie können die ListSerializer Unterklasse und die to_representation
- Methode überschreiben.
Standardmäßig ruft die Methode to_representation
data.all()
im verschachtelten Abfragesatz auf. Sie müssen also effektiv data = data.filter(**your_filters)
machen, bevor die Methode aufgerufen wird. Dann müssen Sie Ihren ListSerializer der Unterklasse als list_serializer_class auf der Meta des verschachtelten Serializers hinzufügen.
to_representation
und ruft dann super auflist_serializer_class
für den verschachtelten Serializer hinzuHier ist der relevante Code für Ihr Beispiel.
class FilteredListSerializer(serializers.ListSerializer):
def to_representation(self, data):
data = data.filter(user=self.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
Getestet viele Lösungen von SO und anderen Orten.
Es wurde nur eine funktionierende Lösung für Django 2.0 + DRF 3.7.7 gefunden.
Definieren Sie eine Methode im Modell, die eine verschachtelte Klasse hat. Stellen Sie einen Filter zusammen, der Ihren Anforderungen entspricht.
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',)
Achten Sie auf source="current_epg"
und Sie werden den Punkt bekommen.
Wenn ein Serializer instanziiert und many = True übergeben wird, wird eine ListSerializer-Instanz erstellt. Die Serializer-Klasse wird dann ein untergeordnetes Element des übergeordneten ListSerializer
Diese Methode nimmt das Ziel des Felds als Wertargument und sollte die Darstellung zurückgeben, die zum Serialisieren des Ziels verwendet werden soll. Das value-Argument ist normalerweise eine Modellinstanz.
nten sehen Sie das Beispiel des verschachtelten Serializers
class UserSerializer(serializers.ModelSerializer):
""" Here many=True is passed, So a ListSerializer instance will be
created"""
system = SystemSerializer(many=True, read_only=True)
class Meta:
model = UserProfile
fields = ('system', 'name')
class FilteredListSerializer(serializers.ListSerializer):
"""Serializer to filter the active system, which is a boolen field in
System Model. The value argument to to_representation() method is
the model instance"""
def to_representation(self, data):
data = data.filter(system_active=True)
return super(FilteredListSerializer, self).to_representation(data)
class SystemSerializer(serializers.ModelSerializer):
mac_id = serializers.CharField(source='id')
system_name = serializers.CharField(source='name')
serial_number = serializers.CharField(source='serial')
class Meta:
model = System
list_serializer_class = FilteredListSerializer
fields = (
'mac_id', 'serial_number', 'system_name', 'system_active',
)
In view:
class SystemView(viewsets.GenericViewSet, viewsets.ViewSet):
def retrieve(self, request, email=None):
data = get_object_or_404(UserProfile.objects.all(), email=email)
serializer = UserSerializer(data)
return Response(serializer.data)