Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

☂️ Adopt generic class based views across all areas of admin (epic) #8365

Open
11 of 12 tasks
lb- opened this issue Apr 15, 2022 · 46 comments
Open
11 of 12 tasks

☂️ Adopt generic class based views across all areas of admin (epic) #8365

lb- opened this issue Apr 15, 2022 · 46 comments

Comments

@lb-
Copy link
Member

lb- commented Apr 15, 2022

It> ☂️ This is an epic / umbrella issue

We will break down individual parts into sub-issues, please work on the sub-issues instead.

Description

  • Wagtail 2.12 added generic class based views for use across Wagtail's admin, which was a progression of existing work to move to class based views where possible
  • This provides the ability for common views to share common logic and behaviour
  • This also provides a way for even more customisation over specific URLs by overriding a specific URL path with your own custom class based view that extends the generic ones
  • This will replace the function views used in other parts of Wagtail currently, or ad-hoc class based views that either use Django's directly or do not
  • The Wagtail generic class based views extend the Django class based views

Implementation (core) - high priority

Implementation (contrib) - medium priority

  • Adopt generic class based views for Form builder wagtail/contrib/forms/views.py
    • we may want to pull up SafePaginateListView into a shared mixin
  • Adopt generic class based views for Site Settings wagtail/contrib/settings/views.py
    • using function based views
  • Adopt generic class based views for Search promotions wagtail/contrib/search_promotions/views.py
  • Adopt generic class based views for Redirects wagtail/contrib/redirects/views.py
  • Simple translation wagtail/contrib/simple_translation/views.py
    • using Django's class based views

Implementation (contrib) - low priority

These areas may not be needed but adding here for completeness without checkboxes. We will likely either not do these ever or split these out to future issues.

  • Adopt generic class based views for ModelAdmin wagtail/contrib/modeladmin/views.py
    • using Wagtail's generic views in most cases, may need to assess the other usage
    • migrating ModelAdmin views to this approach may end up being a large amount of extra overhead due to the different usage of search / filtering Params in the url
    • if we can do this in a way that preserves the existing API it may be ok but tread carefully.
  • Styleguide wagtail/contrib/styleguide/views.py
    • using function view, not a huge priority though - maybe it's worth refactoring into using Template Components also but there is some long term plans that may involve removing this contrib module completely

Additional context

@lb- lb- changed the title Adopt generic class-based views across all areas of admin (epic) Adopt generic class based views across all areas of admin (epic) Apr 15, 2022
@lb- lb- changed the title Adopt generic class based views across all areas of admin (epic) ☂️ Adopt generic class based views across all areas of admin (epic) Apr 20, 2022
@lb-
Copy link
Member Author

lb- commented Apr 22, 2022

#8417

@lb-
Copy link
Member Author

lb- commented Jun 5, 2022

Created three new issues, these would be very helpful to streamline the efforts on UX Unification (GSoC) but not critical

@kaedroho
Copy link
Contributor

kaedroho commented Jun 6, 2022

Thanks for this @lb-!!

I feel like we should drop the styleguide from this, since that view just needs to render a template and I don't think any of our generic views will help with this. Also, simple translation doesn't contain any index/create/edit/delete views so it might not make much sense to make this one generic either.

Modeladmin might be tricky since the way it implements search, filtering and customising the listing is very different to how the generic views currently/will work. If we need to change modeladmin's API in order to make it fit generic views better, I don't think this would be worth it. W plan to make model viewsets easier to use so developers could switch to that if they want this API.

@lb-
Copy link
Member Author

lb- commented Jun 7, 2022

PR for reports index that relates to this.
#8637

Thanks @laymonage !

@lb-
Copy link
Member Author

lb- commented Jun 7, 2022

@kaedroho I have descoped (no longer has checkboxes) the ModelAdmin and styleguide ones and re-grouped these into a low priority section.

Keeping them listed for completeness - hope that is ok.

Let me know if you are aware of any other views in Wagtail that should adopt the shared classes approach.

@lb-
Copy link
Member Author

lb- commented Aug 31, 2023

Note - there is now an RFC for further enhancements to the viewsets system.

