how to get id from object in POST request - python

Here I m making a POST request with the following data:
{
"ruleAssignmentDetails": {
"id": 1,
"ruleAssignment": {
"id": 1,
"empId": 1,
"roleId": 1,
"empName": "Emp01",
"roleName": "CEO"
},
"detailSrl": 12,
"rule": 4,
"validityType": "F",
"startDate": "2021-06-14",
"endDate": null,
"frequency": {
"id": 1,
"frequencyName": "Test",
"frequencyTpe": "Weekly"
}
},
"detailSrl": 12,
"parameterName": "Param1",
"valueType": "D",
"overwriteValue": null,
"targetDefination": {
"id": 1,
"targetName": "MIN SALES",
"displayName": "MIN SALES"
}
}
split the objects into respective models but when I m not getting the 'id' of targetDefination and ruleAssignmentDetails
serializer.py
class RuleAssignmentParamsSerializers(serializers.ModelSerializer):
ruleAssignmentDetails = RuleAssignmentDetailsSerializers()
targetDefination = TargetDefinationSerializers()
class Meta:
model = RuleAssignmentParams
fields = (
'id',
'ruleAssignmentDetails',
'detailSrl',
'parameterName',
'valueType',
'overwriteValue',
'targetDefination',
)
def create(self,validated_data):
ruleAssDetails = validated_data.pop('ruleAssignmentDetails')
targetdef = validated_data.pop('targetDefination')
serial = RuleAssignmentParams.objects.create(**validated_data)
return serial
views.py
def getSimpleRules(request):
simpleRules = RuleSimple.objects.all()
simpleRulesSer = OnlySimpleRules(simpleRules,many=True)
return JsonResponse(simpleRulesSer.data,safe=False)
#api_view(['GET'])
def getRuleAssignment(request,pk):
if request.method == 'GET':
print("get working")
q=get_object_or_404(RuleAssignmentParams,pk=pk)
f=RuleAssignmentParamsSerializers(q)
return JsonResponse(f.data)
#api_view(['POST'])
def ruleAssignment(request):
if request.method == 'POST':
data = JSONParser().parse(request)
validated_data = data
serializer=RuleAssignmentParamsSerializers(data=data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data,status=status.HTTP_200_OK,safe=False)
return JsonResponse(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
when I run this it shows me this error:
IntegrityError at /api/rules/ruleassign
(1048, "Column 'ruleAssignmentDetails_id' cannot be null")
How do I get the id of ruleAssignmentDetails and targetDefination ?

The create method in your serializer looks incorrect. Try this:
class RuleAssignmentParamsSerializers(serializers.ModelSerializer):
ruleAssignmentDetails = RuleAssignmentDetailsSerializers()
targetDefination = TargetDefinationSerializers()
class Meta:
model = RuleAssignmentParams
fields = (
'id',
'ruleAssignmentDetails',
'detailSrl',
'parameterName',
'valueType',
'overwriteValue',
'targetDefination',
)
def create(self,validated_data):
ruleAssDetails = validated_data.pop('ruleAssignmentDetails')
targetdef = validated_data.pop('targetDefination')
rule_serial = RuleAssignmentDetailsSerializers()
rule_instances = rule_serial.create(ruleAssDetails)
target_serial = RuleAssignmentDetailsSerializers()
target_instances = rule_serial.create(targetdef)
serial = RuleAssignmentParams.objects.create(**validated_data)
instance = super(RuleAssignmentParams, self).create(validated_data)
instance.ruleAssignmentDetails.add(*rule_instances)
instance.ruleAssignmentDetails.add(*target_instances)
instance.save()
return instance
Only works if the the ForeignKey in your model is not required. (blank=True, null=True). Otherwise you have to your rule_id and target_id to your validated_data.

Related

How to create values to foreign key model in DRF serializer?

When sending json to the server, it shows the following error:
Direct assignment to the reverse side of a related set is prohibited. Use items.set() instead.
Help me please. I recently started to study DRF, and I don't understand how to correctly write def create in django to write data to a foreign key model?
Here is my code
serializer.py
class ConsignmentNoteSerializer(serializers.ModelSerializer):
create_user = serializers.HiddenField(default=serializers.CurrentUserDefault())
create_user = UserSerializer(source='creator', read_only=True)
contragent_detail = ContragentSerializer(source='contragent', read_only=True)
items = ConsignmentItemSerializer(many=True)
class Meta:
model = ConsignmentNote
fields = ['id', 'doc_type', 'date', 'number', 'contragent_detail', 'comment', 'create_user', 'items', 'created']
**def create(self, validated_data):
items_data = self.validated_data.pop('items')
return ConsignmentNote.objects.create(**validated_data)**
Here is the json I am trying to send
{
"id": 9,
"doc_type": "capitalize",
"date": "2022-06-04",
"number": 98,
"contragent_id": 4,
"comment": "",
"items": [
{
"id": 18,
"product": 10,
"buy_price": "200.00",
"sell_price": "500.00",
"quantity": 5
},
],
}
I think You need to upload the item_ids data.
class ConsignmentNoteSerializer(serializers.ModelSerializer):
...
item_ids = serializers.ListField(
child = serializers.IntegerField,
write_only = True
)
class Meta:
model = ConsignmentNote
fields = ['id', 'doc_type', 'date', 'number', 'contragent_detail', 'comment', 'create_user', 'items', 'created', 'item_ids']
def create(self, validated_data):
item_ids = self.validated_data.pop('item_ids')
new_obj = ConsignmentNote.objects.create(**validated_data)
new_obj.set(item_ids)
return new_obj
And in this case, the payload should be
{
"doc_type": "capitalize",
"date": "2022-06-04",
"number": 98,
"contragent_id": 4,
"comment": "",
"item_ids": [18],
}
This solved my problem
def create(self, validated_data):
items = validated_data.pop('items')
note = ConsignmentNote.objects.create(**validated_data)
for item in items:
product = item.pop('product')
item = ConsignmentItem.objects.create(consignmentnote=note, product=product ,**item)
return note

How to get relate model without nested in Django rest framework?

How to get a json with relate model but without nested in Django rest framework?
Code :
Models, Session and Athlete, Athlete models has foreign key relationship with Session
class Session(models.Model):
Id = models.AutoField(primary_key=True)
SessionNo = models.SmallIntegerField()
WinTeam = models.SmallIntegerField(null=True)
class Athlete(models.Model):
Id = models.AutoField(primary_key=True)
Name = models.CharField(max_length=6)
Age = models.SmallIntegerField()
Session = models.ForeignKey(Session, on_delete=models.CASCADE, related_name='athletes')
Status = models.SmallIntegerField()
Serializers
class SessionSerializer(serializers.ModelSerializer):
class Meta:
model = Session
fields = '__all__'
class AthleteSerializer(serializers.ModelSerializer):
Session = SessionSerializer(read_only=True)
class Meta:
model = Athlete
fields = ('Age', 'Status', 'Session')
And views:
def all_athletes(request):
"""
Get all athletes list
"""
queryset = Athlete.objects.all().select_related()
serializer = AthleteSerializer(instance=queryset, many=True)
return Response(serializer.data)
And the API result is :
[
{
"Age": 38,
"Status": 1,
"Session": {
"Id": 13,
"SessionNo": 1,
"WinTeam": null
}
},
{
"Age": 26,
"Status": 1,
"Session": {
"Id": 13,
"SessionNo": 1,
"WinTeam": null
}
},
{
"Age": 35,
"Status": 2,
"Session": {
"Id": 13,
"SessionNo": 1,
"WinTeam": null
}
}
]
It works to get relate model, but I want relate models show without nested, how to do to fit my expectation ?
I expect the API result:
[
{
"Age": 38,
"Status": 1,
"Id": 13,
"SessionNo": 1,
"WinTeam": null
},
{
"Age": 26,
"Status": 1,
"Id": 13,
"SessionNo": 1,
"WinTeam": null
},
{
"Age": 35,
"Status": 2,
"Id": 13,
"SessionNo": 1,
"WinTeam": null
}
]
You could try SerializerMethodFields....
class AthleteSerializer(serializers.ModelSerializer):
Id = serializers.SerialierMethodField(read_only=True)
SessionNo = serializers.SerialierMethodField(read_only=True)
WinTeam = serializers.SerialierMethodField(read_only=True)
class Meta:
model = Athlete
fields = ('Age', 'Status', 'Id', 'SessionNo', 'WinTeam')
def get_Id(self, obj):
return obj.Session.id
def get_SessionNo(self, obj):
return obj.Session.SessionNo
def get_WinTeam(self, obj):
return obj.Session.WinTeam
And then remember to prefetch the Session relationship(s) in your view's queryset or else it will hit the database multiple times for those multiple fields
You can override to_representation() in AthleteSerializer as well. With that you do not need SerialierMethodField.
def to_representation(self, value):
ref = super().to_representation(value)
session = ref.pop("Session")
ref.update(**session)
return ref

How to create a custom API views in Django Rest Framework

I want to create a custom API view based on existing data.
models.py
class Practice(models.Model):
practice_id = models.BigAutoField(primary_key=True)
score = models.SmallIntegerField(null=True)
correct = models.SmallIntegerField(null=True)
wrong = models.SmallIntegerField(null=True)
not_answered = models.SmallIntegerField(null=True)
class Meta:
managed = True
db_table = 'practice'
def __str__(self):
return str(self.practice_id)
serializers.py
class PracticeSerializer(serializers.ModelSerializer):
class Meta:
model = Practice
fields = ('practice_id',
'score',
'correct',
'wrong',
'not_answered',
)
views.py
#api_view(['GET'])
def practice_detail(request, pk):
try:
practice = Practice.objects.get(pk=pk)
except Practice.DoesNotExist:
return JsonResponse({'message': 'The practice does not exist'}, status=status.HTTP_404_NOT_FOUND)
if request.method == 'GET':
exercises_serializer = PracticeSerializer(practice)
return JsonResponse(exercises_serializer.data)
With the code above I get the results of the API view as below using practice id 485 :
/api/practice/485
{
practice_id: 485,
score: 10,
correct: 2,
wrong: 3,
not_answered: 0,
}
Now I want to create a custom API view with the result as below :
{
labels: ["Practice"],
datasets: [
{
label: "Correct",
data: [2],
},
{
label: "Wrong",
data: [3],
},
{
label: "Not_answered",
data: [0],
}
]
}
How to do that?
Is possible to achieve that without create new models?
Define the format in Serializer.to_representation() as documented
.to_representation() - Override this to support serialization, for read operations.
class PracticeSerializer(serializers.ModelSerializer):
class Meta:
model = Practice
fields = ('practice_id',
'score',
'correct',
'wrong',
'not_answered',
)
def to_representation(self, instance):
"""
Object instance -> Dict of primitive datatypes.
"""
return {
"labels": ["Practice"],
"datasets": [
{
"label": "Correct",
"data": instance.correct,
},
{
"label": "Wrong",
"data": instance.wrong
},
{
"label": "Not_answered",
"data": instance.not_answered,
}
]
}
Output:
$ curl http://127.0.0.1:8000/api/practice/485
{"labels": ["Practice"], "datasets": [{"label": "Correct", "data": 2}, {"label": "Wrong", "data": 3}, {"label": "Not_answered", "data": 0}]}

How to create post request in DRF

I m working on this POST request in drf and I lost it somewhere please help.
my models.py
class TargetDefination(models.Model):
targetName=models.CharField(max_length=50)
displayName=models.CharField(max_length=100)
def __str__(self):
return self.targetName
class Target(models.Model):
targetDefn=models.ForeignKey(TargetDefination,on_delete=models.CASCADE)
roleId=models.ForeignKey(Role,on_delete=models.CASCADE)
empId=models.ForeignKey(Employee,on_delete=models.CASCADE)
startDate= models.DateField(default=datetime.date.today)
endDate= models.DateField(null=True,blank=True)
value=models.PositiveIntegerField(default=0)
def __str__(self):
return str(self.empId) + ' ' +str(self.targetDefn)
serializer.py
class TargetSerializers(serializers.ModelSerializer):
targetDefn=TargetDefinationSerializers()
roleId=RoleSerializers()
empId=OnlyEmployeeSerializers()
class Meta:
model = Target
fields = (
'id',
'targetDefn',
'roleId',
'empId',
'startDate',
'endDate',
'value'
)
and this is what I have tried:
views.py
#api_view(['GET','POST'])
def setTarget(request, *args, **kwargs):
if request.method=='GET':
setTrgt=Target.objects.all()
serial=TargetSerializers(setTrgt,many=True)
return JsonResponse(serial.data,safe=False)
elif request.method == 'POST':
data=JSONParser().parse(request)
serial=TargetSerializers(data=data)
if serial.is_valid():
print("working")
target = serial.save()
serializer = TargetSerializers(target)
return JsonResponse(serializer.data,status=status.HTTP_200_OK,safe=False)
return JsonResponse(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
I need to create POST request and the format will be:
{
"id": 6,
"targetDefn": {
"id": 1,
"targetName": "MIN SALES",
"displayName": "MIN SALES"
},
"roleId": {
"id": 1,
"roleName": "CEO",
"description": "Chief executive officer",
"roleReportsTo": null,
"roleReportsToName": null
},
"empId": {
"id": 5,
"empName": "Emp05",
"startDate": "2021-05-04",
"termDate": null
},
"startDate": "2021-05-05",
"endDate": null,
"value": 123
}
this is an example with just values in it.
errors I m getting:
The `.create()` method does not support writable nested fields by default.
Write an explicit `.create()` method for serializer `employee.serializers.TargetSerializers`, or set `read_only=True` on nested serializer fields.
You will have to implement a create() method in your serializer. The implementation of this method should break the request data and then write it into its respective models.
Here is how you can implement the method -
def create(self, validated_data):
#split the objects into multiple objects.
targetDef = validated_data.pop(targetDefn)
#save the objects into its respective models.
targetDefId = TargetDefination.objects.create(**targetDef)
#get the objects of roleId and empID
role = list(validated_data['roleId'].items())
role_id = Role.objects.get(roleName =role[0][1])
emp_id = Employee.objects.get(pk=validated_data['empId']['id'])
target_obj = Target.object.create(targetDef=targetDefId, roleId=role_id, empID=emp_id, startDate=validated_data['startDate'], endDate=validated_data['endDate'], value=validated_data['value'])
return target_obj

Add new values at Django rest framework pagination

I want to add 'isSuccess' at the pagination returns.
For example,
{
"count": 1234,
"next": "http://mydomain/?page=2",
"previous": null,
"isSuccess" : 'Success' # <---- this one
"results": [
{
'id':123,
'name':'abc'
},
{
'id':234,
'name':'efg'
},
...
]
}
I found this way but It didn't work. How can I add new values at Django pagination return?
this is my try:
class Testing(generics.GenericAPIView):
queryset = Problem.objects.all()
serializer_class = userSerializer
pagination_class = userPagination
def get(self, request):
queryset = self.get_queryset()
page = self.request.query_params.get('page')
if page is not None:
paginate_queryset = self.paginate_queryset(queryset)
serializer = self.serializer_class(paginate_queryset, many=True)
tmp = serializer.data
tmp['isSuccess'] = 'Success'
return self.get_paginated_response(tmp)
Give this a try, instead of adding isSuccess to the serializer.data, add it to get_paginated_response().data
def get(self, request):
queryset = self.get_queryset()
page = self.request.query_params.get('page')
if page is not None:
paginate_queryset = self.paginate_queryset(queryset)
serializer = self.serializer_class(paginate_queryset, many=True)
tmp = serializer.data
# tmp['isSuccess'] = 'Success'
response = self.get_paginated_response(tmp)
response.data['isSuccess'] = "Success"
return Response(data=response.data, status=status.HTTP_200_OK)
return Response(data="No Page parameter found", status=status.HTTP_200_OK)
The response will be something like
{
"count": 1234,
"next": null,
"previous": null,
"results": [
{
'id':123,
'name':'abc'
},
...
],
"isSuccess" : 'Success'
}
You can try overriding the get_paginated_response method in the PageNumberPagination
Example:
from rest_framework.pagination import PageNumberPagination
from collections import OrderedDict
class CustomPagination(PageNumberPagination):
def get_paginated_response(self, data):
return Response(OrderedDict([
('count', self.page.paginator.count),
('next', self.get_next_link()),
('previous', self.get_previous_link()),
('results', data),
('isSuccess', "Success") # extra
]))

Categories