Roadmap: django-polymorphic

Roadmap: django-polymorphic

This is an update for everyone on how I’m thinking about and prioritizing work on this library so you may make decisions about continuing to use it based on more than nothing.

The first version of django-polymorphic was released 15 years ago in 2011. There are many users of this library and it runs in production systems around the world - per PyPi statistics it is not unreasonable to assume that somewhere approaching 5% of production Django systems depend on this library. During that time it has been supported by 6 different maintainers (@bconstantin @vdboor @chrisglass @jleclanche @meshy with me being the most recent) and over 125 individual contributors.

Maintaining open source is difficult. Volunteers burn out, get busy or have life changes that pull them away. There was a period of ~4 years where this library was essentially unmaintained. The Django/Python ecosystem marched on and things started to break. When I was granted maintainership there were 163 open issues and 16 open PRs - the oldest dating back 14 years.

Move to django-commons

This project was moved into jazzband not that long ago. Unfortunately the move took place without an identified maintainer so it languished for a few years without a successful update. The jazzband has been a true boon to the Django ecosystem over the years but I think this move is necessary for the health of this library for several reasons:

  1. I maintain several other packages at django-commons so its just going to be easier for me to unify all my Django package workflows under a common organization.
  2. I still have not been able to get a successful release through the jazzband process. and moving to django-commons would enable trusted publishing through backbone infrastructure in a way that I believe is just more secure. Right now I am publishing directly through my own PyPi account which is not ideal.
  3. If something happened to me this project would be stuck again with nobody in position to issue releases. django-commons has 5 active admins to jazzband’s overstretched single admin. This means if something happened to me there would be 5 people able to grant maintainership to someone else.

I do not have admin rights to this repo, nor do I have full admin rights to the pypi repository. This move will be hard to coordinate as we will need to get help from at least @jezdez @vdboor or @chrisglass. Please be patient.

Additional Maintainer

I would like to find at least one other additional maintainer with publish privileges. This will likely not move forward until the move to django-commons is complete. Given where I would like to take this library (see below) if you have experience in the guts of Django’s ORM that would be extremely helpful! Otherwise - for trust - you would need an established record in the open source Django ecosystem. The best way to help right now is to pick off issues by opening PRs - I promise to look at them within a reasonable amount of time!

Progress So Far

  • I have closed around 70 issues and merged around 15 outstanding PRs. Most of these issues were longstanding bug fixes. Many issues were duplicates or were addressing bugs that were fixed without the issue having been closed. For specific bug reports I have been adding matching tests and closing the issue if the tests pass. I ask for your continued patience because this is a very laborious process - no PR was merged without changes. Most merged PRs have included bug fixes. See the changelog for a comprehensive list. A few notable improvements include:
    1. Polymorphic QuerySet iteration now produces dramatically fewer SQL queries.
    2. A create_from_super method was added to Polymorphic managers that provides a shortcut for “promoting” an existing model row to a direct subclass of that model. This was the longest standing open PR (from 2013!).
    3. Q objects are no longer deepcopied by the PolymorphicQueryset. This eliminates spurious failures that some users were encountering.
    4. Many admin bug fixes.
  • Code coverage has increased by ~7%.
  • I have enabled discussions and for issues that were how-to-like questions I have been moving them into Q&A. If I have answered your question satisfactorily please accept the answer. The intention is for Q&A to function as an FAQ.
  • Packaging has been modernized:
    1. uv is now the package manager.
    2. just has implemented many package management shortcuts.
    3. CI runs on all Django supported RDBMS and more combinations of supported dependencies.
    4. Admin tests now test full integration (including the delivered javascript) using playwright

Roadmap

I am cognizant that there are many outstanding bugs in this library and for users that have invested in its existing functionality fixing these should and will be be my top priority. The focus of the version 4.x series will be fixing those bugs while maintaining backwards compatibility. For version 5.x I would like to take a deeper look at how django-polymorphic works and determine if there are some fundamental changes that might notably increase its performance or simplify the implementation in ways that address the longstanding lack of support for selected_related and prefetch_related.

The current design of django-polymorphic is mostly a manager/queryset extension. It basically works by storing the most-derived leaf class ContentType on the parent table(s). When queries are made a second step uses those ContentTypes to run an additional query (or queries) if there are more derived tables for any model in the queryset. This works, is performant enough for most workflows, and is aligned with how most users would implement polymorphism themselves - but there may be deeper tie-ins to the Django ORM that could replace the 2-phase process with a single step process.

I want to acknowledge that of all the outstanding PRs those by @pgammans (Fix proxy model support. #676 and Related polymorphic query support inc select_related and prefetch_related #545) were the most thorough and impactful but they are the only two outstanding PRs I have not merged yet. I am delaying proxy model changes (Fix proxy model support. #676) to version 5.x because there will be breaking changes. The current proxy model support is unintuitive and, I think, incongruous with the intent of proxy models in Django. I did not see a way to offer backwards compatibility with the current behavior without requiring users to change their code. I am delaying select_related and prefetch_related support (Fix proxy model support. #676) until I can do a more thorough review of the library’s architecture and I do not want to publish an interface that might be immediately deprecated in the next release. Thank you @pgammans - I promise these PRs will not languish forever!

Version 4.x

The last 4.x release will coincide with a Django LTS release (hopefully 6.2) to give users a solid 3 years to migrate to 5.x.

In priority order, with some issue links these are my areas of focus. Each block will be a release containing fixes in a related area. This should help users more easily identify the source of regressions if they arise and help keep me sane as I work through the backlog.

The best way for folks to help right now is to pick out open issues and open PRs that have tests and fixes! I will happily accept and work on PRs that have tests illustrating bugs without the fixes in place yet!

Version 5.x

Version 5.x will include a significant scope of refactoring and potential breaking changes.

Please hold some grace for me and the other contributors to this library. Coming updates will likely trigger regressions. This is unavoidable to make progress and that progress lies at the feet of volunteers who are not remunerated for this work.