coderedcorp / coderedcorp/coderedcms

ClassifierSelectWidget should respect `limit_choices_to` on model field

Open
#713 1 comment 0 reactions 0 assignees View on GitHub
Type: Bug
Dominant language
Python
Stars
765
Forks
154
PR merge metrics
No merged PRs in 30d

Description

#### Describe the bug
ClassifierSelectWidget always shows all classifiers and terms even if the underlying model field definition restricts choices using `limit_choices_to`. This allows users to click on invalid options causing the form to fail validation.

#### Steps to reproduce
Steps to reproduce the behavior:
1. Set up a classifier with multiple terms. For this example I'm imagining a classifier called "Genre" with the terms "Action", "Adventure", "Horror", "Thriller", "Science-Fiction".
2. Make a snippet model (new or existing) with the following field:
```python
classifier_terms = ParentalManyToManyField(
'coderedcms.ClassifierTerm',
blank=True,
related_name="genres",
limit_choices_to=Q(name__startswith="A"), # or any filter eliminates some terms.
)
```
3. In the model's `panels` attribute, include `FieldPanel("classifier_terms", widget=ClassifierSelectWidget())`.
4. Run migrations, register snippet, etc.
5. Go to the snippet edit page for the snippet.
6. Scroll to the "classifier terms" panel. See that all of the terms are present, not just ones matching the `Q` object.
7. Select both a matching term and a non-matching term, and save the form. The form validation should fail and the error message should complain only about the ID of the non-matching term.

#### Expected behavior
Only the terms and classifiers matching the `limit_choices_to` filter should be available as choices, as happens when not using the ClassifierSelectWidget(). `CheckboxSelectMultiple` is very close to what I want, but it is not grouped by classifier.

#### Additional context
This should theoretically be a simple matter of updating the `optgroups` class to use `self.choices.queryset`.

I made a simple working example by changing the initial classifier queryset from `Classifier.objects.all().select_related()` to

```python

classifiers = Classifier.objects.all().select_related().prefetch_related(
Prefetch("terms", queryset=self.choices.queryset)
)
```
to stop Classifiers with no matching terms from appearing as empty groupings, I just changed the inner loop to this:

```python

if terms := classifier.terms.all():
for term in terms:
```

If this seems like something y'all would be interested in implementing, I could try my hand at making a merge request. Wanted to confirm that the team would consider it worthwhile.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.