Объединение двух таблиц и поиск/фильтр в сериализованных данных с помощью django-rest-framework
Я объединяю две таблицы и хочу выполнить поиск по ключевым словам. Мне нужно создать один SQL и добавить WHERE с аргументом(ами). Я использую django-rest-framework.
models.py
from django.db import models
class Paper(models.Model):
title = models.TextField()
paper_lan = models.CharField(max_length=2)
nb_authors = models.SmallIntegerField()
class Meta:
managed = False
def __str__(self):
return str(self.title)
class Abstract(models.Model):
paper = models.OneToOneField(Paper,
related_name='abstracts',
on_delete=models.CASCADE,
primary_key=True)
abstract = models.TextField()
class Meta:
managed = False
def __str__(self):
return str(self.abstract)
serializers.py
from rest_framework import serializers
from .models import Paper, Abstract
class PaperAbstractSerializer(serializers.ModelSerializer):
class Meta:
model = Paper
#fields = '__all__'
fields = ['title', 'paper_lan', 'nb_authors', 'abstracts']
depth = 1
class PaperSerializer(serializers.ModelSerializer):
class Meta:
model = Paper
fields = ('title', 'paper_lan', 'nb_authors')
class AbstractSerializer(serializers.ModelSerializer):
class Meta:
model = Abstract
fields = ['abstract']
filters.py
from django.db.models import Q
from django_filters.rest_framework import CharFilter, FilterSet
from .models import Paper, Abstract
class PaperAbstractFilterSet(FilterSet):
query = CharFilter(method='qfilter')
class Meta:
model = Paper
fields = ['query']
def qfilter(self, queryset, name, value):
squery = Q(abstracts__icontains=value)
return queryset.filter(squery)
class PaperFilterSet(FilterSet):
query = CharFilter(method='qfilter')
class Meta:
model = Paper
fields = ['query']
def qfilter(self, queryset, name, value):
squery = Q(title__icontains=value)
return queryset.filter(squery)
class AbstractFilterSet(FilterSet):
query = CharFilter(method='qfilter')
class Meta:
model = Abstract
fields = ['query']
def qfilter(self, queryset, name, value):
squery = Q(abstract__icontains=value)
return queryset.filter(squery)
views.py
from rest_framework.generics import ListAPIView
from .models import Paper, Abstract
from .serializers import PaperAbstractSerializer, PaperSerializer, AbstractSerializer
from .filters import PaperAbstractFilterSet, PaperFilterSet, AbstractFilterSet
class PaperAbstractView(ListAPIView):
queryset = Paper.objects.all()
serializer_class = PaperAbstractSerializer
filterset_class = PaperAbstractFilterSet
class PaperView(ListAPIView):
queryset = Paper.objects.all()
serializer_class = PaperSerializer
filterset_class = PaperFilterSet
class AbstractView(ListAPIView):
queryset = Abstract.objects.all()
serializer_class = AbstractSerializer
filterset_class = AbstractFilterSet
urls.py
from django.urls import path
from .views import PaperAbstractView, PaperView, AbstractView
urlpatterns = [
path('paperabs/', PaperAbstractView.as_view()),
path('paper/', PaperView.as_view()),
path('abstract/', AbstractView.as_view()),
]
Когда я выполняю следующие действия, поиск производится в одной таблице, все в порядке. Есть только один SQL, который производится.
curl "http://localhost:8003/api/v1/appln/abstract/?query=<keyword_searching>"
curl "http://localhost:8003/api/v1/appln/paper/?query=<keyword_searching>"
Но когда я выполняю следующий запрос, я не могу выполнить поиск по ключевым словам. Если я закомментирую строку filterset_class = PaperAbstractFilterSet в PaperAbstractView, появится один SQL, а затем, соответственно, n других SQL, созданных для второй таблицы.
curl "http://localhost:8003/api/v1/appln/paperabs/?query=<keyword_searching>"
Как создать один SQL с дополнительным WHERE для проведения любого поиска по названию и/или реферату?
Чтобы ответить на свой вопрос; для объединения двух таблиц в одном SQL я использую select_related и корректирую serializers.py, добавляя сериализатор LEFT JOINed table, AbstractSerializer в PaperAbstractSerializer.
# serializers.py
class PaperAbstractSerializer(serializers.ModelSerializer):
abstracts = AbstractSerializer(read_only=True)
class Meta:
model = Paper
fields = ['title', 'paper_lan', 'nb_authors', 'abstracts']
# views.py
class PaperAbstractView(ListAPIView):
queryset = Paper.objects.select_related('abstracts').all()
serializer_class = PaperAbstractSerializer
filterset_class = PaperAbstractFilterSet