我如何检查Field.choices值在同一模型django中是唯一的

时间:2018-11-26 14:01:57

标签: django

我需要用户只能在photo_tipo中选择一张值为'COVER'的照片。

Models.py的一部分

class Listing(models.Model):
...

class Photo(models.Model):
    PHOTO_TIPO_CHOICES = (
            ('GALLERIA', 'Galleria'),
            ('COVER', 'Cover'),
            ('PLANIMETRIA', 'Planimetria'),
    )

    photo_tipo = models.CharField(
        max_length=20,
        choices=PHOTO_TIPO_CHOICES,
        verbose_name='Tipo immagine',
        default='GALLERIA',
    )

    listing = models.ForeignKey(
        Listing, 
        related_name='photos',
        on_delete=models.CASCADE,
        blank=True,
        null=True,
    )

Admin.py的一部分

class PhotoInline(admin.TabularInline):
    model = models.Photo
    readonly_fields = ('image_tag',)


@admin.register(models.Listing)
class ListingAdmin(admin.ModelAdmin):
    inlines = [
        PhotoInline,
    ]

enter image description here

我是否可以通过错误消息控制用户选择,或者如果他已经选择了COVER照片,则可以从选择列表中删除“ COVER”? 我不能在现场使用unique=True,因为所有模特都必须有封面照片。

1 个答案:

答案 0 :(得分:0)

根据建议,我认为您需要为列表管理员实现模型表格。我不确定是否可以使用内联,但这将是这样的:

class ListingAdminForm(forms.ModelForm):
    class Meta:
        model = Listing
        fields = '__all__'

    def clean_photos(self):
        photos = self.cleaned_data['photos']
        cover_photos = [
            photo for photo in photos if photo.photo_tipo == 'COVER'
        ]
        if len(cover_photos) > 1:
            self.add_error('photos', forms.ValidationError('Cannot add more than one cover photo', code='more_than_one_cover'))
        return photos


@admin.register(Listing)
class ListingAdmin(admin.ModelAdmin):
    inlines = [
        PhotoInline,
    ]
    form = ListingAdminForm

如果这不起作用,则可以在表单上创建自定义字段,其中一个用于封面照片,而对于其他类型的照片则只允许一个字段和另一个字段。然后,您必须进行一些验证。

替代方法

通常,当我发现自己在管理员中做过多的工作时,是因为我没有按应有的方式设计模型。

您是否考虑过对模型中的基数进行编码?

class Photo(models.Model):
    title = models.CharField(max_length=100)
    image = models.ImageField()


class Listing(models.Model):
    # Restricted to 1 cover photo by the model, add null=False if required
    cover_photo = models.ForeignKey(Photo, on_delete=models.CASCADE)
    # Multiple photos for gallery allowed
    gallery_photos = models.ManyToManyField(Photo)

这会使您的管理代码更简单吗?