carltongibson / django-filter

A generic system for filtering Django QuerySets based on user selections
https://django-filter.readthedocs.io/en/main/
Other
4.45k stars 766 forks source link

Non model filters declared in class without label show "[invalid name]" #1684

Open hyperstown opened 1 month ago

hyperstown commented 1 month ago

Hello I noticed that declaring non model field filter without label in filterset class is not displayed properly in filter form.

So for this example model:

class Post(models.Model):
    title =  models.CharField(max_length=250)
    description = models.TextField()
    author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='posts')

class Comment(models.Model):
    text = models.TextField()
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
    author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='comments')

and this viewset:

class PostViewSet(viewsets.ModelViewSet):

    queryset = Post.objects.annotate(has_comments=Exists(Comment.objects.filter(post_id=OuterRef('pk'))))
    serializer_class = PostSerializer
    filterset_class = PostFilterSet

and this filterset:

class PostFilterSet(filters.FilterSet):

    has_comments = filters.BooleanFilter()

    class Meta:
        model = Post
        fields = '__all__'

Filters in form will look like this:

image

Expected result would be something like this:

image

I know that this can be accomplished adding label parameter to BooleanFilter but it's very inconvenient. Form should not show [invalid name] unless it absolutely cannot figure out field name.

As a potential solution I propose changing verbose_field_name function in django_filters/utils.py.

From:

parts = get_field_parts(model, field_name)
if not parts:
    return "[invalid name]"

to:

parts = get_field_parts(model, field_name)
if not parts:
    return field_name.replace("_", " ")

I can make a PR but before that I want to make sure that it's not just some kind of mistake on my part.

carltongibson commented 1 month ago

In this case you should pass the label kwarg no? https://django-filter.readthedocs.io/en/stable/ref/filters.html#label

hyperstown commented 1 month ago

But that's the thing, why should I specify label each time when field name is not unknown? We have access to field name in that function but we still choose to return [Invalid Name].\ I think that label role is for example more in case of field abbreviations. So for example filed name is p_txt and label should be Private text. Or just in general when you want to name field differently but you want to keep filter name. But if field name is first_name there is no reason for me to get out of my way to specify label First name. It's redundant and inconvenient in my opinion.