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:
class Table(models.Model):
name = models.CharField(max_length=100)
...
class Column(models.Model):
original_name = models.CharField(max_length=100)
name = models.CharField(max_length=100, blank=True, null=True)
...
table = models.ForeignKey(Table, on_delete=models.CASCADE, related_name="columns")
- And their serializers as follows:
class ColumnSerializer(serializers.HyperlinkedModelSerializer):
table = serializers.HyperlinkedRelatedField(
read_only=True, view_name="table-detail"
)
class Meta:
model = Column
fields = ["url", "name", "table"]
class TableSerializer(serializers.HyperlinkedModelSerializer):
dataset = serializers.HyperlinkedRelatedField(
read_only=True, view_name="dataset-detail"
)
tags = serializers.SlugRelatedField(
many=True, slug_field="name", queryset=Tag.objects.all()
)
columns = ColumnSerializer(many=True, read_only=True)
class Meta:
model = Table
fields = [
"url",
"name",
...
"columns",
]
- This returns me an output similar to
{
...
"results": [
{
"url": "http://0.0.0.0:8001/api/tables/1/",
"name": "some-name",
"columns": [
{
"url": "http://0.0.0.0:8001/api/columns/1/",
"name": "id",
"table": "http://0.0.0.0:8001/api/tables/1/"
},
...
}
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 nulls on the Column list.
I wonder if there’s a way of hiding those.
EDIT 1: Adding my ViewSets
class TableViewSet(viewsets.ModelViewSet):
serializer_class = TableSerializer
def get_queryset(self):
queryset = Table.objects.all().order_by("name")
# some query_params filtering
return queryset
class ColumnViewSet(viewsets.ModelViewSet):
serializer_class = ColumnSerializer
def get_queryset(self):
queryset = Column.objects.all().order_by("id")
queryset = queryset.filter(name__isnull=False)
# some query_params filtering
return queryset
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
You can work with a Prefetch object [Django-doc] to filter the related object collection, so:
from django.db.models import <strong>Prefetch</strong>
class TableViewSet(viewsets.ModelViewSet):
serializer_class = TableSerializer
def get_queryset(self):
queryset = Table.objects.prefetch_related(
Prefetch('columns', <strong>Column.objects.filter(name__isnull=False)</strong>)
).order_by('name')
# some query_params filtering
return queryset
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0