I understand that my question is repeated often, but I'm stuck with this.
I want to make a simple API with DRF. I have two models:
models.py
class Rubrics(models.Model):
id = models.AutoField(primary_key=True)
rubric = models.CharField(max_length=255, blank=True, null=True)
class Books(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=255, blank=True, null=True)
author = models.CharField(max_length=255, blank=True, null=True)
date = models.CharField(max_length=255, blank=True, null=True)
rubrics = models.ForeignKey('Rubrics', on_delete=models.DO_NOTHING, related_name='books', blank=True, null=True)
I'd like to view serialized results like this:
[
rubric1: [
{
title: "title1",
author:"author1"
},
book_obj2,
so on
],
rubric2: [
book_obj4,
book_obj5
]
]
views.py
class BooksByRubricView(APIView):
"""List of books by rubrics"""
def get(self, request):
last_date = Books.objects.latest("date").date
books_last = Books.objects.filter(date=last_date)
serializer = RubricsSerializer(books_last, many=True)
return Response(serializer.data)
I try a lot of examples in this theme:
#sorry this garbage
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Books
#fields = ("title",)
exclude = ()
class RubricsSerializer(serializers.ModelSerializer):
rubrics = BookSerializer(read_only=True)
class Meta:
model = Rubrics
fields = ("rubrics",)
#exclude = ()
"""
class RubricSerializer(serializers.ModelSerializer):
#rubrics = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
#books = RecursiveSerializer(many=True)
#print(books)
rubrics = RubricSerializer(read_only=True)
#books = BooksListSerializer(many=True)
class Meta:
model = Books
fields = ("title", "rubrics",)
#fields = ['rubric', 'rubrics']
#fields = ['books', 'rubrics']
"""
But maybe I don't understand the principles of reverse relationships and serializing in DRF. Please, tell me WAIDW. Thanks.
UPD.
I want to operate only on specified sets of data (for example, work with the last uploaded books), not on the whole table Books. So I want to view only rubrics, that are in this set, not all rubrics from table Rubrics. Yes, books have only one rubric id in a specified field, and the rubric has a one-to-many relationship to books.
Well, that's JSON I want to see (of course, all characters appearing in this work, are fictitious. Any resemblance to actual persons, living or dead, is purely coincidental.):
{
"rubric1": [{
"author": "Marley W. Watkins",
"title": "A Step-By-Step Guide to Exploratory Factor Analysis with Stata"
}, {
"author": "Robert E. Davis",
"title": "Auditing Information and Cyber Security Governance; A Controls-Based Approach"
}, {
"author": "Gerhard X. Ritter, Gonzalo Urcid",
"title": "Introduction to Lattice Algebra: With Applications in AI, Pattern Recognition, Image Analysis, and Biomimetic Neural Networks"
}],
"rubric2": [{
"author": "Richard Cross and JT Paasch",
"title": "The Routledge Companion to Medieval Philosophy"
}, {
"author": "Nicholas Allott (editor), Terje Lohndal (editor), Georges Rey (editor)",
"title": "A Companion to Chomsky"
}, {
"author": "Olakunle George",
"title": "A Companion to African Literatures"
}, {
"author": "Tim Byrnes, Ebubechukwu O. Ilo-Okeke",
"title": "Quantum Atom Optics: Theory and Applications to Quantum Technology"
}],
"rubric3": [{
"author": "Hiroyoshi Naito",
"title": "Organic Semiconductors for Optoelectronics"
}, {
"author": "Bassem R. Mahafza, Scott C. Winton",
"title": "Handbook of Radar Signal Analysis"
}, {
"author": "Sean McManus, Mike Cook",
"title": "Raspberry Pi For Dummies, 4th Edition"
}]
}
I realize it in plain Django:
class BooksByRubricView(APIView):
"""List of books by rubrics"""
def get(self, request):
last_date = Books.objects.using('books').latest("date").date
books_last = Books.objects.using('books').filter(date=last_date)
categories = []
res_dict = {}
for item in books_last:
categories.append(item.rubrics_id)
categories = set(categories)
for item in categories:
temp_list = []
temp_qs = books_last.filter(rubrics_id=item)
for i in temp_qs:
temp_list.append({"author": i["author"], "title": i["title"]})
res_dict["rubric"+str(item)]=list(temp_list)
# res = json.dumps(res_dict)
return JsonResponse(res_dict, safe=False, json_dumps_params={'ensure_ascii': False})
can I realize it with DRF serializers or simplest way is not f*cking any brains and return JSON as above?
Update2:
Well, after some magic with serializers and generic.APIView I've got a result not exactly expected, but very closest to that. Example (of course, all characters appearing in this work, are fictitious. Any resemblance to real persons, living or dead, is purely coincidental)
views.py
class BooksByRubricView2(generics.ListAPIView):
"""Books grouped by rubrics"""
serializer_class = RubricsSerializer2
queryset = Rubrics.objects.all()
#OR without generic
class BooksByRubricView3(APIView):
def get(self, request):
r = Rubrics.objects.all()
serializer=RubricsSerializer2(r,many=True)
return Response(serializer.data)
serializers.py
class FilteredListSerializer(serializers.ListSerializer):
"""Serializer to filter Book table, look for latest date for every rubric"""
def to_representation(self, data):
latest_data = data.latest("date").date
data = data.filter(date=latest_data)
return super(FilteredListSerializer, self).to_representation(data)
class BookSerializer2(serializers.ModelSerializer):
class Meta:
model = Books
list_serializer_class = FilteredListSerializer
fields = (
"title",
"author",
"date")
class RubricsSerializer2(serializers.ModelSerializer):
books = BookSerializer2(many=True, read_only=True)
class Meta:
model = Rubrics
fields = ("rubric", "books",)
result:
[
{
"rubric": "Computers",
"books": [
{
"title": "A Step-By-Step Guide to Exploratory Factor Analysis with Stata",
"author": "Marley W. Watkins",
"date": "2021-08-08"
},
{
"title": "Auditing Information and Cyber Security Governance; A Controls-Based Approach",
"author": "Robert E. Davis",
"date": "2021-08-08"
}
]
},
{
"rubric": "Education",
"books": [
{
"title": "The Routledge Companion to Medieval Philosophy",
"author": "Richard Cross and JT Paasch",
"date": "2021-08-08"
}
]
},
so on
}
It's a dirty way because every Rubric from table Rubrics creates its own query to table Books and each Rubric has its latest date. But DRF filtering will be the next step.
There is no field rubrics in Rubrics model, available fields are:
id,rubric from model itself,
books_set which represent all books that have FK reference to that Rubrics instance. Take a look at this official docs
Book have one rubric (rubrics foreign key), and rubrics have multiple books (books_set). I would also suggest changing FK name from rubrics to rubric since there can be only one.
Try this and work from there:
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Books
#fields = ("title",)
exclude = ()
class RubricsSerializer(serializers.ModelSerializer):
class Meta:
model = Rubrics
fields = ("books_set",)
#exclude = ()
First i've tried to get the result that you wanted using your view and just dit not worked! So I've created another view:
from .serializers import *
from rest_framework import generics
from .models import *
class BooksByRubricView(generics.ListAPIView):
serializer_class = RubricsSerializer
queryset = Rubric.objects.all()
# You should try!
And course I also had to create a path (Just for tests! Ignore it!):
from django.urls import path
from .views import BooksByRubricView
urlpatterns = [
path('books/', BooksByRubricView.as_view(), name='books')
]
In your models:
from django.db import models
class Rubric(models.Model):
id = models.AutoField(primary_key=True) # Do not use plural in the models name!
rubric_name = models.CharField(max_length=255, blank=True, null=True)
class Meta:
ordering = ['id'] # Create a ordering!
def __str__(self):
return self.rubric_name
class Book(models.Model):
rubric = models.ForeignKey(Rubric, related_name='rubrics', on_delete=models.CASCADE)
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=255, blank=True, null=True)
author = models.CharField(max_length=255, blank=True, null=True)
date = models.CharField(max_length=255, blank=True, null=True)
class Meta:
ordering = ['id'] # Create a ordering!
In your serializers.py:
from rest_framework import serializers
from .models import *
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = (
"title",
"author",
"date"
)
class RubricsSerializer(serializers.ModelSerializer):
rubrics = BookSerializer(many=True, read_only=True)
class Meta:
model = Rubric
fields = (
"id", # Put an Id if you want!
"rubrics",
)
Maybe the only problem was with your view! So I just did all this to get the result that you want but localy; images of the result:
Related
So let's say I have this 2 models
Poll:
class Poll(models.Model):
title = models.CharField(max_length=255)
is_active = models.BooleanField(default=True)
is_available = models.BooleanField(default=True)
date_created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
Options:
class Option(models.Model):
title = models.CharField(max_length=255)
poll = models.ForeignKey(Poll, on_delete=models.CASCADE)
def __str__(self):
return f'{self.poll.title} - {self.title}'
These two objects are connected with ForeignKey. Now let's say I have a frontend that renders both options and the question (title of the poll) but I only want make a single API call to the backend. Basically I need the API to looked like this:
{
"title": "Which is the best frontend framework?",
"options":[
{
"id": 1,
"title": "React"
},
{
"id": 2,
"title": "Vue"
},
{
"id": 3,
"title": "Angular"
}
]
}
How what method/technique should I use to merge two objects like this?
Based on DRF docs
class OptionSerializer(serializers.ModelSerializer):
class Meta:
model = Option
fields = ['id', 'title']
class PollSerializer(serializers.ModelSerializer):
options = OptionSerializer(source='option_set', many=True)
class Meta:
model = Poll
fields = ['title', 'options']
I am trying to filter related_name field with a query if it's possible. I serialize the tables.
class ProjectsSerializers(serializers.ModelSerializer):
class Meta:
model = Projects
fields = ["id", "project_id", "project_name", "tasks"]
depth = 1
Above in the fields list. tasks is the related_table so in the tasks table I have task_created_at field and when I retrieve the projects table. I want to filter it by that field.
def get_projects(request):
projects = Projects.objects.filter(task_created_at__startswith="2020-04")
serializer = ProjectsSerializers(projects, many=True)
return Response(serializer.data)
Of course this: task_created_at__startswith="2020-04" isn't working. Because task_created_at is not in the projects. it's in the related_name which is tasks. So is there a way to filter tasks with getting projects
and the relevent models:
class Projects(models.Model):
project_id = models.CharField(max_length=255)
project_name = models.CharField(max_length=255)
def __str__(self):
return self.project_name
class Meta:
db_table = "projects"
class Tasks(models.Model):
projects = models.ForeignKey(Projects, on_delete=models.CASCADE, related_name='tasks', blank=True, null=True)
task_price = models.IntegerField(blank=True, null=True)
task_total_price = models.IntegerField(blank=True, null=True)
task_created_at = models.CharField(max_length=255, blank=True, null=True)
def __str__(self):
return self.ad_kind
class Meta:
db_table = "tasks"
the example data:
[
{
"id": 6,
"order_id": null,
"project_id": "23123",
"project_name": "プレサンス グラン 茨木駅前",
"company_name": null,
"analytics_id": null,
"advertisements": [],
"tasks": [
{
"id": 1,
"task_total_price": null,
"task_created_at": "2020-04-02",
"task_due_date": "2020-04-07",
"task_modified_at": "2020-04-07T06:42:41.447Z",
"projects": 6
},
{
"id": 2,
"task_total_price": null,
"task_created_at": "2020-02-02",
"task_due_date": "2020-03-07",
"task_modified_at": "2020-04-07T06:42:41.447Z",
"projects": 6
},
]
}
]
You can JOIN two tables/models by __ (a double underscore).
from django.db.models import Prefetch
def get_projects(request):
projects = Projects.objects.prefetch_related(
Prefetch('tasks', queryset=Tasks.objects.filter(task_created_at__istartswith='2020-04'))
).filter(tasks__task_created_at__istartswith='2020-04')
serializer = ProjectsSerializers(projects, many=True)
return Response(serializer.data))
Reference
Lookups that span relationships
Prefetch(...)
You will need to use a subquery:
def get_projects(request):
project_ids = Task.objects.filter(
task_created_at__startswith='2020-04').values('project_id')
projects = Project.objects.filter(id__in=project_ids)
serializer = ProjectsSerializers(projects, many=True)
return Response(serializer.data)
Also, please don't use plural table names ;-)
Lastly, I'd recommend using a DateTimeField for storing dates, instead of using a CharField.
To be able to dynamically change the representation of an object, you can modify the serializer. One way to filter the tasks is to provide a serializers.SerializerMethodField that filters the tasks dynamically.
class TaskSerializer(serializers.ModelSerializer):
class Meta:
model = Task
fields = [ ... your fields ... ]
class ProjectSerializer(serializers.ModelSerializer):
filtered_tasks = serializers.SerializerMethodField()
class Meta:
model = Project
fields = ["id", "project_id", "project_name", "filtered_tasks"]
depth = 1
def get_filtered_tasks(self, obj):
tasks = Task.objects.filter(created_at__startswith="2020-04")
return TaskSerializer(tasks, many=True).data
However, I don't like this approach. I think you should reconsider how you present the data. It feels like your binding the data too hard together. Although, I don't know your use-case so I cannot come with any concrete suggestions.
Also, I've changed the names here so the models are singular, as it's the convention.
I am using Django Rest Framework for a project and I am running into a problem. When the frontend creates a Team they want to reference all relationships with an ID, but when getting the Team, they want the data from the relationship. How can I achieve this?
models:
class Team(models.Model):
class Meta:
db_table = "team"
team_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=100)
organization = models.ForeignKey(Organization, on_delete=models.CASCADE)
class Organization(models.Model):
class Meta:
db_table = "organization"
organization_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=100)
class Position(models.Model):
class Meta:
db_table = "position"
position_id = models.AutoField(primary_key=True)
team = models.ForeignKey(Team, on_delete=models.CASCADE, related_name="positions")
class Player(model.Model):
class Meta:
db_table = "player"
player_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=100)
positions = models.ManyToManyField(Position, related_name="players")
serializers:
class TeamSerializer(serializers.ModelSerializer):
class Meta:
model = Team
fields = ["team_id", "name", "organization", "positions"]
positions = PositionSerializer(many=True) # This is merely for output. There is no need to create a position when a team is created.
organization = OrganizationSerializer() # Since an organization already exists I'd like to just give an organization_id when creating/editing a team.
# I don't think the other serializers matter here but can add them on request.
So when doing POST or PATCH on a team, I'd like the front end to be able to pass this payload
{
"name": "My Team",
"organization": 1
}
but when doing a GET on a team, I'd like the front end to receive this response.
{
"team_id": 1,
"name": "My Team",
"organization": {
"organization_id": 1,
"name": "My Organization"
},
"positions": [{
"position_id": 1,
"players": [{
"player_id": 1,
"name": "Member 1"
}
]
}
Is there a a way to achieve this?
In such situations define two serializers, one is for read operations and one is for write operations.
class TeamWriteSerializer(serializers.ModelSerializer):
# see, here no nested relationships...
class Meta:
model = Team
fields = ["name", "organization"]
class TeamReadSerializer(serializers.ModelSerializer):
class Meta:
model = Team
fields = ["team_id", "name", "organization", "positions"]
positions = PositionSerializer(many=True)
organization = OrganizationSerializer()
and now, use these two serializers properly in your views. For example, I hope you are using the ModelViewSet in views,
class TeamModelViewSet(viewsets.ModelViewSet):
def get_serializer_class(self):
if self.request.method.lower() == 'get':
return TeamReadSerializer
else:
return TeamWriteSerializer
recently i am converting my project into DRF and the serializer.py is following:
from rest_framework import serializers
from .models import Menu,MenuCategory,MenuItem
class MenuItemSerializer(serializers.ModelSerializer):
class Meta:
model = Menu
fields = ['name', 'additional_text', 'order']
class MenuCategorySerializer(serializers.ModelSerializer):
menuitem = serializers.StringRelatedField(many=True, read_only=True)
class Meta:
model = MenuCategory
fields = ['order', 'name', 'description','menuitem']
def create(self, MenuCategory, MenuItem,validated_data):
menucategory=MenuCategory.objects.create(**validated_data)
item_data = validated_data.pop('menuitem')
for it_data in item_data:
MenuItem.objects.create(menucategory=menucategory, **item_data)
return menucategory
class MenuSerializer(serializers.ModelSerializer):
menucategory = serializers.StringRelatedField(many=True, read_only=True)
class Meta:
model = Menu
fields = ['name', 'additional_text', 'order','menucategory']
def create(self,MenuCategory, Menu, validated_data):
category_data = validated_data.pop('menucategory')
menu= Menu.objects.create(**validated_data)
for cat_data in category_data:
MenuCategory.objects.create(menu=menu, **category_data)
return menu
When i browse http://localhost:8000/api/, it shows:
[
{
"name": "Breakfast",
"additional_text": "Served between 8:00am and11:00am",
"order": 1,
"menucategory": [
"MenuCategory object (3)",
"MenuCategory object (4)"
]
},
{
"name": "Lunch",
"additional_text": "Served between 12:00pm and 3:00pm",
"order": 2,
"menucategory": [
"MenuCategory object (1)",
"MenuCategory object (5)",
"MenuCategory object (7)"
]
},
{
"name": "Dinner",
"additional_text": "Served between 6:00pm and 10:00pm",
"order": 3,
"menucategory": [
"MenuCategory object (2)",
"MenuCategory object (6)",
"MenuCategory object (8)"
]
},
{
"name": "Drinks",
"additional_text": "Happy hour 3:00pm to 6:00 pm",
"order": 4,
"menucategory": [
"MenuCategory object (9)",
"MenuCategory object (10)",
"MenuCategory object (11)"
]
}
]
but the list shouldn't be showing this menuobject kind of things. it should show the item and category name with the price and other fields. here is my views.py:
from rest_framework import generics
from .models import Menu,MenuCategory,MenuItem
from .serializers import MenuCategorySerializer,MenuSerializer,MenuItemSerializer
class ListMenuCategory(generics.ListAPIView):
queryset = MenuCategory.objects.order_by('order')
serializer_class = MenuCategorySerializer
class ListMenu(generics.ListAPIView):
queryset = Menu.objects.order_by('order')
serializer_class = MenuSerializer
class ListMenuItem(generics.ListAPIView):
queryset = MenuItem.objects.order_by('order')
serializer_class = MenuItemSerializer
and my models.py as followed:
from django.db import models
class MenuItem(models.Model):
menu_category = models.ManyToManyField('MenuCategory', related_name='menuitem',help_text='The menus that this category belongs to, i.e. \'Lunch\'.')
name = models.CharField(max_length=48, help_text='Name of the item on the menu.')
description = models.CharField(max_length=128, null=True, blank=True, help_text='The description is a simple text description of the menu item.')
order = models.IntegerField(default=0, verbose_name='order', help_text='The order is to specify the order in which items show up on the menu.')
price = models.FloatField(help_text='The price is the cost of the item.')
class Meta:
ordering = ['order', 'name']
def __unicode__(self):
return self.name
class MenuCategory(models.Model):
menu = models.ManyToManyField('Menu', related_name='menucategory',help_text='The menus that this category belongs to, i.e. \'Lunch\'.')
name = models.CharField(max_length=48, help_text='Name of the item on the menu.')
description = models.CharField(max_length=128, null=True, blank=True, help_text='The description is a simple text description of the menu item.')
order = models.IntegerField(default=0, verbose_name='order', help_text='The order is to specify the order in which items show up on the menu.')
class Meta:
ordering = ['order', 'name']
def __unicode__(self):
return self.name
class Menu(models.Model):
name = models.CharField(max_length=32, verbose_name='menu category name')
additional_text = models.CharField(max_length=128, null=True, blank=True, help_text='The additional text is any bit of related information to go along with a menu category, i.e. the \'Pasta\' category might have details that say \'All entrees come with salad and bread\'.')
order = models.IntegerField(default=0, help_text='The order is the order that this category should appear in when rendered on the templates.')
class Meta:
ordering = ['order', 'name']
def __unicode__(self):
return self.name
how should i do the query and how can i fix my DRF api list?
You should use the serializer for the related model if you wish to use the related serializer, not a serializers.StringRelatedField
class MenuSerializer(serializers.ModelSerializer):
menucategory = MenuCategorySerializer(many=True, read_only=True)
I am new to Django.I am using Django REST Framework and I need to get json from serializers in the following format:
{
"result" : 200,
"categories" : [{
"id" : "V001",
"name": "Vehicles",
"description": "All types of motor and non-motor vehicles",
"icon": "http://images.maa.ae/static/icons/vehicles.png",
"subcategories": [{
"id" : "V00101",
"name": "Cars",
"description": "Motor Cars",
"subcategories": [{
"id" : "V0010101",
"name": "Passenger Cars",
"description": "All types of passenger cars"
}]
},
{
"id" : "V00102",
"name": "Bikes",
"description": "Bikes",
"subcategories": [{
"id" : "V0010201",
"name": "Motor Bikes",
"description": "All kinds of motor bikes"
},
{
"id" : "V0010202",
"name": "Sports Bikes",
"description": "All kinds of sports bikes"
}]
}]
}]
}
My Model class is:
class Category(models.Model):
_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=128)
description = models.CharField(max_length=150,null=True, blank=True)
icon = models.ImageField(upload_to='icons',null=True, blank=True)
parent_id = models.ForeignKey('self', null=True, blank=True)
and my serializers class is:
class CategorySerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Category
fields = ('_id', 'name', 'description', 'icon')
From above implementation I can get Array of Category objects in JSON format.
But I don't know how can I include 'subcategories' in my serializer class.Please help me to get an output similar to json shown in above format.
Use Django Rest Framework.
http://www.django-rest-framework.org/
Keep your code DRY
from rest_framework import serializers
class CategoriesSerializer(serializers.ModelSerializer):
class Meta:
model = Categories
Views
from rest_framework import viewsets
from .serializers import CategoriesSerializer
class CategoryViewSet(viewsets.ModelViewSet):
queryset = Categories.objects.all()
serializer_class = CategoriesSerializer
Example
models.py:
class Sprints(models.Model):
name = models.CharField(default='', blank=True, max_length=90)
description = models.TextField(default='')
class Tasks(models.Model):
date_posted = models.DateTimeField(auto_now_add=True)
name = models.CharField(default='', blank=True, max_length=90)
end = models.DateTimeField(null=True, blank=True)
sprint = models.ForeignKey(Sprints, related_name='tasks')
class Meta:
ordering = ['-date_posted']
unique_together = ['name', 'sprint']
serializers.py:
class TaskSerializer(serializers.ModelSerializer):
class Meta:
model = Tasks
fields = ('id', 'name', 'date_posted', 'end')
class SprintSerializer(serializers.ModelSerializer):
tasks = TaskSerializer(many=True, read_only=True)
class Meta:
model = Sprints
fields = ('id', 'name', 'description', 'tasks')
views.py
class SprintsViews(viewset.ModelViewSet):
queryset = Sprints.objects.all()
serializer_class = SprintSerializer
You can also add a slug field to the models to make them easier to deal with, but this is how for now :)
You should consider having a look at THIS. The usage of depth meta attribute enables you to retrieve related objects to the depth you set.
By doing so, it automatically retrieves nested data.
It is very convenient to avoid using serializers in both sides and thus having ImportError caused by cycles too.
Use related_name and on_delete on your parent_id field in models.py file
class Category(models.Model):
_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=128)
description = models.CharField(max_length=150,null=True, blank=True)
icon = models.ImageField(upload_to='icons',null=True, blank=True)
parent_id = models.ForeignKey('self', null=True, blank=True, related_name='children', on_delete=models.CASCADE)
Now add the packege pip install djangorestframework-recursive on your project
serializers.py:
##################################
from rest_framework_recursive.fields import RecursiveField
##################################
class CategorySerializer(serializers.ModelSerializer):
children = RecursiveField(many=True)
class Meta:
model = Category
fields = ('_id', 'name', 'description', 'icon', 'parent_id', 'children')
views.py (Serializers view file):
class CategoryListAPIView(generics.ListAPIView):
serializer_class = CategorySerializer
queryset = Category.objects.filter(parent_id__isnull=True)
urls.py:
############################
############################
urlpatterns = [
path('category/', views.CategoryListAPIView.as_view(), name="categoryAPI"),
######################################
]