怎么能让一个ForeignKey('self')的管理员禁用自己呢?

时间:2016-06-21 14:15:04

标签: django django-admin

我有一个带有forgein键的模型。例如:

class Folder(models.Model):
    name = models.CharField()
    parent_folder = models.ForeignKey('self', null=True, blank=True, default=None, on_delete=models.CASCADE)

出于我的目的,我从不希望parent_folder引用自身,但此模型的默认管理界面允许用户选择自己的实例。我怎么能阻止这种情况发生?

编辑:如果您尝试进行分层树状布局,就像我一样,您需要注意的另一件事是圆形父关系。 (例如,A的父母是B,B的父母是C,C的父母是A.)避免这不是这个问题的一部分,但我想我会把它作为一个提示。

2 个答案:

答案 0 :(得分:3)

我个人会在模型级别这样做,所以如果你以另一种形式重用模型,你也会遇到错误:

class Folder(models.Model):
    name = models.CharField()
    parent_folder = models.ForeignKey('self', null=True, blank=True, default=None, on_delete=models.CASCADE)

    def clean(self):
        if self.parent_folder == self:
            raise ValidationError("A folder can't be its own parent")

如果在表单中使用此模型,请使用查询集,以便不显示模型本身:

class FolderForm(forms.ModelForm):

    class Meta:
        model = Folder
        fields = ('name','parent_folder')

    def __init__(self, *args, **kwargs):
        super(FolderForm, self).__init__(*args, **kwargs)
        if hasattr(self, 'instance') and hasattr(self.instance, 'id'):
            self.fields['parent_folder'].queryset = Folder.objects.exclude(id=self.instance.id)

答案 1 :(得分:1)

要确保用户在填写外键字段时没有选择相同的实例,请在管理表单中实施拒绝该错误值的clean_FIELDNAME方法。

在此示例中,模型为Folder,外键为parent_folder

from django import forms
from django.contrib import admin
from .models import Folder

class FolderAdminForm(forms.ModelForm):
    def clean_parent_folder(self):
        if self.cleaned_data["parent_folder"] is None:
            return None
        if self.cleaned_data["parent_folder"].id == self.instance.id:
            raise forms.ValidationError("Invalid parent folder, cannot be itself", code="invalid_parent_folder")
        return self.cleaned_data["parent_folder"]

class FolderAdmin(admin.ModelAdmin):
    form = FolderAdminForm

admin.site.register(Folder, FolderAdmin)

编辑:将我的答案与raphv's answer相结合,以获得最大效果。