Django Admin: использование пользовательского виджета только для одного поля модели

У меня есть поле DateTimeField в моей модели. Я хотел отобразить его как виджет-флажок на сайте администратора Django. Для этого я создал собственный виджет формы. Однако я не знаю, как использовать свой пользовательский виджет только для одного этого поля.

Документация Django объясняет, как использовать пользовательский виджет для всех полей определенного типа:

class StopAdmin(admin.ModelAdmin):
    formfield_overrides = {
        models.DateTimeField: {'widget': ApproveStopWidget }
    }

Это не достаточно детально, хотя. Я хочу изменить это только для одного поля.

5 ответов

Решение

Создайте пользовательский ModelForm для вашего ModelAdmin и добавьте "виджеты" в его мета-класс, например так:

class StopAdminForm(forms.ModelForm):
  class Meta:
    model = Stop
    widgets = {
      'approve_ts': ApproveStopWidget(),
    }
    fields = '__all__'

class StopAdmin(admin.ModelAdmin):
  form = StopAdminForm

Готово!

Документация для этого вроде неинтуитивно помещена в документы ModelForm, без каких-либо упоминаний об этом, приведенных в документах администратора. Смотрите: Создание форм из моделей

После изучения администратора, поля модели и кода поля формы, я считаю, что единственный способ выполнить то, что я хочу, это создать поле пользовательской модели:

models.py

from django.db import models
from widgets import ApproveStopWidget

class ApproveStopModelField(models.DateTimeField):
    pass

class Stop(models.model):
    # Other fields
    approve_ts = ApproveStopModelField('Approve place', null=True, blank=True)

admin.py

from widgets import ApproveStopWidget
from models import ApproveStopModelField

class StopAdmin(admin.ModelAdmin):
    formfield_overrides = {
        ApproveStopModelField: {'widget': ApproveStopWidget }
    }

Это делает работу.

Пока я оставлю вопрос без ответа, потому что у меня есть привычка пропускать очевидное. Возможно, некоторые умные штаны Django имеют лучшее решение.

Переопределите formfield_for_dbfield следующим образом:

class VehicleAdmin(admin.ModelAdmin):
  search_fields = ["name", "colour"]
  def formfield_for_dbfield(self, db_field, **kwargs):
    if db_field.name == 'colour':
      kwargs['widget'] = ColourChooserWidget
    return super(VehicleAdmin,self).formfield_for_dbfield(db_field,**kwargs)

(ссылка на http://www.kryogenix.org/days/2008/03/28/overriding-a-single-field-in-the-django-admin-using-newforms-admin/)

ModelAdmin.get_changelist_form в Django (self, request, **kwargs) выполнит свою задачу в случае list_editable

class StopAdminForm(forms.ModelForm):
  class Meta:
    model = Stop
    widgets = {
      'approve_ts': ApproveStopWidget(),
    }

class StopAdmin(admin.ModelAdmin):
  form = StopAdminForm

  #just return the ModelForm class StopAdminForm
  def get_changelist_form(self, request, **kwargs):
        return StopAdminForm

Обратитесь к официальной документации Django по этой теме.

Я надеюсь, это поможет

Вы можете изменить виджет только для одного поля, назначив виджет на поле в настраиваемой форме и назначив настраиваемую форму администратору, как показано ниже:

      # "admin.py"

class ProductForm(forms.ModelForm):
    class Meta:
        model = Product
        widgets = {
          'price': PriceWidget(),
        }
        fields = '__all__'

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    form = ProductForm
Другие вопросы по тегам