Доступ к значениям Django M2M в наборе запросов без циклов
Я получаю некоторые данные через Ajax, что позволяет мне сделать некоторую фильтрацию на модели, которая имеет некоторые m2m отношения (скажем, Model). Я получаю набор запросов, скажем "content", который мне нужно отправить обратно, используя json. Вот упрощенные строки кода:
content = Models.objects.all()
content = content.values
return JsonResponse({"data":list(content)})
Все работало нормально, но проект изменился, и теперь мне нужно включить значения некоторых m2m связанных моделей, присоединенных к Model, в каждый экземпляр результата queryset, проблема в том, что content=Model.objects.all(), конечно, не даст мне эти значения без некоторого цикла, поэтому я застрял. Я помню, что использовал опцию глубины в DRF, которая могла бы сделать эту работу здесь, но, к сожалению, я не могу сделать это сейчас, так как проект слишком продвинутый и живой. Есть ли способ добавить непосредственно в набор запросов результаты значений, связанных с m2m? Большое спасибо
Добавляем сюда упрощенные модели :
class Content(models.Model):
uuid = models.CharField(max_length=255, primary_key=True, default=uuid.uuid4, editable=False)
pathology = models.ManyToManyField(Pathology, null=True, blank=True)
organs = models.ManyToManyField(Organ, null=True, blank=True)
title = models.CharField(verbose_name="Titre",
max_length=255, null=True, blank=False)
document = models.ForeignKey(
'wagtaildocs.Document',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="+",
)
description = RichTextField(null=True, blank=True)
class Pathology(models.Model):
title = models.CharField(max_length=255, null=True, blank=True)
def __str__(self):
return self.title
class Organ(models.Model):
title = models.CharField(max_length=255, null=True, blank=True)
def __str__(self):
return self.title
Пожалуйста, не используйте .values(…)
[Django-antipatterns], они разрушают логику в слое модели. Кроме того, вы не можете использовать .values(…)
двунаправленно: вы можете только преобразовывать записи в словари, но не десериализовывать словари в объекты модели.
В PostgreSQL можно использовать ArrayAgg
[Django-doc], это агрегат, который работает только для PostgreSQL, и, кроме того, он, вероятно, не идеален, поскольку опять же делает адаптацию процесса сериализации громоздкой. Вы можете использовать это как:
from django.contrib.postgres.aggregates import ArrayAgg
content = Models.objects.values().annotate(
organs=ArrayAgg('organs__pk')
)
return JsonResponse({"data":list(content)})
Использование Django REST framework все же возможно с текущим представлением. Вы можете установить этот фреймворк и определить сериализатор с помощью:
from rest_framework import serializers
class ContentSerializer(serializers.ModelSerializer):
organs = serializers.PrimaryKeyRelatedField(many=True)
class Meta:
model = Content
fields = '__all__'
Затем в представлении вы можете работать с:
contents = Models.objects.prefetch_related('organs')
serializer = ContentSerializer(contents, many=True)
return JsonResponse({'data': serializer.data})
Решение Виллема с использованием DRF корректно, но возвращает только ID связанных полей. Я полагаю, что есть способ изменить это и получить другое поле, но вместо этого я нашел другой способ, не требующий переопределения:
class OrganSerializer(serializers.ModelSerializer):
class Meta:
model = Organ
fields = (('title'),)
class PathologySerializer(serializers.ModelSerializer):
class Meta:
model = Pathology
fields = (('title'),)
class ContentSerializer(serializers.ModelSerializer):
organs = OrganSerializer(many=True, read_only=True)
pathology = PathologySerializer(many=True, read_only=True)
class Meta:
model = Content
fields = '__all__'
Остальная часть решения была точной. Я еще не пробовал PGSQL для продов