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

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
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

1 participant