使用Django过滤器和Q对象来根据多列中的任意一个来筛选数据

总结

使用Django过滤器和Q对象来实现本次任务。

    • 名前

 

    カナ

我想解释一下如何筛选出满足以下条件的数据:
例如,如果想通过姓名或假名进行筛选,可以使用以下示例中的”name”查询参数进行筛选。

'http://127.0.0.1:8080/api/customer/?name=大阪'
'http://127.0.0.1:8080/api/customer/?name=オオサカ'

因为不需要特意创建假名查询参数,所以在想要进行假名搜索时很方便,我希望实施它。

前提- 就像這句中所說的,需要用中文來翻譯

    • django-filtersをインストール済み

 

    • django-filtersの基本的な使い方を知っている

 

    必須ではないが最後にSwaggerで検証するため、Swaggerを設定済み

文件结构

文件的结构如下所示。

application
   ├── __init__.py
   ├── admin.py
   ├── apps.py
   ├── filters.py
   ├── fixtures
   |   └── fixture.json
   ├── migrations
   ├── models.py
   ├── serializers
   |   └── customer.py
   ├── urls.py
   └── views
       └── customer.py

以上提及的部分

    • models.py

 

    • serializers/customer.py

 

    • views/customer.py

 

    • urls.py

 

    • fixtures/fixture.json

 

    filters.py

我会逐步记录所需的设置。

起初,Q对象是什么呢?

当在进行复杂查询时,会使用OR或AND来搜索。这次我们将在filters.py中使用它来进行name和kana的OR搜索。

模型.py

本次我们将创建一个供客户使用的模型,并添加kana和name两列。

import uuid

from django.core.validators import RegexValidator
from django.db import models


class Customer(models.Model):
    """お客様"""

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    kana = models.CharField(max_length=255)
    """カナ氏名"""
    name = models.CharField(max_length=255)
    """氏名"""
    birthday = models.DateField()
    """誕生日"""
    phone_no = models.CharField(
        max_length=11,
        validators=[RegexValidator(r"^[0-9]{11}$", "11桁の数字を入力してください。")],
        blank=True,
    )
    """電話番号"""

    class Meta:
        db_table = "Customer"

序列化器/顾客.py

本次我们将使用ModelSerializer。

from rest_framework import serializers

from application.models import Customer


class CustomerSerializer(serializers.ModelSerializer):
    class Meta:
        model = Customer
        fields = "__all__"

视图/顾客.py

创建CustomerViewSet,并进行django-filters的配置。

from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.viewsets import ModelViewSet

from application.filters import CustomerFilter
from application.models import Customer
from application.serializers.customer import CustomerSerializer


class CustomerViewSet(ModelViewSet):
    queryset = Customer.objects.all()
    serializer_class = CustomerSerializer
    filter_backends = (DjangoFilterBackend,)
    filterset_class = CustomerFilter

urls.py 的中文释义是什么?

为客户创建一个URL

from django.urls import include, path
from rest_framework_nested import routers

from application.views.customer import CustomerViewSet

router = routers.DefaultRouter()
router.register(r"customer", CustomerViewSet, basename="customer")

urlpatterns = [
    path(r"", include(router.urls)),
]

赛程.json

请放入客户的测试数据。

python manage.py loaddata fixtures.json

可以一次性全部放进去。

[
    {
        "model": "application.Customer",
        "pk": 1,
        "fields": {
            "kana": "オオサカタロウ",
            "name": "大阪太郎",
            "birthday": "1992-01-06",
            "phone_no": "08011112222",
            "address": 1
        }
    },
    {
        "model": "application.Customer",
        "pk": 2,
        "fields": {
            "kana": "キョウトジロウ",
            "name": "京都二郎",
            "birthday": "1994-01-06",
            "phone_no": "08022223333",
            "address": 2
        }
    },
    {
        "model": "application.Customer",
        "pk": 3,
        "fields": {
            "kana": "ヒョウゴサブロウ",
            "name": "兵庫三郎",
            "birthday": "1995-03-06",
            "phone_no": "08033334444",
            "address": 3
        }
    }
]

过滤器.py

我需要在这里进行过滤器的设置。

import django_filters
from django.db.models import Q

from application.models import Customer


class CustomerFilter(django_filters.FilterSet):
    """お客様の
    - 氏名・カナ氏

    で絞り込むFilter

    Args:
        django_filters
    """

    name = django_filters.CharFilter(method="search_name", label="name")

    class Meta:
        model = Customer
        fields = ["name"]

    def search_name(self, queryset, name, value):
        return queryset.filter(
            Q(name__contains=value) | Q(kana__contains=value)
        )

由于普通的CharFilter只能通过name对数据进行筛选,因此我们将创建一个名为search_name的自定义搜索方法。

name = django_filters.CharFilter(method="search_name", label="name")

在这里使用前面提到的Q对象进行筛选。

    def search_name(self, queryset, name, value):
        return queryset.filter(
            Q(name__contains=value) | Q(kana__contains=value)
        )

搜寻名称()函数的参数

    • querysetの変数内にはCustomerのオブジェクトが入ります

 

    • value内には指定した検索条件が入ります

例えば”大阪”で絞り込もうと思った場合はvalue内に”大阪”が入ります

search_name()の引数にdjango-filtersで指定したfilter名(今回だとname)も入れないとカスタムメソッドが機能しないので注意です

print(queryset)
<QuerySet [<Customer: Customer object (00000000-0000-0000-0000-000000000001)>, <Customer: Customer object (00000000-0000-0000-0000-000000000002)>, <Customer: Customer object (00000000-0000-0000-0000-000000000003)>]>
print(value)
'大阪'
print(name)
'name'

关于已发出的SQL

我发现queryset中有Customer对象,所以让我们在Shell中进行确认。
如果你不知道如何使用django-debug-toolbar,你可以参考下面的文章,它可以方便地查看Django ORM生成的SQL语句。

 

python manage.py debugsqlshell
Python 3.11.3 (main, Apr 12 2023, 14:31:14) [GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from application.models import Customer
>>> from django.db.models import Q
>>> Customer.objects.filter(Q(name__contains="大阪") | Q(kana__contains="大阪"))
SELECT `Customer`.`id`,
       `Customer`.`kana`,
       `Customer`.`name`,
       `Customer`.`birthday`,
       `Customer`.`phone_no`,
       `Customer`.`address_id`
FROM `Customer`
WHERE (`Customer`.`name` LIKE BINARY '%大阪%'
       OR `Customer`.`kana` LIKE BINARY '%大阪%')
LIMIT 21 [1.05ms]
<QuerySet [<Customer: Customer object (00000000-0000-0000-0000-000000000001)>]>

通过在WHERE条件中使用OR,可以确认正在筛选包含在name或kana列中含有”大阪”的对象。

让我们使用Swagger进行验证

スクリーンショット 2023-05-14 10.38.25.png
スクリーンショット 2023-05-14 10.38.41.png
スクリーンショット 2023-05-14 10.39.23.png
スクリーンショット 2023-05-14 10.40.29.png
スクリーンショット 2023-05-14 10.40.47.png
スクリーンショット 2023-05-14 10.41.01.png

请提供更多上下文以便我更好地理解您所需的信息。

 

bannerAds