Построить Django "ForeignKey", который возвращает несколько значений

Я хотел бы создать новый связанный тип поля. Вот простой пример:

class CustomQuerySet(QuerySet):
    def current(self):
        return self.filter(invalid_date__isnull=True)

class CustomManager(Manager):
    def get_query_set(self):
        return CustomQuerySet(self.model, using=self._db)
    def current(self):
        return self.get_query_set().current()

class Item(models.Model):
    objects = CustomManager()

    row_id = models.IntegerField(primary_key=True)
    id = models.IntegerField()
    name = models.CharField(max_length=100)
    change_date = models.DateTimeField(auto_now_add=True)
    invalid_date = models.DateTimeField(null=True, blank=True)


class Collection(models.Model):
    item = MultipleRelatedField(Item, related_field='id', related_name='collections')
    name = models.CharField(max_length=100)

Дано c = Collection():

  • c.item должен вернуть набор запросов, эквивалентный Item.objects.filter(id=c.item_id),
  • Этот набор запросов должен быть экземпляром CustomQuerySet
  • Item.objects.filter(collections__name='SomeName') должен работать как положено.
  • Операция Collection.objects.filter(item__name='OtherName', item__invalid_date__isnull=True) должен работать как положено.

Я понимаю, что это может быть реализовано с ManyToManyField но я не хочу вручную добавлять / удалять объекты предметов в c.item. Мне не нужна таблица соединений, поскольку c.item всегда использует одно значение id, это просто не первичный ключ в Collection. А также c.item может / не / содержать объекты предметов с разными значениями идентификатора.

Я знаю, что это, вероятно, будет требовать подклассов django.db.models.fields.related.ForeignRelatedObjectsDescriptor и / или django.db.models.fields.related.ForeignObject (или, возможно, эквиваленты ManyToMany).

1 ответ

Мне кажется, что вы действительно хотите, это автоматический способ создания набора запросов из модели A против другой модели B основанный на значении поля в A,

Я подозреваю, что в конечном итоге, возвращая этот набор запросов в качестве значения поля на A на самом деле это не лучшее решение - это действительно идет вразрез с ORM и затруднит, например, использование этой модели в админке или других местах общего пользования.

Вместо этого было бы лучше взять идею из того, как Django обрабатывает поля с choices set: автоматически генерировать метод в классе модели, который возвращает производную информацию, например, если ваша модель имеет поле:

item = MultipleRelatedField(Item, related_field='id', related_name='collections')

вы бы автоматически получили такой метод, как get_item_queryset это вернет указанный вами набор запросов.

Чтобы построить это, вы, вероятно, захотите создать подкласс существующего поля (IntegerField будет хорошей отправной точкой), а затем переопределить __init__ метод (чтобы принять дополнительные аргументы) и contribute_to_class метод (где новый метод будет создан). Вы можете увидеть место, где это происходит для choices -derived get_FIELD_display метод здесь для вдохновения.

Другие вопросы по тегам