Reputation: 1122
class ModelA(models.Model):
views = models.PositiveBigIntegerField()
class ModelB(models.Model):
parent = models.ForeignKey(ModelA, on_delete=models.CASCADE, related_name='modelB', blank=True, null=True)
string = models.CharField()
class ModelAListView(generics.ListAPIView):
serializer_class = ModelASerialezer
queryset = ModelA.objects.all().prefetch_related('modelb')
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset.filter(modelb__string__icontains=request.GET['string']), many=True)
return Response(serializer.data)
class ModelASerializer(serializers.ModelSerializer):
id = serializers.ReadOnlyField()
modelB = ModelBSerializer(source='modelB', many=True, read_only=False)
class Meta:
model = ModelA
exclude = ('views',)
class ModelBSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(required=False)
class Meta:
model = ModelB
fields = '__all__'
If I need to search by "string" field I can write
modelA.objects.filter(modelB__string__icontains=request.GET['string']).values('modelB__string')
Which return ModelB instances only with necessary string
values:
<QuerySet [{'modelB__string': 'Test1'}]>
When I filter by modelb_string I expect to get only filtered FK value:
{
"id": 1,
"views": 0,
"modelb": [
{
"id": 46,
"string": "Test1",
"item": 1
}
]
}
but I get all FK values:
{
"id": 1,
"views": 0,
"modelb": [
{
"id": 46,
"string": "Test1",
"item": 1
},
{
"id": 47,
"string": "Test85",
"item": 1
},
{
"id": 48,
"string": "Test64",
"item": 1
}
]
}
Upvotes: 2
Views: 1699
Reputation: 81
The best practice would be on your view class
from django.db.models import Prefetch
modelA.objects.all().prefetch_related(Prefetch(modelB, queryset=modelB.objects.filter(string__icontains=request.GET['string'])))
This returns modelA objects with filtered modelB FK related instances
Upvotes: 1
Reputation: 4635
Few points worth mentioning :
You don't need to implement the list
function and redo what's already being done in the mixin
If we want to customise the queryset then we should override the get_queryset
, details
Something like this :
class ModelAListView(generics.ListAPIView):
serializer_class = ModelASerialezer
def get_queryset(self, *args, **kwargs):
queryset = modelA.objects.all()
given_string = self.request.query_params.get('string', None)
if given_string is not None:
queryset = queryset.filter(modelB__string__icontains=given_string)
return queryset
string
References :
Upvotes: 0