Django: фильтровать первые элементы на основе ForeignKey

#python #django

#python #django

Вопрос:

Допустим, у меня есть эти модели (MariaDB):

 class MediaSeries(models.Model):
    name = models.CharField(max_length=200)
    description = models.TextField(blank=True)


class MediaFiles(models.Model):
    entryNr = models.IntegerField(default=0, help_text="number of episode")
    name = models.CharField(max_length=300)
    serie = models.ForeignKey(MediaSeries, null=True,
                              on_delete=models.SET_DEFAULT)
  

Медиафайлы могут быть одной записью или частью серии. Когда он является частью серии, он будет иметь уникальный entryNr .
entryNr может начинаться с любого числа, а не только с 1.

Теперь мне нужен метод фильтрации для фильтрации всех записей медиафайлов, которые являются частью серии, но только первой записи.

Например, у меня есть этот необработанный список:

 {"entryNr": 0, "name": "test a1", "serie": 0},
{"entryNr": 2, "name": "test b1", "serie": 1},
{"entryNr": 3, "name": "test b2", "serie": 1},
{"entryNr": 4, "name": "test b3", "serie": 1},
{"entryNr": 1, "name": "test c1", "serie": 2},
{"entryNr": 2, "name": "test b1", "serie": 2},
{"entryNr": 5, "name": "test d1", "serie": 3},
{"entryNr": 6, "name": "test d2", "serie": 3},
{"entryNr": 7, "name": "test d3", "serie": 3},
{"entryNr": 0, "name": "test e1", "serie": 0},
{"entryNr": 0, "name": "test f1", "serie": 0}
  

И результат, который мне нужен, должен быть:

 {"entryNr": 2, "name": "test b1", "serie": 1},
{"entryNr": 1, "name": "test c1", "serie": 2},
{"entryNr": 5, "name": "test d1", "serie": 3}
  

С моим текущим представлением и фильтрующим классом я уже могу фильтровать все, что является частью серии:

 class MediaFilesFilter(filters.FilterSet):
    serie__isnull = filters.BooleanFilter(field_name='serie_id',
                                          lookup_expr='isnull')

    class Meta:
        model = MediaFiles
        fields = ['id', 'name', 'serie__isnull',]


class MediaFilesViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows media to be viewed.
    """
    queryset = MediaFiles.objects.all().order_by('name')
    serializer_class = MediaFilesSerializer
    filter_backends = (filters.DjangoFilterBackend, OrderingFilter,
                       SearchFilter)
    filterset_class = MediaFilesFilter
  

Но как я могу отфильтровать все первые записи мультимедиа в серии?

Только в качестве информации: логика дыры, которую мне нужно использовать позже с rest_framework, но я думаю, что здесь это не так актуально.

Ответ №1:

Вам придется использовать raw метод для такого сложного запроса:

 MediaFiles.objects.raw("""
SELECT *
FROM my_project_mediafiles mf
  INNER JOIN
    (
      SELECT serie_id, MIN(entryNr) minEntryNr
      FROM my_project_mediafiles
      GROUP BY serie_id
    ) min_tbl
  ON min_tbl.serie_id = mf.serie_id
WHERE mf.entryNr = minEntryNr
""")
  

ПРИМЕЧАНИЕ: я не уверен, каково MediaFiles имя вашей таблицы, оно должно быть «{project_name}_mediafiles»

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

1. Спасибо! Но совместимо ли это с другими фильтрами? Мне нужен общий способ, с помощью которого я мог бы динамично комбинировать этот выбор с другими фильтрами.