wagtail/rfcs#87

Update. This RFC has been closed.

@Temidayo32
Copy link
Contributor

@laymonage @lb-

using function based views, no class based ones at all, may be suitable for viewset

Can I clarify what this means? I'm not sure what is meant here.

@lb-
Copy link
Member Author

lb- commented Oct 4, 2023

@Temidayo32 at the time of creation of this issue, viewsets were still new-ish and didn't support a full range of views. The viewsets system is now quite capable of probably covering all these use cases.

It's also a public facing API. See https://docs.wagtail.org/en/stable/reference/viewsets.html

@Temidayo32
Copy link
Contributor

Temidayo32 commented Oct 4, 2023

@lb- Thanks for the response.

Adopt generic class based views for Redirects wagtail/contrib/redirects/views.py

I intend to work on this above. So if I understand you, wagtail/contrib/redirects/views.py should be refactored using the viewsets, right?

@lb-
Copy link
Member Author

lb- commented Oct 5, 2023

@Temidayo32 yep. I think that's what we would want to do now.

@Temidayo32
Copy link
Contributor

@lb- Alright. Thanks for the clarification

@Chidera6
Copy link

Chidera6 commented Oct 8, 2023

Hi @thibaudcolas @laymonage , I intend working on this issue wagtail/contrib/search_promotions/views.py.

@Chiemezuo
Copy link
Contributor

Chiemezuo commented Oct 8, 2023

@Chidera6 incidentally, I'm trying to get started on the one for redirects wagtail/contrib/redirects/views.py
Is it okay for us to reach out to ourselves if we get stuck?

@Chidera6
Copy link

Chidera6 commented Oct 8, 2023

@Chidera6 incidentally, I'm trying to get started on the one for redirects wagtail/contrib/redirects/views.py Is it okay for us to reach out to ourselves if we get stuck?

That would be very nice @Chiemezuo but I think @Temidayo32 is working on that issue you selected.

@thibaudcolas thibaudcolas added the Outreachy https://www.wagtail.org/outreachy/ label Oct 9, 2023
@thibaudcolas
Copy link
Member

@Temidayo32 @Chidera6 @Chiemezuo just a heads’up we consider this all to be relatively advanced as far as Wagtail contributions go. If you don’t have pre-existing experience with Django and with class-based views, I would recommend you focus on other possible contributions. If you do have this expertise… go for it!

As you approach this please take ample time reviewing other pull requests done in this space, so you get to see how the contributions that we accepted were made.

@Chiemezuo
Copy link
Contributor

Thank you @lb-
Working on that right now.

@Temidayo32
Copy link
Contributor

@Chidera6 Are you still working on wagtail/contrib/search_promotions/views.py?

@Temidayo32
Copy link
Contributor

@thibaudcolas Is there anything left in this issue that I can contribute to? I know Django and want to help.

@tony-nyagah - there are lots of other function based views still needing work.

If you are keen, there is one I have started that may be good to get your help with, there are two FBVs in the images views that we are in the process of doing some clean up on. Some of this clean up would be better enabled by these moving to CBVs.

  • url_generator - This serves a page that lets you create a URL to an image based on the size you want. Similar to how images are used in templates with a filter_spec.
  • generate_url - This serves a JSON response with the generated URL data and is requested from the view above.

Both of these are at same URL, just the second one is based on a different path.

I started looking at using the generic.models.InspectView for this as it contains most of the basics we would need and avoids the added features of EditView.

