I have a custom django admin page, and I would like to make the two ForeignKey fields optional in the admin interface. I do not want to change the underlying model.
This is the model:
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 is a mixin which provides get_absolute_url)
This is the 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)
As you can see, I have tried to use both formfield_overrides, and formfield_for_foreignkey to set required = False on the FormField, but it is not having the required effect: when attempting to save through the admin interface without setting (that is, leaving the field in its original blank state), the admin interface shows the error ‘This field is required.’
So, my question is: how does one prevent the underlying form from requiring certain fields, while still also setting the choices in formfield_for_foreignkey?
While I’m not sure why
kwargs['required']wouldn’t work, you could always override the admin form with your own form. It hasn’t failed me with magical django admin behavior so it’s a pretty good bet.This would still allow you to modify the
QuerySetvia theformfield_for_foomethods.