Ограничение объема отношений ForeignKey? - PullRequest
2 голосов
/ 21 сентября 2009

Я разрабатываю приложение для портфолио. В этом приложении у меня есть модель под названием «Проект», которая выглядит примерно так:

class Project(models.Model):
    ... 
    images = models.ManyToManyField(Image)
    ...

так что, по сути, этот проект может содержать набор изображений (любое из этих изображений может также принадлежать другому проекту).

Теперь я хотел бы добавить способ указать, что одно из этих «изображений» является «lead_image».

Так что я мог бы добавить что-то вроде этого:

class Project(models.Model):
    ... 
    images = models.ManyToManyField(Image, related_name='images')
    lead_image = models.ForeignKey(Image, related_name='lead_image')
    ...

Однако проблема в том, что в этом случае lead_image может быть ЛЮБОЙ картинкой. Что я действительно хочу, так это чтобы оно было одним из «изображений», принадлежащих этому экземпляру модели.

Я думаю, что мне нужно использовать аргумент "ForeignKey.limit_choices_to", но я не уверен, как его использовать ... тем более, что когда экземпляр модели создается впервые, изображений еще не будет в каталоге "images".

Любая помощь будет очень востребована.

Doug

Ответы [ 2 ]

2 голосов
/ 22 сентября 2009

Если вы хотите добиться ограничивающего эффекта в инструменте администратора , вы можете переопределить метод formfield-for-foreignkey и вставить свой собственный фильтр.

class ProjectAdmin(admin.ModelAdmin):

    # ...

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == "lead_image":
            kwargs["queryset"] = self.model.images.all()
            return db_field.formfield(**kwargs)
        return super(ProjectAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

Проблема, которую я вижу здесь (с этой общей идеей выбора только из выбранных изображений), заключается в том, что для новых моделей изначально модель. Изображения не будут устанавливаться при загрузке страницы. Вы, вероятно, столкнетесь с этой проблемой, независимо от того, какой трюк на стороне сервера вы используете.

Это может работать, но для этого требуется дополнительный щелчок: при первом создании модели модель ManyToMany будет выбрана. После выбора, если нажать «Сохранить и продолжить», эти изображения должны появиться в поле FK model.lead-image.

Другим вариантом будет переопределение формы администратора по умолчанию и создание чего-то настраиваемого (настраиваемого, например, в пользовательском javascript для маскарадных штанов, для автоматического обновления поля со списком 'lead image').

2 голосов
/ 22 сентября 2009

Другой подход к вашей проблеме - использовать промежуточную таблицу с логическим свойством 'is_lead_image'.

class Image(models.Model):
    ...

class Project(models.Model):
    images = models.ManyToManyField(Image, through='ProjectImage')
    ...

class ProjectImage(models.Model):
    image = models.ForeignKey(Image)
    project = models.ForeignKey(Project)
    is_lead_image = models.Boolean(default=False)

    def save(self, *args, **kwargs):
        if self.is_lead_image:
            self._default_manager.filter(project=self.project).update(is_lead_image=False)
        return super(ProjectImage, self).save(*args, **kwargs)

* Примечание. Если вам нравится и у вас есть доступ, вы можете просто добавить поле is_lead_image и сохранить его непосредственно в класс Image.

...