2011-12-30 2 views
2

У меня есть пользовательская страница администрирования django, и я хотел бы сделать два поля ForeignKey необязательными в интерфейсе администратора. Я не хочу менять базовую модель.Сделать ForeignKey необязательным в Django Admin?

Это модель:

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?

ответ

3

Хотя я не уверен, почему 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 методов.

+0

@ Марцин, не так ли? Это особая цель 'formfield_for_foreignkey', чтобы переопределить форму. –

+0

Фактическое тестирование показывает, что набор запросов, заданный в 'formfield_for_foreignkey', переопределяется настройками по умолчанию в пользовательской форме. – Marcin

+1

@Marcin это уже не внешний ключ, поэтому нам нужен другой крючок. Альтернативно, как насчет вышеизложенного? Установите обязательный атрибут поля в форме переопределения, и пусть django свяжет это поле с 'models.ForeignKey', поэтому администратор позволяет вам использовать крюк' formfield_for_foreignkey' –

Смежные вопросы