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
Related
Still very new to Django. I'm trying to send a post request to my backend from insomnia right now and I'm getting the error Getting null value when I'm passing in the ID value.
model:
class Run(models.Model):
gameId = models.ForeignKey(Game,on_delete=models.CASCADE, related_name='runs')
userId = models.ForeignKey(User,on_delete=models.CASCADE, related_name='game')
name = models.CharField(max_length=30)
isComplete = models.BooleanField(default=False)
deaths = models.IntegerField()
badges = models.IntegerField()
def __str__(self):
return self.name
Here is my seralizer:
class RunSerialzer(serializers.HyperlinkedModelSerializer):
gameId = GameSerialzer(
read_only = True
)
userId = UserSerialzer(
read_only = True
)
class Meta:
model = Run
fields=('id','name','isComplete','deaths','badges','userId','gameId')
My view:
class RunList(generics.ListCreateAPIView):
queryset = Run.objects.all()
serializer_class = RunSerialzer
And my request I'm making:
{
"gameId":1,
"userId": 1,
"name":"testrun2",
"deaths":0,
"badges": 0,
"isComplete": false
}
and the second one I tried
{
"gameId": {
"id": 1,
"name": "Vintage White",
"photo": "https://archives.bulbagarden.net/media/upload/thumb/0/08/White_EN_boxart.png/250px-White_EN_boxart.png"
},
"userId": {
"id": 1,
"name": "TestUser"
},
"name":"testrun2",
"isComplete": false,
"deaths": 0,
"badges": 0
}
I feel like I need to create either a new Serailizer to get the instance I want in my Game model with the pk im passing in the request
since you are using read_only=True on your serializer for two of your fields you need to pass gameId and userId manually to save method of serializer.
in your view(RunList) you should overwrite perform_create method like following:
def perform_create(self, serializer):
gameId = self.request.data.get('gameId')
userId = self.request.data.get('userId')
return serializer.save(gameId=gameId, userId=userId)
Whenever i called my booking function with a post method in that it throws me an error of 'Invalid Data Type it expected dict but its an int'. So when i debug that i found a problem in my serializers so Please help me to resolve the error
model.py
class Booking(models.Model):
details = models.ForeignKey(PersonalDetails, on_delete=models.CASCADE)
quantity = models.IntegerField(null=False)
total_amount = models.IntegerField()
show = models.ForeignKey(ShowTime, on_delete=models.CASCADE)
def __str__(self) -> str:
return self.total_amount
views.py
class BookingTicketsQuery(APIView):
permission_classes = [IsAuthenticated]
def get(self, request, format=None):
booking_id = request.query_params.get('booking_no', None)
if booking_id is not None:
queryset = Booking.objects.get(id=booking_id)
else:
return Response("invalid", status=status.HTTP_409_CONFLICT)
seriliazer = BookingSerializer(queryset)
return Response(seriliazer.data)
def post(self, request, format=None):
recieve_data = JSONParser().parse(request)
showtime = ShowTime.objects.get(id=recieve_data['show'])
print(showtime)
if recieve_data['quantity'] > (showtime.total_seats - showtime.booked_seats):
return Response("Error: No seats available", status=status.HTTP_409_CONFLICT)
recieve_data['total_amount'] = showtime.total_price * \
recieve_data['quantity']
showtime.booked_seats += recieve_data['quantity']
showtime.save()
serializer = BookingSerializer(data=recieve_data)
if serializer.is_valid():
booking_obj = serializer.save()
return Response(booking_obj.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
serializers.py
class ShowMovieSerializer(serializers.ModelSerializer):
cinema = CinemaSerializer()
movie = MovieSerializer()
class Meta:
model = ShowTime
fields = ('id', 'show_start_time', 'show_end_time',
'total_seats', 'booked_seats', 'cinema', 'movie')
class BookingSerializer(serializers.ModelSerializer):
show = ShowMovieSerializer()
details = PersonalDetailsSerializer()
class Meta:
model = Booking
fields = ('id', 'total_amount', 'quantity', 'details', 'show')
traceback
Bad Request: /api/v1/bookings/
[19/Jul/2021 12:07:20] "POST /api/v1/bookings/ HTTP/1.1" 400 168
{
"details": {
"non_field_errors": [
"Invalid data. Expected a dictionary, but got int."
]
},
"show": {
"non_field_errors": [
"Invalid data. Expected a dictionary, but got int."
]
}
}
my post data:
{
"details": 1,
"quantity":1,
"show":1
}
You added a ShowMovieSerializer() and PersonalDetailsSerializer(). Therefore drf expects data that represents both models (nested data). What you have to do instead of posting { "details": 1, "quantity":1, "show":1 }-data you have to adjusted your data that represents your model. You are posting data with a pk of your Movie and Show.
For instance:
{
"id":....,
"total_amount": ....,
....
"movie": {
"title": ...., # fields are only for explanation
"length": ....
},
"show": {
"title": ....,
"actor": ....
}
}
If you only want to establish a relationship between you ShowTime and Booking you have to remove your serializers.
dealing with nested data
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.
I'm trying to create a serializer which outputs the Report and also the User information.
My task is accomplished by this serializer:
class ReportSerializer(serializers.ModelSerializer):
latitude = serializers.CharField()
longitude = serializers.CharField()
city = serializers.IntegerField()
type = serializers.IntegerField()
# We have created a field which returns a value from get_marker_icon_url
marker_icon = serializers.SerializerMethodField('get_marker_icon_url')
status_str = serializers.SerializerMethodField('convert_status_toStr')
type_str = serializers.SerializerMethodField('convert_type_toStr')
status_color = serializers.SerializerMethodField('get_status_color')
likes = serializers.SerializerMethodField('random_likes')
user = ReportUserSerializer()
class Meta:
model = Reports
fields = [
'user',
'id',
'type',
'city',
'latitude',
'longitude',
'likes',
'type_str',
'status_str',
'status_color',
'attached_message',
'marker_icon',
'attached_photo',
'date_created'
]
...
With this code my serializer returns a response like this:
[
{
"user": {
"id": 1,
"username": "3nematix",
"profile_pic": "http://192.168.0.29:8000/frontend/static/frontend/images/reports/user_profile_pic.jpg",
"verified": false
},
"id": 1,
"type": 9,
"city": 0,
"latitude": "6.5123333",
"longitude": "51.512586",
"likes": 27,
"type_str": "OTHER",
"status_str": "PENDING",
"status_color": "orange",
"attached_message": "test",
"marker_icon": "OTHER",
"attached_photo": "http://192.168.0.29:8000/frontend/static/frontend/images/reports/user_profile_pic_VRjIYTs.jpg",
"date_created": "2020-10-21T23:19:06.899302Z"
},
......
]
And this is exactly what I need, but the problem is that when I'm trying to create a new object by a POST request, I get this response:
{
"user": [
"This field is required."
]
}
If I would remove 'user' from Meta and user = ReportUserSerializer() from the ReportSerializer class, then I can create a new object, but when I wish to get the Reports I with the Users information I need to add these two again, how can I fix it?
You need to fill the user field yourself before calling save.
Here's the easy way:
class YourView(generics.ListCreateAPIView):
...
def perform_create(self, serializer):
serializer.save(user=self.request.user)
Or slightly differently:
class YourView(generics.ListCreateAPIView):
...
def perform_create(self, serializer):
serializer.validated_data['user'] = self.request.user
return super().perform_create(serializer)
The problem: when I pass someModelSerializer.data as a nested data for anotherModelSerializer, and after that I pass anotherModelSerializer.data to Response, in the response I see only two fields of SomeModel instead of 5. But when I pass someModelSerializer.data directly to Response, I can see that all model fields are present.
Details below.
I have TranslationHistory model
class TranslationHistory(models.Model):
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
string = models.CharField(max_length=255)
count = models.IntegerField(default=1)
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='translation_history')
and it's TranslationHistorySerializer
class TranslationHistorySerializer(serializers.ModelSerializer):
class Meta:
model = TranslationHistory
user = serializers.PrimaryKeyRelatedField(read_only=True, default=None)
count = serializers.IntegerField(read_only=True)
def validate_user(self, value):
return self.context['request'].user
def update(self, instance, validated_data):
instance.count += 1
instance.save()
return instance
I also have a virtual entity Translation, which is not a model. It has it's own serializer.
class TranslationSerializer(serializers.Serializer):
translation_history = TranslationHistorySerializer() # nested serializer
translation = serializers.CharField()
In my view, if I do like this,
history = TranslationHistory().findByUserAndString(request.user, string)
historySerializer = TranslationHistorySerializer(history)
return Response(historySerializer.data, status=status.HTTP_200_OK)
I have the response like this.
{
"id": 18,
"user": 1,
"count": 72,
"created": "2015-07-15T15:35:50.751219Z",
"updated": "2015-07-24T15:37:04.247469Z",
"string": "hello"
}
But if in my view I do like this,
history = TranslationHistory().findByUserAndString(request.user, string)
historySerializer = TranslationHistorySerializer(history)
serializer = TranslationSerializer(
data={
'translation_history': historySerializer.data,
'translation': 'hello'
},
context={'request': request}
)
serializer.is_valid(raise_exception=True)
return Response(serializer.data, status=status.HTTP_200_OK)
I have the response like this.
{
"translation_history": {
"user": 1,
"string": "hello"
},
"translation": "hello"
}
Why am I getting only user and string fields in this case?