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

Filter choices in model form #767

Open
billybonks opened this issue Feb 7, 2024 · 3 comments
Open

Filter choices in model form #767

billybonks opened this issue Feb 7, 2024 · 3 comments
Labels
enhancement Feature requests or improvements to existing functionality help wanted Issues where maintainers could use assistance from others

Comments

@billybonks
Copy link
Contributor

Bottle feeding, has an option of solid food which makes no sense :).

I would like to filter that option out for bottle feeding for specifically i have tried every option on the internet

class BottleFeedingForm(CoreModelForm, TaggableModelForm):
    fieldsets = [
        {
            "fields": ["child", "type", "start", "amount"],
            "layout": "required",
        },
        {"layout": "advanced", "fields": ["notes", "tags"]},
    ]

    class Meta:
        model = models.Feeding
        fields = ["child", "start", "type", "amount", "notes", "tags"]
        widgets = {
            "child": ChildRadioSelect,
            "start": DateTimeInput(),
            "type": PillRadioSelect(
                choices=[
                    ("breast milk", _("Breast milk")),
                    ("formula", _("Formula")),
                    ("fortified breast milk", _("Fortified breast milk")),
                ],
            ),
            "notes": forms.Textarea(attrs={"rows": 5}),
        }

https://forum.djangoproject.com/t/overriding-models-choices-in-form-init/15048

probably a few more.

before i build FIlterablePillRadioSelect I was wondering if you have a way to do this?

I will be doing using this for a nursing form as well.

@cdubz
Copy link
Member

cdubz commented Feb 14, 2024

I'm not 100% but this looks like how I would expect it to work: https://forum.djangoproject.com/t/how-to-filter-the-choices-in-forms-select-widget/19974/4

@cdubz cdubz added enhancement Feature requests or improvements to existing functionality help wanted Issues where maintainers could use assistance from others labels Feb 14, 2024
@billybonks
Copy link
Contributor Author

billybonks commented Feb 14, 2024

I tried this and it didn't work, i can create a pr that we can debug together. Maybe i am doing something wrong

@MrApplejuice
Copy link
Contributor

MrApplejuice commented Feb 15, 2024

I tried to do the leg-work and it is quite interesting actually. It seems to come down to a conscious choice by django:

class ChoiceField(Field):
    # ...
    @choices.setter
    def choices(self, value):
        # Setting choices on the field also sets the choices on the widget.
        # Note that the property setter for the widget will re-normalize.
        self._choices = self.widget.choices = normalize_choices(value)

Source: https://github.com/django/django/blob/c783e7a3a0e411811aba83158d55e4f2f3091ac7/django/forms/fields.py#L899-L903

The "field" that is meant here, according to my investigation, is the model-field because the stack-trace in question looks as follows (Comment from my side: This feels buggy and not intended, but maybe it is?!):

  File "/home/paul/code/python/babybuddy/core/forms.py", line 207, in <module>                                                                                                                         
    class BottleFeedingForm(CoreModelForm, TaggableModelForm):                                                                                                                                         
  File "/home/paul/.local/share/virtualenvs/babybuddy-bwgPVFMf/lib/python3.10/site-packages/django/forms/models.py", line 309, in __new__                                                              
    fields = fields_for_model(                                                                                                                                                                         
  File "/home/paul/.local/share/virtualenvs/babybuddy-bwgPVFMf/lib/python3.10/site-packages/django/forms/models.py", line 234, in fields_for_model                                                     
    formfield = f.formfield(**kwargs)                                                                                                                                                                  
  File "/home/paul/.local/share/virtualenvs/babybuddy-bwgPVFMf/lib/python3.10/site-packages/django/db/models/fields/__init__.py", line 1298, in formfield                                              
    return super().formfield(**defaults)                                                                                                                                                               
  File "/home/paul/.local/share/virtualenvs/babybuddy-bwgPVFMf/lib/python3.10/site-packages/django/db/models/fields/__init__.py", line 1140, in formfield                                              
    return form_class(**defaults)                                                                                                                                                                      
  File "/home/paul/.local/share/virtualenvs/babybuddy-bwgPVFMf/lib/python3.10/site-packages/django/forms/fields.py", line 932, in __init__                                                             
    super().__init__(**kwargs)                                                                                                                                                                         
  File "/home/paul/.local/share/virtualenvs/babybuddy-bwgPVFMf/lib/python3.10/site-packages/django/forms/fields.py", line 880, in __init__                                                             
    self.choices = choices                                                                                                                                                                             
  File "/home/paul/.local/share/virtualenvs/babybuddy-bwgPVFMf/lib/python3.10/site-packages/django/forms/fields.py", line 895, in choices                                                              
    self._choices = self.widget.choices = normalize_choices(value)                                                                                                                                     
  File "/home/paul/code/python/babybuddy/core/forms.py", line 204, in choices                                                                                                                          
    traceback.print_stack()               

The callstack indicates that forms/models.py calls out -> db/models/... which then causes a -> self.widget.choices = ....

Baby buddy sets choices on the model field:

babybuddy/core/models.py

Lines 237 to 247 in 2d1338a

color = models.CharField(
blank=True,
choices=[
("black", _("Black")),
("brown", _("Brown")),
("green", _("Green")),
("yellow", _("Yellow")),
],
max_length=255,
verbose_name=_("Color"),
)


How to get it to work

However, independent from my finding above (or coming forth out it), this does the trick: Setting the "choices" not on the widget but on the form-field!

class BottleFeedingForm(CoreModelForm, TaggableModelForm):
    def save(self):
        instance = super(BottleFeedingForm, self).save(commit=False)
        instance.method = "bottle"
        instance.end = instance.start
        instance.save()
        return instance

    type = ChoiceField(
        choices=(
            ("breast milk", _("Breast milk")),
            ("formula", _("Formula")),
            ("fortified breast milk", _("Fortified breast milk")),
        ),
    )

    class Meta:
        model = models.Feeding
        fields = ["child", "start", "type", "amount", "notes", "tags"]
        widgets = {
            "child": ChildRadioSelect,
            "start": DateTimeInput(),
            "notes": forms.Textarea(attrs={"rows": 5}),
        }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Feature requests or improvements to existing functionality help wanted Issues where maintainers could use assistance from others
Projects
None yet
Development

No branches or pull requests

3 participants