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

"form" definition on "class Meta" of a FilterSet is not honored #1650

Open
DanielSwain opened this issue Mar 25, 2024 · 3 comments
Open

"form" definition on "class Meta" of a FilterSet is not honored #1650

DanielSwain opened this issue Mar 25, 2024 · 3 comments

Comments

@DanielSwain
Copy link
Contributor

DanielSwain commented Mar 25, 2024

I need to modify what is displayed to the user for each item in a <select> by including in parentheses the count of a set of items that ForeignKey to the main model. To do this, I defined a custom form and fields (including a queryset definition on the field displayed in the <select> - see the very end of this question for additional information). I was getting KeyError on the first of the field names, so I then stripped down the form definition by simply declaring a filter form of type forms.ModelForm with exclude:

class MyModelFilterForm(forms.ModelForm):

    class Meta:
        model = MyModel
        exclude = ['field1', 'field2']
        # fields = ['field1', 'field2', 'field3', 'field4', 'field5', etc.]

class MyModelFilter(django_filters.FilterSet):

    class Meta:
        form = MyModelFilterForm

As I add each subsequent field from the fields in the model definition to exclude, I then get a KeyError on the next, non-excluded field. It seems like the form declaration isn't being honored. I looked at your source code in BaseFilterSet.get_fields().
It appears that the form argument is possibly not being taken into account in get_fields(). Is that right, or am I missing something?

Incidentally, in order to modify what is displayed for each item in the <select>, I defined a custom ModelChoiceField and used the label_from_instance method as mentioned here.

class MyCustomChoiceField(forms.ModelChoiceField):
    def label_from_instance(self, obj):
        return f"{obj.name} ({obj.relatedmodel_set.count()})"

There will only ever be a small number of items in the <select>, and I included select_related for related_model on the queryset definition.

@DanielSwain DanielSwain changed the title A "form" definition on "class Meta" is not honored "form" definition on "class Meta" is not honored Mar 25, 2024
@DanielSwain DanielSwain changed the title "form" definition on "class Meta" is not honored "form" definition on "class Meta" of a FilterSet is not honored Mar 25, 2024
@carltongibson
Copy link
Owner

Hi @DanielSwain. The Meta.form attribute is used in get_form_class(), where it's used as the base for a new class built with fields for the declared filters.

You may want to override that, e.g. if your form has exact fields specified, or to control the dynamic generation.

@DanielSwain
Copy link
Contributor Author

DanielSwain commented Mar 26, 2024

Thank you @carltongibson. I did notice get_form_class() and the comment in the code there:

image

A search in the docs on get_form_class turns up nothing, so this appears to be an undocumented feature(?). 😊 Also, while setting a form attribute seems like the most acceptable and most standard way to use a custom form in a FilterSet, the statement in the docs that one can set a form attribute on a FilterSet appears to not be applicable. Is that correct? None of this is a criticism of this excellent library. I just want to make sure things are clear for the record. In my ideal world, I would be able to assign a custom form to the form attribute as is currently stated in the docs.

@carltongibson
Copy link
Owner

... the statement in the docs that one can set a form attribute on a FilterSet appears to not be applicable.

I would be able to assign a custom form to the form attribute as is currently stated in the docs.

You can. You can see in the code there that self._meta.form is used as the base class for the dynamically generated form class used by the filterset.

this appears to be an undocumented feature(?)

Yes, good. Adding that to the FilterSet reference would be great.

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

No branches or pull requests

2 participants