Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

About "Keyword-only Arguments:" section in the documentation #1440

Open
mayukorin opened this issue Sep 18, 2021 · 0 comments
Open

About "Keyword-only Arguments:" section in the documentation #1440

mayukorin opened this issue Sep 18, 2021 · 0 comments

Comments

@mayukorin
Copy link

mayukorin commented Sep 18, 2021

For the following codes in
https://django-filter.readthedocs.io/en/stable/ref/filters.html#method

class F(FilterSet):
    """Filter for Books by if books are published or not"""
    published = BooleanFilter(field_name='published_on', method='filter_published')

    def filter_published(self, queryset, name, value):
        # construct the full lookup expression.
        lookup = '__'.join([name, 'isnull'])
        return queryset.filter(**{lookup: False})

        # alternatively, you could opt to hardcode the lookup. e.g.,
        # return queryset.filter(published_on__isnull=False)

    class Meta:
        model = Book
        fields = ['published']


# Callables may also be defined out of the class scope.
def filter_not_empty(queryset, name, value):
    lookup = '__'.join([name, 'isnull'])
    return queryset.filter(**{lookup: False})

class F(FilterSet):
    """Filter for Books by if books are published or not"""
    published = BooleanFilter(field_name='published_on', method=filter_not_empty)

    class Meta:
        model = Book
        fields = ['published']

I think it would be better to change it as following.

  1. If "published" field is present in "Book" model, then
# published = BooleanFilter(field_name='published_on', method='filter_published')
published = BooleanFilter(field_name='published', method='filter_published')
  1. If "published_on" field is present in "Book" model, then
class Meta:
        model = Book
        # fields = ['published']
        fields = ['published_on']

I've made pull requests #1441, #1442 for each pattern.

Reason

I think field_name in BooleanFilter should match the field name in the model.

Test

I used the code in
https://django-filter.readthedocs.io/en/stable/ref/filters.html#method
as a reference and tested it.

# models.py
from django.db import models


class Author(models.Model):
    name = models.CharField(max_length=255)


class Book(models.Model):
    name = models.CharField(max_length=255)
    published = models.DateTimeField(null=True)
# serializers.py
from rest_framework import serializers
from .models import Book


class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = "__all__"

# views.py
from django_filters import BooleanFilter
from django_filters import rest_framework as filters
from rest_framework import generics
from .serializers import BookSerializer
from .models import Book


class F(filters.FilterSet):

    published = BooleanFilter(field_name="published_on", method="filter_published")

    def filter_published(self, queryset, name, avlue):
        lookup = "__".join([name, "isnull"])
        print(lookup)
        return queryset.filter(**{lookup: False})

    class Meta:
        model = Book
        fields = ["published"]


class BookListAPIView(generics.ListAPIView):
    serializer_class = BookSerializer
    queryset = Book.objects.all()
    filter_backends = [filters.DjangoFilterBackend]
    filterset_class = F
# tests.py
from rest_framework.test import APITestCase
from .models import Book
import datetime


class TestBookListAPIView(APITestCase):

    TARGET_URL = "/document/books/"

    def setUp(self):
        dt = datetime.datetime(
            2018, 2, 1, 12, 15, tzinfo=datetime.timezone(datetime.timedelta(hours=9))
        )
        self.book = Book.objects.create(name="django", published=dt)

    def test_list_success(self):
        params = {"published": "true"}
        response = self.client.get(self.TARGET_URL, params, format="json")

        expected_json = [
            {
                "id": self.book.id,
                "name": self.book.name,
                "published": str(self.book.published).replace(" ", "T"),
            }
        ]

        self.assertEqual(response.status_code, 200)
        self.assertJSONEqual(response.content, expected_json)

The test resulted in the following error.

raise FieldError("Cannot resolve keyword '%s' into field. "
django.core.exceptions.FieldError: Cannot resolve keyword 'published_on' into field. Choices are: id, name, published

The test was successful when I modified it as pull requests #1441, #1442.
Adopting pull requests #1441 or #1442 is recommending.

This was referenced Sep 18, 2021
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant