Django : This field is required on POST request - python

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)

Related

Getting null value in column "userId_id" of relation "pnrDB_run when sending a POST to django backend

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)

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 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

django.db.utils.IntegrityError: NOT NULL constraint failed fom Postman

I am trying to create a simple model with foreign keys using Django rest framework.
This are the models:
class Route(models.Model):
place_origin = models.ForeignKey(
Place, null=False, on_delete=models.DO_NOTHING)
class Place(models.Model):
name = models.CharField(max_length=50, null=False)
This are the serializers for each model:
class PlaceSerializer(serializers.ModelSerializer):
class Meta:
model = Place
fields = ["id", "name"]
class RouteSerializer(serializers.ModelSerializer):
place_origin = PlaceSerializer(many=False, read_only=True)
class Meta:
model = Route
fields = ["id", "place_origin"]
This RouteSerializer has the place_origin property in order to show the place details(all the fields from it) when I am looking at the route detail. What I mean is for routes I want to display:
[
{
"id": 1,
"place_origin": {
"id": 1,
"name": "New york"
}
},
{
"id": 2,
"place_origin": {
"id": 2,
"name": "Boston"
}
}
]
And not just:
[
{
"id": 1,
"place_origin": 1
},
{
"id": 2,
"place_origin": 2
}
]
This is the view:
#api_view(['POST'])
def routes_new_route_view(request):
"""
Create a new route
"""
if request.method == "POST":
data = JSONParser().parse(request)
place_origin = Place.objects.get(id=data["place_origin"])
data["place_origin"] = PlaceSerializer(place_origin)
data["place_origin"] = data["place_origin"].data
serializer = RouteSerializer(data=data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data, status=201)
else:
return JsonResponse(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
I want to send the request from postman this way:
{
"place_origin": 3
}
But I am getting the error from the title.
Thanks for all the help!
The error is that you're trying to send data via a PlaceSerializer but this field is read_only. On the other hand, your DB expects place_origin since you precised null=False in your model. Both combined gives the error "Not NULL constraint failed".
The easiest way is to slightly modify your serializer in order to have one field for write and another for read.
class RouteSerializer(serializers.ModelSerializer):
place_origin = PlaceSerializer(many=False, read_only=True)
place = serializers.PrimaryKeyRelatedField(source="place_origin",queryset=Place.objects.all(),write_only=True)
class Meta:
model = Route
fields = ["id", "place_origin", "place"]
Here, you will use place field as a way to create the relationship with your Route instance.

Django REST Framework Model Serializer is not showing all fields for POST method?

I'm trying to make custom create()method to save my user profile when a User is created, the serializer works perfect for the GET method, but for POST it only shows one field instead of all fields.
I specified the fields = '__all__' property, but still don't work
GET:
JSON Response:
[
{
"job_title": {
"id": 1,
"name": "Desarrollador"
},
"birthdate": "2019-11-06",
"roles": [
{
"id": 1,
"name": "Administrador",
"description": "Administrador del sistema",
"key": "ADMIN"
}
]
}
]
POST:
Expected JSON:
[
{
"birthdate": "2019-11-06",
}
]
Serializers:
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = '__all__'
depth = 1
class UserSerializer(serializers.ModelSerializer):
user_profile = UserProfileSerializer(read_only=False, many=False)
class Meta:
model = User
fields = '__all__'
depth = 1
def create(self, validated_data):
profile_data = validated_data.pop('user_profile')
user = User.objects.create(**validated_data)
UserProfile.objects.create(user=user, **profile_data)
return user
views.py
class UserDetail(generics.RetrieveUpdateDestroyAPIView):
profile = serializers.PrimaryKeyRelatedField(many=False, queryset=UserProfile.objects.all())
queryset = User.objects.all()
serializer_class = UserSerializer
class UserProfileList(generics.ListCreateAPIView):
queryset = UserProfile.objects.all()
serializer_class = UserProfileSerializer
models.py
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='user_profile', on_delete=models.CASCADE)
birthdate = models.DateField(default=datetime.date.today)
job_title = models.ForeignKey(JobTitle, related_name='job_title', on_delete=models.CASCADE)
roles = models.ManyToManyField(Role)
def createProfile(sender, **kwargs):
if kwargs['created']:
user_profile = UserProfile.objects.created(user=kwargs['instance'])
post_save.connect(createProfile, sender=User)
def __str__(self):
return self.user.username
I need that POST method also requires the full JSON, the same as the GET JSON response, in order to complete the create method. Need this for POST method:
{
"id": 1,
"user_profile": {
"job_title": {
"id": 1,
"name": "Desarrollador"
},
"birthdate": "2019-11-06",
"roles": [
{
"id": 1,
"name": "Administrador",
"description": "Administrador del sistema",
"key": "ADMIN"
}
]
},
"password": "pbkdf2_sha256$150000$0XdmQpeiPtVl$rQh2MEYV+IO5Y4gm2o1md2cVzgn/mL95r6m1TvRmG3g=",
"last_login": "2019-11-06T00:34:25-06:00",
"is_superuser": true,
"username": "aruiz",
"first_name": "",
"last_name": "",
"email": "correo#correo.com",
"is_staff": true,
"is_active": true,
"date_joined": "2019-11-05T11:37:49-06:00",
"groups": [],
"user_permissions": []
}

Categories