webentwicklung-frage-antwort-db.com.de

Wie filtert man einen verschachtelten Serializer in Django Rest Framework?

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
65
John

Sie können die ListSerializer Unterklasse und die to_representation - Methode überschreiben.

Standardmäßig ruft die Methode to_representationdata.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.

  1. unterklasse ListSerializer, überschreibt to_representation und ruft dann super auf
  2. fügen Sie ListSerializer der Unterklasse als Meta list_serializer_class für den verschachtelten Serializer hinzu

Hier 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
73
inperspective

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.

15
duddits

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)
6
Vinay Kumar