Some notes.

  • wagtail/images/templates/wagtailimages/images/url_generator.html would need to extend {% extends "wagtailadmin/generic/base.html" %}
  • We can get rid of the title tag there and use the built in title generation from the class views.
  • We would need to move the main content into {% block main_content %} not {% block content %}
  • No need to use the header in that view as this will come from the base template {% include "wagtailadmin/shared/header.html"

Starting point - I think we would just make get_fields return an empty array as we would use the existing Form.

class GenerateURLView(generic.InspectView):
    any_permission_required = ["change"]
    model = get_image_model()
    pk_url_kwarg = "image_id"
    header_icon = "image"
    page_title = gettext_lazy("Generating URL")
    template_name = "wagtailimages/images/url_generator.html"

    def get_page_subtitle(self):
        return self.object.title

    def get_fields(self):
        return []

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        context["form"] = URLGeneratorForm(
            initial={
                "filter_method": "original",
                "width": self.object.width,
                "height": self.object.height,
            }
        )

        return context

This does not consider the other URL (returning JSON) we would want to build into this response, either with a request varies decorator or just logic in the response building.

To see this page in action you can go to edit an image, then click 'URL Generator' under the image preview.

Screenshot 2023-10-26 at 5 50 16 pm Screenshot 2023-10-26 at 5 50 36 pm
For the other related work we are planning to do, see #11045 & #3683

If you are keen for this, let us know, I am happy to split this out to its own issue for further discussion.

I am interested @lb-

@Chidera6
Copy link

@Chidera6 Are you still working on wagtail/contrib/search_promotions/views.py?

Yes, I am still working on it @Temidayo32

@lb-
Copy link
Member Author

lb- commented Oct 26, 2023

@Temidayo32 - I think @tony-nyagah else has already started (image url generator views) so it's best to avoid conflicting PRs for now.

@sharma-ramya
Copy link

sharma-ramya commented Oct 27, 2023

Hi @lb- I know Django and would like to contribute to this issue. Can you let me know what is available to avoid any conflicts with the current allocated tasks?
Can I get started on wagtail/contrib/forms/views.py?
Thanks in advance!

lb- pushed a commit to Chiemezuo/wagtail that referenced this issue Oct 27, 2023
lb- pushed a commit that referenced this issue Oct 27, 2023
@Temidayo32
Copy link
Contributor

This will replace the function views used in other parts of Wagtail currently, or ad-hoc class based views that either use Django's directly or do not

@lb- can you please clarify what is meant by ad-hoc class based views. Perhaps a link to one would be helpful. Thanks.

@lb-
Copy link
Member Author

lb- commented Oct 29, 2023

@Temidayo32 - please note that this issue was created well before the Outreachy program was scoped and before a lot of the recent (last six months) refactoring of Snippets and model viewsets was done.

However, generally, my initial specification for this issue was based on our introduction of more useful view classes that were used throughout Wagtail. This includes the Wagtail admin mixins, the model generic views and the viewsets system.

Some earlier class based views may have been ad-hoc, as in they did not use the shared generic views within Wagtail's code. Instead they would have been built upon Django's classed based views.

Migration needs to be assessed on a case by case basis though. Sometimes we do not need more than the Django base classes go do what's needed. But once we start dealing with models/objects - the Wagtail ones will replace a lot of the boilerplate needed for a consistent UI.

I hope that helps add some context, I do expect that once the Outreachy program starts that this issue will be closed / revised. Along with a new, clearer migration schedule based on a review of what's used throughout the admin currently.

The main goals here are to:

  • A. Avoid duplication for common UI patterns (such as pagination, we have implemented various versions of this in different modules).
  • B. Build on the patterns provided by Django and then use those to provide patterns for those building with Wagtail.
  • C. Make parts of Wagtail easier to customise, maybe not in an officially supported way yet but still have some undocumented escape hatches that Classes provide.

@rohitsrma
Copy link
Contributor

@thibaudcolas Is there anything left in this issue that I can contribute to? I know Django and want to help.

@tony-nyagah - there are lots of other function based views still needing work.

If you are keen, there is one I have started that may be good to get your help with, there are two FBVs in the images views that we are in the process of doing some clean up on. Some of this clean up would be better enabled by these moving to CBVs.

  • url_generator - This serves a page that lets you create a URL to an image based on the size you want. Similar to how images are used in templates with a filter_spec.
  • generate_url - This serves a JSON response with the generated URL data and is requested from the view above.

Both of these are at same URL, just the second one is based on a different path.

I started looking at using the generic.models.InspectView for this as it contains most of the basics we would need and avoids the added features of EditView.

Some notes.

  • wagtail/images/templates/wagtailimages/images/url_generator.html would need to extend {% extends "wagtailadmin/generic/base.html" %}
  • We can get rid of the title tag there and use the built in title generation from the class views.
  • We would need to move the main content into {% block main_content %} not {% block content %}
  • No need to use the header in that view as this will come from the base template {% include "wagtailadmin/shared/header.html"

Starting point - I think we would just make get_fields return an empty array as we would use the existing Form.

class GenerateURLView(generic.InspectView):
    any_permission_required = ["change"]
    model = get_image_model()
    pk_url_kwarg = "image_id"
    header_icon = "image"
    page_title = gettext_lazy("Generating URL")
    template_name = "wagtailimages/images/url_generator.html"

    def get_page_subtitle(self):
        return self.object.title

    def get_fields(self):
        return []

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        context["form"] = URLGeneratorForm(
            initial={
                "filter_method": "original",
                "width": self.object.width,
                "height": self.object.height,
            }
        )

        return context

This does not consider the other URL (returning JSON) we would want to build into this response, either with a request varies decorator or just logic in the response building.

To see this page in action you can go to edit an image, then click 'URL Generator' under the image preview.

Screenshot 2023-10-26 at 5 50 16 pm Screenshot 2023-10-26 at 5 50 36 pm
For the other related work we are planning to do, see #11045 & #3683

If you are keen for this, let us know, I am happy to split this out to its own issue for further discussion.

Hello @lb- , May i work on this?

@lb-
Copy link
Member Author

lb- commented Jan 6, 2024

@rohitsrma - go for it. I don't think @Temidayo32 made progress on the Image url generator views and this is still up for grabs.

@rohitsrma
Copy link
Contributor

Thanks @lb- , I've created a PR #11423 and would appreciate feedback on it.

lb- pushed a commit to rohitsrma/wagtail that referenced this issue Jan 20, 2024
lb- pushed a commit that referenced this issue Jan 20, 2024
- Relates to #8365 (class based views migration)
@thibaudcolas thibaudcolas removed the Outreachy https://www.wagtail.org/outreachy/ label Feb 7, 2024
@thibaudcolas
Copy link
Member

thibaudcolas commented Feb 7, 2024

Reviewing this today, I see the following three items would still need refactoring:

  • Adopt generic class based views for Redirects wagtail/contrib/redirects/views.py
  • Adopt generic class based views for Search promotions wagtail/contrib/search_promotions/views.py
  • Simple translation wagtail/contrib/simple_translation/views.py

@laymonage I believe you might be working on refactoring all three areas as part of Universal listings continued – how do you think those CBV refactorings fit with those UX improvements? I imagine they go hand in hand?

@lb-
Copy link
Member Author

lb- commented Feb 11, 2024

Redirects has a PR up #11035

@rohitsrma
Copy link
Contributor

@lb- , I'm working on refactoring search_promotions/views.py.

@zerolab
Copy link
Contributor

zerolab commented Apr 17, 2024

@lb- it looks like the last remaining bit on this is the simple translation view (wagtail/contrib/simple_translation/views.py) and we can close this epic 🎉

Thank you for putting it together and guiding folks. And to everyone that contributed so far ⭐ 🌟

@laymonage
Copy link
Member

laymonage commented Apr 17, 2024

Thanks all!

#11762 only covers the index view so there are still some other views in the redirects contrib module to be refactored. Same with the search promotions in #11661 (there is #11731).

Not sure about the exact scope of this issue but there are still some views that are function-based and could use some refactoring, although they are not as prominent so we might only consider them as nice-to-haves. Although, it would be cool to at least make them extend WagtailAdminTemplateMixin plus the wagtailadmin/generic/base.html template so we have the standardised breadcrumbs, header icon, etc.

  • wagtail.admin.views.pages.preview.view_draft
    • Could be refactored to extend the generic preview view class, and extracted into a generic view so snippets can also have the "view latest draft" functionality instead of having to preview a specific revision.
  • wagtail.admin.views.pages.create.add_subpage
    • This is the "choose page type" screen when creating new pages.
  • wagtail.admin.views.pages.move.move_choose_destination
  • wagtail.admin.views.pages.move.move_confirm
  • wagtail.admin.views.pages.ordering.set_page_position
    • Not important as this only acts as some sort of API for the client-side code, but if we used CBV it could make it easier if we wanted to add the "custom ordering" feature to non-page models.
  • wagtail.admin.views.pages.copy.copy
  • wagtail.admin.views.pages.revisions.revisions_revert
    • This one has been a pain point whenever we update the page edit view, as this is implemented as an entirely separate view yet uses the same edit template. For snippets, this was done a bit more elegantly by reusing the EditView code combined with the RevisionsRevertMixin to ensure the two never go out-of-sync.
  • wagtail.admin.views.collection_privacy.set_privacy
    • Probably not very important as it's mostly used to render modals.
  • wagtail.admin.views.workflows.enable_workflow
    • Not very important as it's only used for the form action of enabling a disabled workflow, and only returns a redirect.
  • wagtail.admin.views.workflows.usage
    • Would be nice to use the tables UI framework and maybe rework this as a variant of the page usage view.
  • wagtail.admin.views.workflows.remove_workflow
    • Pretty sure we don't expose this at all, in favour of disabling workflows...
  • wagtail.admin.views.workflows.select_task_type
    • Very similar to wagtail.admin.views.pages.create.add_subpage. Could probably share the same template.
  • wagtail.admin.views.workflows.enable_task
    • Not very important as it's only used for the form action of enabling a disabled task, and only returns a redirect.
  • wagtail.contrib.redirects.views.add
  • wagtail.contrib.redirects.views.edit (Refactor redirects edit view to CBV #11860)
  • wagtail.contrib.redirects.views.delete
  • wagtail.contrib.redirects.views.start_import (not sure)
  • wagtail.contrib.redirects.views.process_import (not sure)
  • wagtail.images.views.images.add (unused in favour of the multiple add view)
  • wagtail.images.views.images.edit
  • wagtail.documents.views.documents.add (unused in favour of the multiple add view)
  • wagtail.documents.views.documents.edit
  • wagtail.contrib.search_promotions.views.add
  • wagtail.contrib.search_promotions.views.edit
  • wagtail.contrib.search_promotions.views.delete
  • wagtail.contrib.search_promotions.views.chooser

Not included, mostly straightforward/intermediary views

  • wagtail.embeds.views.chooser.chooser
  • wagtail.embeds.views.chooser.chooser_upload
  • wagtail.admin.views.bulk_action.dispatcher.index
  • wagtail.admin.workflows.views.task_chosen
  • wagtail.contrib.search_promotions.views.chooserresults
  • wagtail.contrib.forms.views.get_submissions_list_view (form submissions listing entrypoint)
  • wagtail.contrib.settings.views.redirect_to_relevant_instance (wagtailsettings entrypoint)
  • wagtail.images.views.images.preview
  • "serve" views (i.e. pages, documents, images)

I think that's it but I might've missed a few.

If anyone is keen to continue the work: if you're not familiar with the recent adoption of generic views (with breadcrumbs etc.), I highly recommend starting off with one view first. Iterate on a PR until you get a sense of how the generic views and templates work and how they're used throughout the admin. Once you get a PR in, and have a good sense of the views and templates, refactoring multiple related views in the same PR is fine. Recent examples:

Also, some of the views that have been migrated to use class-based views may not already:

  • extend the suitable generic views (from wagtail.admin.views.generic or at the very least, WagtailAdminTemplateMixin)
  • extend the corresponding template (or at the very least, wagtailadmin/generic/base.html)

So there are still work to be done for such views.

To add, some of the views already extend the generic ones but haven't been wrapped in a viewset. These include:

  • wagtail.admin.views.collections -> should have CollectionViewSet
  • wagtail.admin.views.workflows -> should have WorkflowViewSet and TaskViewSet
  • wagtail.contrib.redirects.views -> should have RedirectViewSet
  • wagtail.contrib.search_promotions.views -> should have QueryViewSet
  • wagtail.documents.views -> should have DocumentViewSet
  • wagtail.images.views -> should have ImageViewSet

A recent example of wrapping such views in a viewset can be seen in:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests