I am new to django, i tried to practice django rest api implementation.
models.py
from django.db import models
class Parentmodel(models.Model):
ptid = models.IntegerField(primary_key=True)
ptname = models.CharField(default="",max_length=50)
def __str__(self):
return self.ptname
class Studentmodel(models.Model):
stid = models.IntegerField(primary_key=True)
stname = models.CharField(max_length=50)
ptid=models.ForeignKey(Parentmodel,db_column='ptid', related_name="student", on_delete=models.CASCADE)
def __str__(self):
return self.stname
class Marksmodel(models.Model):
Marksid=models.IntegerField(primary_key=True)
maths=models.IntegerField()
physics=models.IntegerField()
science=models.IntegerField()
stid=models.ForeignKey(Studentmodel,db_column='stid', related_name="marks", on_delete=models.CASCADE)
def __str__(self):
return self.Marksid
serializers.py
from rest_framework import serializers
from polls.models import Studentmodel, Marksmodel, Parentmodel
class MarksSerializer(serializers.ModelSerializer):
class Meta:
model=Marksmodel
fields="__all__"
class StudentSerializer(serializers.ModelSerializer):
marks=MarksSerializer(read_only=True,many=True)
class Meta:
model=Studentmodel
fields="__all__"
class ParentSerializer(serializers.ModelSerializer):
student=StudentSerializer(read_only=True,many=True)
class Meta:
model=Parentmodel
fields="__all__"
views.py
from rest_framework import viewsets
from .serializers import StudentSerializer, MarksSerializer, ParentSerializer
from .models import Studentmodel, Marksmodel, Parentmodel
class Studentapi(viewsets.ModelViewSet):
queryset = Studentmodel.objects.all()
serializer_class = StudentSerializer
class Marksapi(viewsets.ModelViewSet):
queryset = Marksmodel.objects.all()
serializer_class = MarksSerializer
class Parentapi(viewsets.ModelViewSet):
queryset = Parentmodel.objects.all()
serializer_class = ParentSerializer
Above code is working fine. I able to get the correct response if i call parent api.
Parentapi Response :
[
{
"ptid": 1,
"student": [
{
"stid": 1,
"marks": [
{
"Marksid": 1,
"maths": 100,
"physics": 100,
"science": 123,
"stid": 1
}
],
"stname": "Nainika",
"ptid": 1
}
],
"ptname": "Sabish"
}
]
Studentapi Response :
[
{
"stid": 1,
"marks": [
{
"Marksid": 1,
"maths": 100,
"physics": 100,
"science": 123,
"stid": 1
}
],
"stname": "Nainika",
"ptid": 1
}
]
My question is how to get the parent data in student api?
Related
I have a puzzle.
These are my models:
class StatusGroup(models.Model):
name = models.TextField()
def __str__(self):
return self.name
class StatusDetail(models.Model):
action = models.CharField(choices=[("CORRECT", "CORRECT"),
("INCORRECT", "INCORRECT")],
max_length=64)
status_group = models.ForeignKey(to=StatusGroup,
on_delete=models.CASCADE,
related_name="status_details")
def __str__(self):
return f"Detail: {self.action}"
serializers:
class StatusDetailSerializer(serializers.ModelSerializer):
class Meta:
model= models.StatusDetail
fields = "__all__"
class StatusGroupSerializer(serializers.ModelSerializer):
status_details = StatusDetailSerializer(many=True)
class Meta:
model = models.StatusGroup
fields = [
"pk",
"status_details",
"name"
]
And a view:
class Status(viewsets.ModelViewSet):
queryset = models.StatusGroup.objects.all()
serializer_class = serializers.StatusGroupSerializer
authentication_classes = []
permission_classes = [permissions.AllowAny]
filter_backends = (DjangoFilterBackend,)
filterset_fields = ['status_details__action']
When I hit localhost:8000/api/status?status_details__action=INCORRECT
I get:
[
{
"pk": 2,
"status_details": [
{
"id": 3,
"action": "CORRECT",
"status_group": 2
},
{
"id": 4,
"action": "INCORRECT",
"status_group": 2
}
],
"name": "Mixed"
}
]
Whereas I would like to have:
[
{
"pk": 2,
"status_details": [
{
"id": 4,
"action": "INCORRECT",
"status_group": 2
}
],
"name": "Mixed"
}
]
How do I force Django to filter the related objects? I can get the result I want in SQL console, but Django adds, all the related objects that belong to the StatusGroup.
I have a misconception, but I don't know what that is.
try this way (using query set):
from django.db.models import Prefetch
queryset = StatusGroup.objects.prefetch_related(
Prefetch('status_details', queryset=StatusDetail.objects.filter(action='what_you_want'), to_attr='action'))
and in your serializer class:
class StatusGroupSerializer(serializers.ModelSerializer):
status_details = StatusDetailSerializer(source='action', many=True, read_only=True)
First you can create a FilterSet class like this:
from django_filters import rest_framework as filters
class StatusGroupFilter(filters.FilterSet):
action = filters.CharFilter(
field_name="status_details__action",
lookup_expr="iexact"
)
class Meta:
model = StatusGroup
fields = ["action"]
Then in your views:
class Status(viewsets.ModelViewSet):
queryset = models.StatusGroup.objects.all()
serializer_class = serializers.StatusGroupSerializer
authentication_classes = []
permission_classes = [permissions.AllowAny]
filter_backends = (DjangoFilterBackend,)
# Set the filterset class here
filterset_class = StatusGroupFilter
Then in the URL you can call localhost:8000/api/status?action=INCORRECT
I use the latest version of The Django REST Framework,
and The table in model is many-to-many related
My current model code looks like this:
model.py
class LvsDeploy(models.Model):
MASTER = 'MASTER'
BACKUP = 'BACKUP'
ROLE_CHOICES = (
(MASTER, 'MASTER'),
(BACKUP, 'BACKUP')
)
id = models.AutoField(primary_key=True)
cluster_name = models.CharField(max_length=30)
dip = models.CharField(max_length=15, verbose_name='DR IP')
role = models.CharField(max_length=10, choices=ROLE_CHOICES, verbose_name="role")
class LoadBalance(models.Model):
id = models.AutoField(primary_key=True)
lb_name = models.CharField(max_length=30, verbose_name='load balance')
cluster = models.ManyToManyField('LvsDeploy',related_name='cluster')
vip = models.CharField(max_length=50, verbose_name='VIP')
port = models.IntegerField(verbose_name='port')
def __str__(self):
return self.lb_name
My serializer code looks like this:
serializers.py
class LvsDeployReadOnly(serializers.ModelSerializer):
class Meta:
model = LvsDeploy
fields = '__all__'
class LoadBalanceSerializer(serializers.ModelSerializer):
cluster_name = serializers.RelatedField(source='cluster.name',read_only=True)
cluster = LvsDeployReadOnly(many=True)
##rs = RSInfoSerializer(many=True, read_only=True)
class Meta:
model = LoadBalance
fields = '__all__'
##extra_fields = ['rs','cluster','cluster_name']
extra_fields = ['rs','cluster','cluster_name']
My views code:
class BalanceList(views.APIView):
def get(self, request):
queryset = LoadBalance.objects.all()
serializer = LoadBalanceSerializer(queryset, many=True)
print(serializer.data)
return Response(serializer.data)
and request actual output:
[
{
"id": 2,
"cluster_name": null,
"cluster": [
{
"id": 1,
"cluster_name": "lvs_sz01",
"dip": "1.1.1.6",
"role": "BACKUP",
},
{
"id": 2,
"cluster_name": "lvs_sz01",
"dip": "1.1.1.5",
"role": "BACKUP",
}
],
"lb_name": "lb001",
"vip": "1.1.1.1",
"port": 80,
}
]
But the cluster_name filed value is same in the dictionary of lists .
I want the output to look like this:
[
{
"id": 2,
"cluster_name": "lvs_sz01",
"cluster": [
{
"dip": "1.1.1.6",
"role": "BACKUP",
},
{
"dip": "1.1.1.5",
"role": "BACKUP",
}
],
"lb_name": "lb001",
"vip": "1.1.1.1",
"port": 80,
}
]
How should I change it? Can you help me ?
I solved it myself with the following method:
class LoadBalanceSerializer(serializers.ModelSerializer):
cluster_name = serializers.SerializerMethodField()
cluster = LvsDeployReadOnly(many=True, read_only=True)
rs = RSInfoSerializer(many=True, read_only=True)
class Meta:
model = LoadBalance
fields = '__all__'
extra_fields = ['rs','cluster','cluster_name']
def get_cluster_name(self,obj):
print(type(obj.lb_name))
lvs_cluster = obj.cluster.all()
cluster_name = [ i.cluster_name for i in lvs_cluster ][0]
print(cluster_name)
return cluster_name
Thanks!
Django Rest Framework - Group data by its parent tag
I have 3 serializers, One for tactics, one for techniques, one for sub techniques, and I'll be adding the sub techniques serializer as an explicit field to the techniques serializer.
models
class Tag(models.Model):
_id = models.CharField(max_length=10)
name = models.CharField(max_length=100)
def __str__(self):
return self._id
def __unicode__(self):
return self._id
class ModelA(models.Model):
_id = models.CharField(max_length=10)
title = models.CharField(max_length=100)
tags = models.ManyToManyField(Tag)
queries = ArrayField(models.TextField(),null=True, blank=True, default=list)
def __str__(self):
return self._id
def __unicode__(self):
return self._id
class ModelB(models.Model):
subtitle = models.ForeignKey(ModelA, on_delete=models.CASCADE)
def __str__(self):
return self.subtitle
serializers
# serializers
class TagSerializer(serializers.ModelSerializer):
def to_representation(self, value):
print(value)
return value.name
class Meta:
model = Tag
fields = ('name',)
class QueriesSerializer(serializers.ModelSerializer):
class Meta:
model = ModelB
fields = '__all__'
class ASerializer(serializers.ModelSerializer):
queries = QueriesSerializer(source='modelb_set', many=True)
tag = TagSerializer(many=True)
class Meta:
model = ModelA
fields = ('_id','title', 'tag','queries',)
class EndUserSerializer(serializers.ModelSerializer):
data = ??
class Meta:
model = ??
fields = '__all__'
I want to create a data visualization API where I need to use the results of ASerializer by their given tag in order to categorize each object into categories based on their associated tag if the object contains two tags, then it should be displayed in both . e.g
desired response
{
[
{
"tag": "Biologyl,
"data": [
{
"_id": str
"title": str
"tag": []
"queries": []
}
]
},
{
"tag": "Denoi2,
"data": [
{
"_id": str
"title": str
"tag": []
"queries": []
}
]
},
]
}
actual response
{
"_id": str
"title": str
"tag": []
"queries": []
}
viewset
#viewsets
class BooksViewSet(mixins.ListModelMixin,
viewsets.GenericViewSet):
queryset = ??.objects.all()
serializer_class = EndUserSerializer
You can use django-rest-multiple-models for receiving multiple querysets in the same view.
https://github.com/MattBroach/DjangoRestMultipleModels
It should look like this:
class BooksViewSet(ObjectMultipleModelAPIView):
querylist = [
{
'querylist': ModelA.objects.filter(tags__name="Biologyl"),
'serializer_class': EndUserSerializer,
'label': 'Biologyl',
},
{
'querylist': ModelA.objects.filter(tags__name="Denoi2"),
'serializer_class': EndUserSerializer,
'label': 'Denoi2',
},
....
]
You can also make it dynamic, but it seems a little bit dangerous👀.
class BooksViewSet(ObjectMultipleModelAPIView):
querylist = [
{
'querylist': ModelA.objects.filter(tags=tag),
'serializer_class': EndUserSerializer,
'label': tag.name,
}
for tag in Tag.objects.all()
]
See more https://django-rest-multiple-models.readthedocs.io/en/latest/object-options.html
I have two models created in my Django app and am looking for a serialization approach so that the IPs are shown in JSON as a list of strings instead of a list of IPAddress objects.
Desired JSON
[
{
"hostname": "www.example.com",
"ip_addresses": [ "1.1.1.1", "2.2.2.2" ]
}
]
Current JSON
[
{
"hostname": "www.example.com",
"ip_addresses": [
{
"id": 1,
"ip_address": "1.1.1.1"
},
{
"id": 2,
"ip_address": "2.2.2.2"
}
]
]
urls.py
class HostSerializer(serializers.ModelSerializer):
hostname = serializers.CharField(source='name', read_only=True)
class Meta:
model = Host
fields = ['hostname', 'ip_addresses']
depth = 1
models.py
class IPAddress(models.Model):
ip_address = models.GenericIPAddressField()
def __str__(self):
return str(self.ip_address)
class Host(models.Model):
name = models.CharField(max_length=100)
ip_addresses = models.ManyToManyField(IPAddress)
def __str__(self):
return self.name
Try out this !
class HostSerializer(serializers.Serializer):
hostname = serializers.CharField(source='name', read_only=True)
ip_addresses = serializers.SerializerMethodField(read_only=True)
def get_ip_addresses(self, instance):
return [item.ip_address for item in instance.ip_addresses.all()]
You can use serializers.SerializerMethodField() to achieve what you want:
class HostSerializer(serializers.ModelSerializer):
hostname = serializers.CharField(source='name', read_only=True)
ip_addresses: serializers.SerializerMethodField()
class Meta:
model = Host
fields = ['hostname', 'ip_addresses']
depth = 1
def get_ip_addresses(self, instance):
return [item.ip_address for item in instance.ip_addresses]
I'm having a problem with displaying the data during serialization.
This is my model:
from django.db import models
class Paradigmn(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return self.name
class Language(models.Model):
name = models.CharField(max_length=50)
paradigm = models.ForeignKey(Paradigmn, on_delete=models.CASCADE)
def __str__(self):
return self.name
class Programmer(models.Model):
name = models.CharField(max_length=50)
languages = models.ManyToManyField(Language, related_name='languages')
def __str__(self):
return self.name
And this is my serializer:
from languages.models import Language, Paradigmn, Programmer
class LanguageSerializer(serializers.ModelSerializer):
paradigms = serializers.ReadOnlyField(source='paradigm.name')
class Meta:
model = Language
fields = ('id', 'name', 'paradigms')
class ParadigmnSerializer(serializers.ModelSerializer):
class Meta:
model = Paradigmn
fields = ('id', 'name',)
class ProgrammerSerializer(serializers.ModelSerializer):
languages = LanguageSerializer(many=True, read_only=True)
class Meta:
model = Programmer
fields = ('id', 'name', 'languages')
And this is the result:
[
{
"id": 1,
"name": "Ryan",
"languages": [
{
"id": 1,
"name": "Java",
"paradigms": "Object-Oriented"
}
]
},
{
"id": 2,
"name": "Jean",
"languages": [
{
"id": 3,
"name": "Python",
"paradigms": "Object-Oriented"
}
]
},
{
"id": 3,
"name": "Michael",
"languages": [
{
"id": 2,
"name": "Elixir",
"paradigms": "Functional"
}
]
}
I just want to show on the languages array, the name of the language instead of the all the details of the language array. What is the best solution for this?
One solution:
from rest_framework.serializers import SerializerMethodField
class ProgrammerSerializer(serializers.ModelSerializer):
languagelist = SerializerMethodField()
def get_languagelist(self, obj):
return [{'name': i.name} for i in obj.languages.all()]
class Meta:
model = Programmer
fields = ('id', 'name', 'languagelist')