¿Cómo serializo un campo de muchos a muchos en una lista de algo y los devuelvo a través del marco de descanso? En mi ejemplo a continuación, trato de devolver la publicación junto con una lista de etiquetas asociadas.
modelos.py
class post(models.Model):
tag = models.ManyToManyField(Tag)
text = models.CharField(max_length=100)
serializers.py
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ("text", "tag"??)
views.py
class PostViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
Respuestas:
Necesitará un
TagSerializer
, cuyoclass Meta
tienemodel = Tag
. Una vezTagSerializer
creado, modifiquePostSerializer
conmany=True
para unaManyToManyField
relación:class PostSerializer(serializers.ModelSerializer): tag = TagSerializer(read_only=True, many=True) class Meta: model = Post fields = ('tag', 'text',)
La respuesta es para DRF 3
fuente
read_only=True
parte se explica aquí: django-rest-framework.org/api-guide/relations/…Esto es lo que hice, supongamos que un libro puede tener más de un autor y un autor puede tener más de un libro: En modelo:
class Author(models.Model): name = models.CharField(max_length=100, default="") last_name = models.IntegerField(default=0) class Book(models.Model): authors = models.ManyToManyField(Author, related_name="book_list", blank=True) name = models.CharField(max_length=100, default="") published = models.BooleanField(default=True)
En serializadores:
class BookSerializer(serializers.ModelSerializer): authors = serializers.PrimaryKeyRelatedField(queryset=Author.objects.all(), many=True) class Meta: model = Book fields = ('id', 'name', 'published', 'authors') class AuthorSerializer(serializers.ModelSerializer): book_list = BookSerializer(many=True, read_only=True) class Meta: model = Author fields = ('id', 'name', 'last_name', 'book_list')
fuente
Agregar a la respuesta de @ Brian "etiquetas": [{"nombre": "etiqueta1"}] se puede simplificar a "etiquetas": ["etiqueta1", "etiqueta2", ...] de esta manera:
class PostSerializer(serializers.ModelSerializer): tag = TagSerializer(read_only=True, many=True) class Meta: ... class TagSerializer(serializers.RelatedField): def to_representation(self, value): return value.name class Meta: model = Tag
Más información aquí: https://www.django-rest-framework.org/api-guide/relations/#custom-relational-fields
fuente
Esto funciona para mi.
tag = TagSerializer(source="tag", read_only=True, many=True)
fuente
Django 2.0
Para el campo de muchos a muchos, si desea uno específico:
class QuestionSerializer(serializers.ModelSerializer): topics_list = serializers.SerializerMethodField() def get_topics_list(self, instance): names = [] a = instance.topics.get_queryset() for i in a: names.append(i.desc) return names class Meta: model = Question fields = ('topics_list',)
fuente
get_topics_list
podrías simplificar areturn list(instance.topics.values_list('desc', flat=True))
En el serializador en el método init , puede pasar el conjunto de consultas al campo y rest_framework validar los identificadores en ese conjunto de consultas
1) primero amplíe su serializador desde los serializadores.
class YourSerializer(serializers.ModelSerializer):
2) incluir el campo en la metaclase
class YourSerializer(serializers.ModelSerializer): class Meta: fields = (..., 'your_field',)
3) en el método init:
def __init__(self, *args, **kwargs): super(YourSerializer, self).__init__(*args, **kwargs) self.fields['your_field].queryset = <the queryset of your field>
Puede limitar el conjunto de consultas para ese campo bajo cualquier argumento usando filtro o excluir como lo hace normalmente. En caso de que desee incluir todos, simplemente use .objects.all ()
fuente
El valor predeterminado
ModelSerializer
usa claves primarias para las relaciones. Sin embargo, puede generar fácilmente representaciones anidadas utilizando elMeta
depth
atributo:class PostSerializer(serializers.ModelSerializer): class Meta: model = Post fields = ("text", "tag") depth = 1
Como se menciona en la documentación :
fuente