[PYTHON] Comprendre comment utiliser django-filter

Qu'est-ce que django-filter?

Vous pouvez écrire vos critères de recherche en short code !!! Quand j'ai appris cela, j'ai pensé que c'était révolutionnaire.

document officiel django-filter

Définir le modèle et le seiralizer

À titre d'exemple, définissons un tel modèle et un sérialiseur.

models.py


class Book(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    is_deleted = models.CharField(max_length=1, default='0')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    title = models.CharField(max_length=128)
    sub_title = models.CharField(max_length=128)
    price = models.DecimalField(max_digits=8, decimal_places=2, blank=True, null=True)
    author = models.ForeignKey(Author, on_delete=models.PROTECT, blank=True, null=True)
    publisher = models.ForeignKey(Publisher, on_delete=models.PROTECT)

serializer.py


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

Écriture de base

Tout d'abord, avec django-filter Essayez d'obtenir la liste sans restreindre les conditions de recherche.

view.py


from django_filters import rest_framework as filters

class FilterBook(filters.FilterSet):
    class Meta:
        model = Book
        fields = '__all__'

class ListBook(APIView):

    def get(self, request):
        filterset = FilterBook(request.query_params, queryset=Book.objects.all())
        serializer = BookSerializer(instance=filterset.qs, many=True)
        return Response(serializer.data)

Créez une classe qui hérite de FilterSet et spécifiez le modèle à cet endroit. Il est similaire à Form and Serializer de Django.

Et l'URL de cette API ListBook créée / api / v1 / book / list / (omis) Lorsque vous faites une demande à partir du navigateur, ces données seront renvoyées. Bien sûr, les données sont un échantillon lol

スクリーンショット 2020-10-21 19.38.42.png

Spécifiez les conditions de recherche

Ensuite, spécifiez les conditions de recherche et faites une demande. L'URL que vous avez demandée plus tôt était / api / v1 / book / list /, mais spécifiez les paramètres de requête ici. Si vous changez en / api / v1 / book / list /? Title = test et demandez, la réponse changera.

スクリーンショット 2020-10-21 19.48.30.png

Aucune réponse n'a été renvoyée cette fois. Ce title = test renvoie un objet dont le titre du modèle de livre correspond au test. De plus, changez title en sub_title en / api / v1 / book / list /? Sub_title = test Lorsque je fais une demande, aucune réponse n'est retournée.

Cependant, si vous spécifiez un paramètre de requête qui n'existe pas dans le modèle Book Les données ne peuvent pas être réduites et les données sont renvoyées dans la réponse.

Modifier les conditions de recherche

Précédemment, affinez par «titre» et «sous-titre» Les données ont été extraites.

Cependant, cette fois, "title" peut être une condition de recherche, mais "sub_title" n'est pas requis comme condition de recherche! Je me demande ce qui est arrivé. Dans un tel cas, vous ne pouvez spécifier que le correspondant avec les champs de la classe Filter.

views.py


class FilterBook(filters.FilterSet):
    class Meta:
        model = Book
        fields = ['title']

En faisant cela, j'ai pu affiner plus tôt par sous_title, mais maintenant je ne peux plus restreindre que par titre.

Personnalisez la méthode de recherche

Si vous avez spécifié des champs avec «all» plus tôt, ce sera la méthode de recherche par défaut. Je ne pouvais pas utiliser la méthode de recherche telle que la recherche numérique ou la correspondance partielle. (Par exemple, même si vous demandez / api / v1 / book / list /? Price = test, il ne sera pas réduit.)

Par conséquent, nous personnaliserons la méthode de recherche.

views.py


class FilterBook(filters.FilterSet):
    # UUID
    id = filters.UUIDFilter()

    #Match partiel
    title = filters.CharFilter(lookup_expr='icontains')

    #Découvrez le montant
    price = filters.NumberFilter()
    price__gt = filters.NumberFilter(field_name='price', lookup_expr='gt')
    price__lt = filters.NumberFilter(field_name='price', lookup_expr='lt')

    class Meta:
        model = Book
        fields = []

Le contenu de la personnalisation. filters.UUIDFilter () correspond à UUID. Même si vous effectuez une recherche par ID, il sera capturé. Avec filters.CharFilter (lookup_expr = 'icontains') J'ai fait une correspondance partielle. L'argument pour cette lookup_expr est les [recherches de champs] de Django (https://docs.djangoproject.com/en/3.1/ref/models/querysets/#field-lookups) Vous pouvez spécifier la même chose que. filters.NumberFilter(field_name='price', lookup_expr='gt') Spécifie la correspondance et la plage de nombres. field_name spécifie le champ cible du modèle. Normalement, si le nom du champ de filtre et le nom du champ de modèle correspondent, vous n'avez pas besoin de le spécifier.


Faisons une demande après personnalisation. ʻApi / v1 / livre / liste /? Title = sqletapi/v1/book/list/?price_gt=3200&price_lt=4000` Les données sont désormais traitées lorsque vous demandez.

スクリーンショット 2020-10-21 20.39.53.png

Soutient également les relations

Si vous souhaitez utiliser le modèle lié par ForeignKey comme condition de recherche, Spécifiez dans field_name. La méthode de spécification peut être prise en charge par [expression de recherche] de django (https://docs.djangoproject.com/ja/3.1/ref/models/lookups/#module-django.db.models.lookups).

views.py


class FilterBook(filters.FilterSet):
    author_last_name = filters.CharFilter(field_name='author__last_name',lookup_expr='icontains')

Personnalisez le filtre par défaut

Avec le filtre par défaut, CharFilter devait être personnalisé pour chaque champ, comme une correspondance exacte. Au lieu de personnaliser champ par champ, nous essayons de personnaliser les valeurs par défaut de CharFilter.

views.py


class FilterBook(filters.FilterSet):

    class Meta:
        model = Book
        fields = ['title']
        filter_overrides = {
            models.CharField: {
                'filter_class': filters.CharFilter,
                'extra': lambda f: {
                    'lookup_expr': 'icontains',
                },
            },
        }

Dans class Meta:, décrivez filter_overrrides et le contenu que vous voulez définir par défaut. Désormais, tous les champs utilisant CharFiled dans le modèle sont partiellement mis en correspondance par défaut.

Faites votre propre personnalisation

Vous pouvez faire votre propre recherche lors de la réduction. J'ai créé un exemple de suppression de traits d'union et de correspondance partielle.

views.py


class FilterBook(filters.FilterSet):
    title = filters.CharFilter(method='title_custom_filter')

    class Meta:
        model = Book
        fields = []

    @staticmethod
    def title_custom_filter(queryset, name, value):
        #nom est le nom du champ
        #value est le paramètre de requête
        # name__icontains
        lookup = '__'.join([name, 'icontains'])
        #Effacer les traits d'union
        replaced_value = value.replace('-', '')
        return queryset.filter(**{
            lookup: replaced_value,
        })

Si vous passez le nom de la méthode sous forme de chaîne dans l'argument de CharFilter, la méthode sera exécutée au moment de la recherche. Le nom du champ et les paramètres de recherche «valeur» sont transmis à «nom». Donc, si vous changez cela, vous pouvez créer librement des conditions de recherche.

Cette fois, par exemple Identique à / api / v1 / book / list /? Title = g /api/v1/book/list/?title=g--- Vous pouvez désormais obtenir une réponse même si vous envoyez une demande à.

スクリーンショット 2020-10-22 1.38.34.png


Pour plus d'informations, consultez Par tous les moyens document officiel J'espère que vous pourrez le vérifier !!!!!!!!!!!!!!!!!

Recommended Posts

Comprendre comment utiliser django-filter
Comment utiliser xml.etree.ElementTree
Comment utiliser Python-shell
Remarques sur l'utilisation de tf.data
Comment utiliser virtualenv
Comment utiliser Seaboan
Comment utiliser la correspondance d'image
Comment utiliser le shogun
Comment utiliser Pandas 2
Comment utiliser Virtualenv
Comment utiliser numpy.vectorize
Comment utiliser pytest_report_header
Comment utiliser partiel
Comment utiliser Bio.Phylo
Comment utiliser SymPy
Comment utiliser x-means
Comment utiliser WikiExtractor.py
Comment utiliser IPython
Comment utiliser virtualenv
Comment utiliser Matplotlib
Comment utiliser iptables
Comment utiliser numpy
Comment utiliser TokyoTechFes2015
Comment utiliser venv
Comment utiliser le dictionnaire {}
Comment utiliser Pyenv
Comment utiliser la liste []
Comment utiliser python-kabusapi
[Python] Comprendre comment utiliser les fonctions récursives
Comment utiliser OptParse
Comment utiliser le retour
Comment utiliser pyenv-virtualenv
Comment utiliser imutils
Comment utiliser Qt Designer
Comment utiliser la recherche triée
[gensim] Comment utiliser Doc2Vec
python3: Comment utiliser la bouteille (2)
Comment utiliser le générateur
[Python] Comment utiliser la liste 1
Comment utiliser FastAPI ③ OpenAPI
Comment utiliser Python Argparse
Comment utiliser IPython Notebook
Comment utiliser Pandas Rolling
[Note] Comment utiliser virtualenv
Comment utiliser les dictionnaires redis-py
Python: comment utiliser pydub
[Python] Comment utiliser checkio
[Aller] Comment utiliser "... (3 périodes)"
Comment faire fonctionner GeoIp2 de Django
[Python] Comment utiliser input ()
Comment utiliser le décorateur
[Introduction] Comment utiliser open3d
Comment utiliser Python lambda
Comment utiliser Jupyter Notebook
[Python] Comment utiliser virtualenv
python3: Comment utiliser la bouteille (3)
python3: Comment utiliser la bouteille
Comment utiliser Google Colaboratory