framework fields exclude delete django django-rest-framework

fields - django rest framework response



¿Cómo se filtra un serializador anidado en Django Rest Framework? (4)

En Django Rest Framework, ¿cómo filtra un serializador cuando está anidado en otro serializador?

Mis filtros se imponen en las vistas DRF, pero cuando llama a un serializador desde otro serializador, la vista del serializador anidado nunca se llama, por lo que los resultados anidados aparecen sin filtrar.

Intenté agregar un filtro en la vista de origen, pero no parece filtrar los resultados anidados porque los resultados anidados se llaman como una consulta pretrapada separada. (El serializador anidado es una búsqueda inversa, ya ves).

¿Es posible agregar una anulación get_queryset () en el serializador anidado (moviéndolo fuera del conjunto de visualización), para agregar el filtro allí? También lo intenté sin suerte.

Esto es lo que probé, pero parece que ni siquiera se llama:

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


Cuando se crea una instancia de un serializador y se pasa many = True, se creará una instancia de ListSerializer. La clase de serializador se convierte en un elemento secundario del ListSerializer primario

Este método toma el objetivo del campo como argumento de valor y debe devolver la representación que se debe usar para serializar el objetivo. El argumento del valor normalmente será una instancia de modelo.

A continuación se muestra el ejemplo del serializador anidado

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'', )

En vista:

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)


Probado muchas soluciones de SO y otros lugares.

Encontró una sola solución de trabajo para Django 2.0 + DRF 3.7.7.

Defina un método en el modelo que tenga una clase anidada. Crea un filtro que se ajuste a tus 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 atención a source="current_epg" y obtendrás el punto.


Puede subclasificar el ListSerializer y sobrescribir el método to_representation .

Por defecto, el método to_representation llama a data.all() en el conjunto de consultas anidado. Por lo tanto, efectivamente debe 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.

  1. subclase ListSerializer, sobrescribiendo to_representation y luego llamando super
  2. agregue ListSerializer subclases 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.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


Si bien todas las respuestas anteriores funcionan, creo que el uso del objeto Prefetch de Django es la forma más fácil de todas.

Digamos que un obj de Restaurant tiene muchos MenuItem s, algunos de los cuales son is_remove == True , y solo desea aquellos que no se eliminan.

En RestaurantViewSet , haga 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 , haga algo como

class RestaurantSerializer(serializers.ModelSerializer): menu_items = MenuItemSerializer(source=''filtered_menu_items'', many=True, read_only=True)