Opened 3 weeks ago
Last modified 8 days ago
#36708 assigned Cleanup/optimization
`formset` not a static attribute of `ChangeList`
| Reported by: | Ben Gregory | Owned by: | Rudraksha Dwivedi |
|---|---|---|---|
| Component: | contrib.admin | Version: | dev |
| Severity: | Normal | Keywords: | ChangeList |
| Cc: | Antoliny | Triage Stage: | Accepted |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | yes | UI/UX: | no |
Description
The ChangeList class is used in Django Admin to determine and configure the functionality of a model's change_list admin page.
I have been experimenting with using ChangeList for my own purposes, to create a custom page not dissimilar to change_list.html.
I have noted that in doing so, I have needed to set the attribute formset = None on my ChangeList instance, to satisfy an expectation of the admin_list.result_list template tag. This is because formset is not a static attribute of the class.
Looking at the source code, the `django.contrib.admin.options` module sets formset on the ChangeList instance.
Outside of tests, ChangeList objects are only instantiated in the above module, and as said above, will always be assigned a formset attribute. See here. So, it appears to me that there is an assumption that instances of this class should _always_ have a formset attribute.
I propose we simply make formset an attribute of ChangeList, rather than assign it dynamically in the aforementioned function. This will mean developers working low-level in the admin needn't write a line of code to be able to use their custom ChangeList objects with the relevant template tags, and will serve to better document the expected attributes of ChangeList objects more generally.
Proposal:
+ formset = None
- formset = cl.formset = None + formset = None
One could also argue that this is an opportunity to remove this notation formset = cl.formset = *, and use cl.formset directly.
Change History (12)
comment:1 by , 3 weeks ago
| Cc: | added |
|---|---|
| Keywords: | ChangeList added |
comment:2 by , 3 weeks ago
| Easy pickings: | set |
|---|---|
| Triage Stage: | Unreviewed → Accepted |
| Version: | 5.2 → dev |
Thanks for the report. And thanks Antoliny for the triage, I trust your view on admin issues :-)
Looks like this may be the issue from #13039, but I'm happy to keep this issue open instead of reopening there.
Ben, would you like to submit a PR?
comment:3 by , 9 days ago
PR submitted: https://github.com/django/django/pull/20184
I think it addresses the issue aptly, I shall set the Has patch to yes
comment:4 by , 9 days ago
| Has patch: | set |
|---|
comment:5 by , 9 days ago
| Owner: | changed from to |
|---|
comment:6 by , 9 days ago
| Patch needs improvement: | set |
|---|
follow-up: 8 comment:7 by , 9 days ago
can someone shed some light on the flake8 test on the automated github testing flow ?
i think the issue is solved but some linting test fail
so i am not setting needs improvement to no currently
thank you!
follow-up: 9 comment:8 by , 9 days ago
Replying to Rudraksha Dwivedi:
can someone shed some light on the flake8 test on the automated github testing flow ?
i think the issue is solved but some linting test fail
so i am not setting needs improvement to no currently
thank you!
Would you like to refer to this document?
You can run the tests with tox as well, but if you use pre-commit, lint tests will run automatically when you make a commit!
follow-up: 10 comment:9 by , 8 days ago
Replying to Antoliny:
Replying to Rudraksha Dwivedi:
can someone shed some light on the flake8 test on the automated github testing flow ?
i think the issue is solved but some linting test fail
so i am not setting needs improvement to no currently
thank you!
Would you like to refer to this document?
You can run the tests with tox as well, but if you use pre-commit, lint tests will run automatically when you make a commit!
hey thanks for your response!!
i read through the article and your suggestion about about precommit lint test was really helpful
I ran the pre-commit hooks locally, and all relevant checks passed
with relevant test log = (
black....................................................................Passed
blacken-docs.........................................(no files to check)Skipped
isort....................................................................Passed
flake8...................................................................Passed
eslint...............................................(no files to check)Skipped
[ticket-36708 e877e5a3be] Cleanup for flake8 check
1 file changed, 1 insertion(+), 1 deletion(-)
)
Since everything appeared clean locally, I expected the GitHub workflow to pass as well, but the same flake8 issue is still reported in CI. Could you provide any guidance on what else I should check or what might cause this discrepancy?
Also, on a related note: is it generally acceptable to make several small commits and pushes to a PR when iterating on CI failures, or is this discouraged?
Thanks again.
follow-up: 11 comment:10 by , 8 days ago
Running only flake8 locally through tox is also an option.
tox -e flake8
Replying to Rudraksha Dwivedi:
Since everything appeared clean locally, I expected the GitHub workflow to pass as well, but the same flake8 issue is still reported in CI. Could you provide any guidance on what else I should check or what might cause this discrepancy?
Also, on a related note: is it generally acceptable to make several small commits and pushes to a PR when iterating on CI failures, or is this discouraged?
Thanks again.
I’m also not entirely sure how to answer this part.
It probably won’t be a big issue, but once you get more familiar with Django’s CI, I think you won’t have to worry much about these CI-related concerns :)
comment:11 by , 8 days ago
Replying to Antoliny:
Running only flake8 locally through tox is also an option.
tox -e flake8Replying to Rudraksha Dwivedi:
Since everything appeared clean locally, I expected the GitHub workflow to pass as well, but the same flake8 issue is still reported in CI. Could you provide any guidance on what else I should check or what might cause this discrepancy?
Also, on a related note: is it generally acceptable to make several small commits and pushes to a PR when iterating on CI failures, or is this discouraged?
Thanks again.
I’m also not entirely sure how to answer this part.
It probably won’t be a big issue, but once you get more familiar with Django’s CI, I think you won’t have to worry much about these CI-related concerns :)
hey! Thanks for being patient ! i realised how i had duplicated the same like of code in two distinct places, also figured out how to setup and test locally properly
Thanks _
If the issues dont occur i will mark needs improvement as no
peace ✨
comment:12 by , 8 days ago
| Patch needs improvement: | unset |
|---|
Thank you for suggesting the improvements Ben!
You're absolutely right, when the
result_listtemplate tag renders the template, the changelist must have aformsetattribute.def results(cl): if cl.formset: for res, form in zip(cl.result_list, cl.formset.forms): yield ResultList(form, items_for_result(cl, res, form)) else: for res in cl.result_list: yield ResultList(None, items_for_result(cl, res, None)) def result_list(cl): """ Display the headers and data list together. """ headers = list(result_headers(cl)) num_sorted_fields = 0 for h in headers: if h["sortable"] and h["sorted"]: num_sorted_fields += 1 return { "cl": cl, "result_hidden_fields": list(result_hidden_fields(cl)), "result_headers": headers, "num_sorted_fields": num_sorted_fields, "results": list(results(cl)), }And as you mentioned, this attribute is currently being dynamically assigned in the
changelist_viewthrough the options.py.I also agree that defining the formset attribute directly in the
ChangeListclass would be more appropriate.I agree with this improvement, but there might be aspects I haven’t considered, so I’ll wait for another person’s triage :)