django-formtools icon indicating copy to clipboard operation
django-formtools copied to clipboard

Admin support

Open alekosot opened this issue 9 years ago • 6 comments

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

alekosot avatar Sep 15 '16 12:09 alekosot

You just need to override the get_urls method of the model admin.

globophobe avatar Sep 22 '16 10:09 globophobe

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.

jedie avatar Sep 28 '16 12:09 jedie

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?

globophobe avatar Sep 28 '16 13:09 globophobe

Please could you be post a sample about how to integrate formtools in django admin? Thank you

pyMan avatar Jul 17 '19 14:07 pyMan

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

globophobe avatar Jul 20 '19 06:07 globophobe

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_urls you can be specific by overriding the various *_view methods
  • If you want to your formwizard template to extend the Django admin base templates (eg {% extends "admin/change_form.html" %}), you need to provide extra_context to 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 from ModelAdmin. I ended up manually building the ModelForm using modelform_factory and then messing around with it to add support for readonly_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

JEphron avatar Mar 31 '20 19:03 JEphron