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