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
À 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__'
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
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.
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.
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
.
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 = sqlet
api/v1/book/list/?price_gt=3200&price_lt=4000`
Les données sont désormais traitées lorsque vous demandez.
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')
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.
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 à.
Pour plus d'informations, consultez Par tous les moyens document officiel J'espère que vous pourrez le vérifier !!!!!!!!!!!!!!!!!
Recommended Posts