Сделать ForeignKey необязательным в Django Admin? - PullRequest
3 голосов
/ 30 декабря 2011

У меня есть пользовательская страница администратора 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)

Это 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 для установки required = False в FormField, но это не дает требуемого эффекта: при попытке сохранения через администратор интерфейс без настройки (то есть, оставляя поле в исходном пустом состоянии), интерфейс администратора показывает ошибку «Это поле обязательно для заполнения».

Итак, мой вопрос: как можно запретить базовой форме требовать определенных полей, в то же время задавая варианты в formfield_for_foreignkey?

1 Ответ

4 голосов
/ 30 декабря 2011

Хотя я не уверен, почему kwargs['required'] не будет работать, вы всегда можете переопределить форму администратора своей собственной формой.Меня не подвела магическое поведение администратора django, так что это довольно хорошая ставка.

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.

...