django-formtools
django-formtools copied to clipboard
Admin support
This is a feature request basically just to start a conversation on the matter.
Especially with the new admin look, the admin is ideal for simple (or not) data entry. I think that having django-formtools available in the admin would provide some much needed logic and customization potential for developers.
Even though the last time I meddled with the admin I found it a troubling procedure, I think it is worth giving it a try when I have some time.
Also, please do share directions or similar efforts having been done already by others
You just need to override the get_urls method of the model admin.
Yes, you can override the get_urls method... But it seems that you have to do many things to integrate a wizard in the admin views, so that it looks like a normal admin view.
Yes, I agree. In particular, I didn't enjoy rendering the formwizard as an action. Also, manually setting the RelatedFieldWidgetWrapper was not fun. Too many hacks were needed. What might be the best way?
Please could you be post a sample about how to integrate formtools in django admin? Thank you
Sure.
class FormWizardAdmin(admin.ModelAdmin):
def get_urls(self):
urls = super().get_urls()
view = FormWizardView.as_view()
add_url = url(
r"add/$", self.admin_site.admin_view(view), name="formwizard_add"
)
change_url = url(
r"^(.+)/change/$",
self.admin_site.admin_view(view),
name="formwizard_change",
)
return [add_url, change_url] + urls
Getting the form wizard to play nicely with the Django admin is definitely a lot harder than it should be. I think the problem is largely due to the complexities of Django's ModelAdmin. Some things I've learned from playing around with it.
- If you don't want to mess with
get_urlsyou can be specific by overriding the various*_viewmethods - If you want to your formwizard template to extend the Django admin base templates (eg
{% extends "admin/change_form.html" %}), you need to provideextra_contextto the WizardView (to be injected into the templates), specifically I needed to include'opts'(for breadcrumbs and other things) and'media'(for scripts, popups, foreignkey widgets) as shown below. - The ModelAdmin's auto-generated forms are available through
self.get_form, but they're quite hard to use on their own since they require all sorts of support fromModelAdmin. I ended up manually building the ModelForm usingmodelform_factoryand then messing around with it to add support forreadonly_fields. Your mileage may vary. - Inlines don't work out of the box. I suspect you could get them working, but I haven't dug too deeply yet.
class FormWizardAdmin(admin.ModelAdmin):
def add_view(self, request, form_url="", extra_context=None):
view = MyWizardView.as_view(
extra_context={"opts": self.model._meta, "media": self.media},
form_list=[Form1, self.get_add_form(request)],
)
return view(request)
def get_add_form(self, request):
form = modelform_factory(
self.model,
fields=flatten_fieldsets(self.get_fieldsets(request)),
formfield_callback=lambda field: self.formfield_for_dbfield(field, request),
)
# Django's implementation of readonly is pretty complicated.
# This is simple enough and worked for my usecase
for field_name in self.readonly_fields:
form.base_fields[field_name].widget.attrs["readonly"] = True
return form