I’m using DRF for a simple API, and I was wondering if there’s a way to achieve this behavior:
- I’ve got two models similar to the following:
JavaScript
x
10
10
1
class Table(models.Model):
2
name = models.CharField(max_length=100)
3
4
5
class Column(models.Model):
6
original_name = models.CharField(max_length=100)
7
name = models.CharField(max_length=100, blank=True, null=True)
8
9
table = models.ForeignKey(Table, on_delete=models.CASCADE, related_name="columns")
10
- And their serializers as follows:
JavaScript
1
27
27
1
class ColumnSerializer(serializers.HyperlinkedModelSerializer):
2
table = serializers.HyperlinkedRelatedField(
3
read_only=True, view_name="table-detail"
4
)
5
6
class Meta:
7
model = Column
8
fields = ["url", "name", "table"]
9
10
class TableSerializer(serializers.HyperlinkedModelSerializer):
11
dataset = serializers.HyperlinkedRelatedField(
12
read_only=True, view_name="dataset-detail"
13
)
14
tags = serializers.SlugRelatedField(
15
many=True, slug_field="name", queryset=Tag.objects.all()
16
)
17
columns = ColumnSerializer(many=True, read_only=True)
18
19
class Meta:
20
model = Table
21
fields = [
22
"url",
23
"name",
24
25
"columns",
26
]
27
- This returns me an output similar to
JavaScript
1
16
16
1
{
2
3
"results": [
4
{
5
"url": "http://0.0.0.0:8001/api/tables/1/",
6
"name": "some-name",
7
"columns": [
8
{
9
"url": "http://0.0.0.0:8001/api/columns/1/",
10
"name": "id",
11
"table": "http://0.0.0.0:8001/api/tables/1/"
12
},
13
14
}
15
16
which is totally fine. But what I’d really want to do is, if a Column
has name=None
, it’s filtered out from every API ViewSet. I’ve managed to do it on the ColumnViewSet
by doing queryset = queryset.filter(name__isnull=False)
, but I can’t do it for the TableViewSet
or others that might show a Column
list.
I’ve tried tinkering with the ColumnSerializer
, but the best I could get from it was to show null
s on the Column
list.
I wonder if there’s a way of hiding those.
EDIT 1: Adding my ViewSets
JavaScript
1
17
17
1
class TableViewSet(viewsets.ModelViewSet):
2
serializer_class = TableSerializer
3
4
def get_queryset(self):
5
queryset = Table.objects.all().order_by("name")
6
# some query_params filtering
7
return queryset
8
9
class ColumnViewSet(viewsets.ModelViewSet):
10
serializer_class = ColumnSerializer
11
12
def get_queryset(self):
13
queryset = Column.objects.all().order_by("id")
14
queryset = queryset.filter(name__isnull=False)
15
# some query_params filtering
16
return queryset
17
Advertisement
Answer
You can work with a Prefetch
object [Django-doc] to filter the related object collection, so:
JavaScript
1
11
11
1
from django.db.models import Prefetch
2
3
class TableViewSet(viewsets.ModelViewSet):
4
serializer_class = TableSerializer
5
6
def get_queryset(self):
7
queryset = Table.objects.prefetch_related(
8
Prefetch('columns', Column.objects.filter(name__isnull=False))
9
).order_by('name')
10
# some query_params filtering
11
return queryset