Запрос в порядке следования многих ко многим полям по первому связанному объекту

в django я хочу сделать запрос в поле many to many, которое упорядочено по первому связанному объекту. это означает, что набор запросов должен искать объекты в первом месте many to many объектов, а затем остальные.

в качестве простого некорректного примера я хочу получить объекты следующего вида:

queryset = Practitioner.objects.filter(practices__0__city__slug='toronto')
queryset += Practitioner.objects.filter(practices__other__except__0__city__slug='toronto')

Примечание: practices является ManyToManyField моделью Practice в Practitioner модели

А ManyToManyField не имеет порядка. Как и любой запрос без столбца для упорядочивания, база данных может возвращать записи в произвольном порядке, причем при каждом запросе он будет разным.

Если вы хотите добавить заказ (или, например, что-то вроде практики "по умолчанию", вы можете добавить это в таблицу перекрестков). Например:

from django.db import models


class City(models.Model):
    slug = models.SlugField()
    # …


class Practice(models.Model):
    city = models.ForeignKey(City, on_delete=models.PROTECT)


class Practitioner(models.Model):
    practices = models.ManyToManyField(Practice, through='PractitionerPractice')


class PractitionerPractice(models.Model):
    practitioner = models.ForeignKey(Practitioner, on_delete=models.CASCADE)
    practice = models.ForeignKey(Practice, on_delete=models.CASCADE)
    standard = models.BooleanField(default=False)

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=('practitioner',),
                condition=models.Q(standard=True),
                name='one_standard',
            )
        ]

На уровне базы данных каждый UniqueConstraint [Django-doc] может гарантировать, что Practitioner только один Practice будет указан как standard=True один.

В этом случае мы можем получить запрос с помощью:

Practitioner.objects.filter(practices__city__slug='toronto').order_by(
    '-practitionerPractice__standard'
)
Вернуться на верх