mirror of
https://github.com/Hopiu/wagtail.git
synced 2026-05-15 18:53:18 +00:00
85 lines
3.1 KiB
Python
85 lines
3.1 KiB
Python
import copy
|
|
|
|
from django.db import models
|
|
from modelcluster.forms import ClusterForm, ClusterFormMetaclass
|
|
from taggit.managers import TaggableManager
|
|
|
|
from wagtail.admin import widgets
|
|
|
|
|
|
# Form field properties to override whenever we encounter a model field
|
|
# that matches one of these types - including subclasses
|
|
FORM_FIELD_OVERRIDES = {
|
|
models.DateField: {'widget': widgets.AdminDateInput},
|
|
models.TimeField: {'widget': widgets.AdminTimeInput},
|
|
models.DateTimeField: {'widget': widgets.AdminDateTimeInput},
|
|
TaggableManager: {'widget': widgets.AdminTagWidget},
|
|
}
|
|
|
|
# Form field properties to override whenever we encounter a model field
|
|
# that matches one of these types exactly, ignoring subclasses.
|
|
# (This allows us to override the widget for models.TextField, but leave
|
|
# the RichTextField widget alone)
|
|
DIRECT_FORM_FIELD_OVERRIDES = {
|
|
models.TextField: {'widget': widgets.AdminAutoHeightTextInput},
|
|
}
|
|
|
|
|
|
# Callback to allow us to override the default form fields provided for each model field.
|
|
def formfield_for_dbfield(db_field, **kwargs):
|
|
# adapted from django/contrib/admin/options.py
|
|
|
|
overrides = None
|
|
|
|
# If we've got overrides for the formfield defined, use 'em. **kwargs
|
|
# passed to formfield_for_dbfield override the defaults.
|
|
if db_field.__class__ in DIRECT_FORM_FIELD_OVERRIDES:
|
|
overrides = DIRECT_FORM_FIELD_OVERRIDES[db_field.__class__]
|
|
else:
|
|
for klass in db_field.__class__.mro():
|
|
if klass in FORM_FIELD_OVERRIDES:
|
|
overrides = FORM_FIELD_OVERRIDES[klass]
|
|
break
|
|
|
|
if overrides:
|
|
kwargs = dict(copy.deepcopy(overrides), **kwargs)
|
|
|
|
return db_field.formfield(**kwargs)
|
|
|
|
|
|
class WagtailAdminModelFormMetaclass(ClusterFormMetaclass):
|
|
# Override the behaviour of the regular ModelForm metaclass -
|
|
# which handles the translation of model fields to form fields -
|
|
# to use our own formfield_for_dbfield function to do that translation.
|
|
# This is done by sneaking a formfield_callback property into the class
|
|
# being defined (unless the class already provides a formfield_callback
|
|
# of its own).
|
|
|
|
# while we're at it, we'll also set extra_form_count to 0, as we're creating
|
|
# extra forms in JS
|
|
extra_form_count = 0
|
|
|
|
def __new__(cls, name, bases, attrs):
|
|
if 'formfield_callback' not in attrs or attrs['formfield_callback'] is None:
|
|
attrs['formfield_callback'] = formfield_for_dbfield
|
|
|
|
new_class = super(WagtailAdminModelFormMetaclass, cls).__new__(cls, name, bases, attrs)
|
|
return new_class
|
|
|
|
@classmethod
|
|
def child_form(cls):
|
|
return WagtailAdminModelForm
|
|
|
|
|
|
class WagtailAdminModelForm(ClusterForm, metaclass=WagtailAdminModelFormMetaclass):
|
|
@property
|
|
def media(self):
|
|
# Include media from formsets forms. This allow StreamField in InlinePanel for example.
|
|
media = super().media
|
|
for formset in self.formsets.values():
|
|
media += formset.media
|
|
return media
|
|
|
|
|
|
# Now, any model forms built off WagtailAdminModelForm instead of ModelForm should pick up
|
|
# the nice form fields defined in FORM_FIELD_OVERRIDES.
|