Django Rest Framework — фильтровать поля вложенных отношений

#python #django #django-rest-framework #django-serializer

#python #django #django-rest-framework #django-сериализатор

Вопрос:

Я хочу вернуть вложенное представление объектов Customer with Image , где Customer может быть много Images .

В настоящее время запрос GET возвращает список ВСЕХ изображений из Image набора запросов для каждого Customer объекта, как показано ниже. Как я могу вместо этого показывать только связанные Image (ы) для каждого Customer объекта в списке?

 # The 'images' field currently returns all images rather than related images to the customer id.
[
   {
       'id': 1,
       'name': 'John Doe',
       'images': [
           {'id': 1, 'name': 'foo.jpg', 'customer': 1},
           {'id': 2, 'name': 'bar.jpg', 'customer': 2},
           {'id': 3, 'name': 'foobar.jpg', 'customer': 3},
           ...
       ]
   },
   {
       'id': 2,
       'name': 'Jane Doe',
       'images': [
           {'id': 1, 'name': 'foo.jpg', 'customer': 1},
           {'id': 2, 'name': 'bar.jpg', 'customer': 2},
           {'id': 3, 'name': 'foobar.jpg', 'customer': 3},
           ...
       ]
   },
   ...
]

  

Это моя текущая настройка

Примеры моделей

 class Customer(models.Model):
      name = models.CharField()

class Image(models.Model):
      name = models.CharField()
      customer = models.ForeignKey(
        Customer, on_delete=models.CASCADE)
  

Примеры сериализаторов

 class CustomerSerializer(serializers.ModelSerializer):
    # My Customer nested relationship is expressed using ImageSerializer as a field
    images = ImageSerializer(many=True)

    class Meta:
        model = Customer
        fields = ('id', 'name', 'images')
        read_only_fields = ('id',)

class ImageSerializer(serializers.ModelSerializer):
    class Meta:
        model = Image
        fields = '__all__'
        read_only_fields = ('id',)
  

Пожалуйста, дайте мне знать, если мой вопрос неясен, и я обновлю свой вопрос. Спасибо.

Ответ №1:

Вам нужно использовать связанное имя в качестве поля для обратного внешнего ключа.

В вашем случае это было бы;

 class CustomerSerializer(serializers.ModelSerializer):

    class Meta:
        model = Customer
        fields = ('id', 'name', 'image_set')
        read_only_fields = ('id',)
  

Рассматривайте это как обратный FK-запрос — Customer.objects.first().image_set.all()


Документы DRF по этому вопросу находятся здесь; Обратные отношения

Документы Django по изменению отношений находятся здесь


Использование _set обратного поиска, подобного этому, используется в django по умолчанию. Возможно, вы можете добавить свои собственные related_name к отношениям.

Пример из документов django;

 # Declare the ForeignKey with related_query_name
class Tag(models.Model):
    article = models.ForeignKey(
        Article,
        on_delete=models.CASCADE,
        related_name="tags",
        related_query_name="tag",
    )
    name = models.CharField(max_length=255)

# That's now the name of the reverse filter
Article.objects.filter(tag__name="important")
  

Для вашего примера вы могли бы добавить что-то вроде;

 class Image(models.Model):
    name = models.CharField()
    customer = models.ForeignKey(
        Customer,
        on_delete=models.CASCADE,
        related_name="images"
    )
  

По умолчанию django Customer.image_set все равно будет работать, но вы можете это сделать, Customer.images.all() потому что вы определили это related_name для отношений.

Комментарии:

1. Спасибо, Марк. Раньше я не знал об обратных связях DRF. Спасибо за помощь.