我有一个自定义的django管理页面,我想在管理界面中使两个ForeignKey字段可选。我不想改变底层模型。
这是模型:
class IncorporationTicket(models.Model, AdminURL):
ordered_by = models.ForeignKey('Organisation', # organisation which ordered this
null = True,
blank = False, # i.e. can only be null as a result of delete
on_delete = models.SET_NULL)
ordered_by_individual = models.ForeignKey('Individual', # individual at organisation which ordered this
null = True,
blank = False, # i.e. can only be null as a result of delete
on_delete = models.SET_NULL)
(AdminURL是一个提供get_absolute_url的mixin)
这是ModelAdmin:
class TicketAdmin(admin.ModelAdmin):
readonly_fields = ('ordered', 'charge', 'amount_paid', 'submitted_on')
formfield_overrides = {
models.ForeignKey: {'required': False},
}
def formfield_for_foreignkey(self, db_field, request, **kwargs):
pk = resolve(request.path).args[0] # the request url should only have one arg, the pk
instance = self.get_object(request, pk)
user = request.user
kwargs['required'] = False # will be passed to every field
if db_field.name == "ordered_by_individual":
# queryset should be a union of (a) individual already set on object (b) individual for current user
## None option is provided by admin interface - just need to let field be optional.
if instance.ordered_by_individual:
kwargs["queryset"] = (
Individual.objects.filter(pk = instance.ordered_by_individual.pk) |
user.individual_set.all())
else: kwargs["queryset"] = user.individual_set.all()
elif db_field.name == "ordered_by":
# queryset should be a union of (a) organisation already set (b) any organisations for which user is authorised
try:
individual = user.individual_set.all()[0]
all_orgs = Organisation.all_organisations_for_which_individual_authorised_to_incorporate(individual)
except:
all_orgs = Organisation.objects.none()
if instance.ordered_by:
kwargs["queryset"] = (
Organisation.objects.filter(pk = instance.ordered_by.pk) |
all_orgs)
else: kwargs["queryset"] = all_orgs
return super(type(self), self).formfield_for_foreignkey(db_field, request, **kwargs)
正如您所看到的,我尝试同时使用formfield_overrides
和formfield_for_foreignkey
在FormField上设置required = False
,但它没有达到要求的效果: when尝试通过管理界面进行保存而不进行设置(即,将字段保留为原始空白状态),管理界面显示错误“此字段是必需的。”
所以,我的问题是:如何阻止基础表单需要某些字段,同时还要在formfield_for_foreignkey
中设置选项?
答案 0 :(得分:4)
虽然我不确定为什么kwargs['required']
不起作用,但您始终可以使用自己的表单覆盖管理表单。它并没有让我失望,因为这是一个非常好的赌注。
class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
self.fields['my_fk_field'].required = False
class Meta:
model = MyModel
class MyAdmin(admin.ModelAdmin):
form = MyForm
这仍然允许您通过QuerySet
方法修改formfield_for_foo
。
答案 1 :(得分:0)
...差不多9年后,在Django v3.1.2中...
blank=True
对我来说很好:
from django.contrib.auth.models import User
owner = models.ForeignKey(User,
related_name="notes",
on_delete=models.CASCADE,
null=True,
blank=True)
(解决方案来自here)