django rest framework post nested json - json

I have a table on sqlserver
ext_id is number,
dealer_code is string,
dealer_name is string
and I need to POST this json
{
"ext_id": 1,
"dealer": {
"dealer_code" : "D1"
"dealer_name": "Dealer1",
}
}
models.py
class reqid(models.Model):
ext_id = models.IntegerField(primary_key=True)
dealer_code = models.CharField(max_length=10, db_column="dealer_code")
dealer_name = models.CharField(max_length=30, db_column="dealer_name")
class Meta:
db_table = 'table_test'
def __str__(self):
return self.ext_id
serializer.py
class ReqSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = reqid
fields = ['ext_id', 'dealer_code','dealer_name']
views.py
class testView(viewsets.ModelViewSet):
queryset = reqid.objects.all()
serializer_class = ReqSerializer
def post(self, request, format=None):
reqid = request.data.get("reqid")
dealer_code = request.data['dealer']['dealer_code']
dealer_name = request.data['dealer']['dealer_name']
data = {'reqid': reqid, 'dealer_code': dealer_code, 'dealer_name': dealer_name}
serializer = ReqSerializer(data=data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
when I try post json i get
HTTP 400 Bad Request
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
{
"detail": "JSON parse error - Expecting ',' delimiter: line 5 column 3 (char 60)"
}
if I post simple json like :
{
"ext_id": 1,
"dealer_code": "D1",
"dealer_name": "Dealer1"
}
everything works. What and where should I change to load nested json.
I am a beginner so please be specific :)
UPDATE
Thx #Vishal Singh
Right now I must add more nest "asset"
....
"dealer":{
"dealer_code":"D1",
"dealer_name":"Dealer1",
},
"asset":{
"sector":{
"code":"SEC1",
"name":"Sector1"
}
}
...
how can I save sector name (I added column to database)?
When I add to views.py
sector_name = request.data['asset']['sector']['name']
and in serialize.py
class SectorField(serializers.Field):
def to_representation(self, value):
ret = {
"sector_name": value.sector_name
}
return ret
def to_internal_value(self, data):
ret = {
"sector_name": data["name"],
}
return ret
I get
HTTP 400 Bad Request
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
{
"sector": [
"This field is required."
]
}

Related

How to Solve Django rest-framework JSON parse Error

What is wrong with this JSON?
when trying to send a POST request with POSTMAN getting JSON PARSE ERROR.
Error from Postman
{
"detail": "JSON parse error - Expecting ',' delimiter: line 5 column 13 (char 82)"
}
JSON Data sending From Postman
{
"menu_name": "indian_menu",
"slug": "indianmenu",
"item_name": [
"category": "indianmenu",
]
}
rest_framework Serializers
class MenuCardSerializer(serializers.ModelSerializer):
class Meta:
model = MenuCard
fields = '__all__'
read_only_fields = ('menu_name', )
class MenuSerializer(serializers.ModelSerializer):
category = MenuCardSerializer(required=True, many=True)
class Meta:
model = Menu
fields = '__all__'
def create(self, validated_data):
category = validated_data.pop('category')
menu = MenuCard.objects.create(**validated_data)
for choice in category:
Menu.objects.create(**choice, category=menu)
rest_framework API_VIEWS
#api_view(['GET', 'POST', 'PUT', 'DELETE', ])
def simple_menu(request, slug):
print("simple menu slug : " + slug)
if request.method == 'GET':
category_list = Menu.objects.all()
serializer = MenuSerializer(category_list)
return JsonResponse(serializer.data)
elif request.method == 'POST':
serializer = MenuSerializer(data=request.data, many=False)
data = {}
if serializer.is_valid():
serializer.save()
data["success"] = "item Catagory Created"
return JsonResponse(data=data, status=status.HTTP_200_OK)
return JsonResponse(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
You JSON from postman is not a valid one, you can easily check it with any JSON validator.
In your first example it should be a dict not list as oz19 mentioned.
The same problem in the second one, the correct one is something like this:
{
"menu_name":"Indian Menu",
"slug":"indianmenu",
"item_name":[
{
"category":"Indian Menu",
"item_name":"dal",
"price":"22.30",
"stock":"10"
}
]
}
The error possibly comes from the data you are entering on Postman. On item_name you probably wanted to create a dict, but it is a list.
Change:
{
...
"item_name": [ "category": "indian_menu"]
}
By:
{
...
"item_name": { "category": "indian_menu" }
}

django REST framework, validate json data

The server comes with json format:
{
"type": "string",
"object": {
"lead_id": int,
"form_name": "string",
"answers": [
{
"lead_id": int,
"key": "string",
}
...
]
},
"group_id": int,
"secret": "string"
}
How to use django REST framework to validate this json?
ru version
class AnswersSerializer(serializers.Serializer):
lead_id = serializers.IntegerField(required=True)
key = serializers.CharField(max_length=100)
class ObjectSerializer(serializers.Serializer):
lead_id = serializers.IntegerField(required=True)
form_name = serializers.CharField(max_length=100)
answers = serializers.ListField(child=AnswersSerializer())
class UpdateGroup(serializers.Serializer):
group_id = serializers.IntegerField(required=True)
type = serializers.CharField(max_length=100)
secret = serializers.CharField(max_length=100)
object = serializers.DictField(child=, default={})
Example:
# serializers.py
from rest_framework import serializers
class VkObjectSerializer(serializers.Serializer):
"""
is 'object'
"""
lead_id = serializers.IntegerField()
group_id = serializers.IntegerField()
user_id = serializers.IntegerField()
form_id = serializers.IntegerField()
class VkBaseSerializer(serializers.Serializer):
"""
Base serializer
"""
type = serializers.CharField(max_length=200)
object = VkObjectSerializer()
group_id = serializers.IntegerField()
secret = serializers.CharField(max_length=200)
# view.py
from rest_framework.generics import CreateAPIView
from rest_framework.response import Response
from .serializers import VkBaseSerializer
class VkCallbackView(CreateAPIView):
serializer_class = VkBaseSerializer
def create(self, request, *args, **kwargs):
"""
Method is validate json in view
"""
valid_ser = self.serializer_class(data=request.data)
if valid_ser.is_valid():
return Response('True')
return Response('False')
Valid data:
>>> valid_ser.data
{
"type": "str",
"object": {
"lead_id": 123,
"group_id": 12345,
"user_id": 12352,
"form_id": 1
},
"group_id": 5123,
"secret": "str"
}
The answers were very helpful:
Django Rest Framework ListField and DictField - how to set model json
How to validate a json object in django - validate data in view
You can use django rest framework to write you own validators like so,
class MultipleOf(object):
def __init__(self, base):
self.base = base
def __call__(self, value):
if value % self.base != 0:
message = 'This field must be a multiple of %d.' % self.base
raise serializers.ValidationError(message)
You can find more details here
Hope this helps!

How to create object with Foreign Key

Fisrt,here is my models:
class Question(models.Model):
description = models.CharField(max_length=200)
analysis = models.CharField(max_length=50)
def __str__(self):
return self.description
class QuestionOption(models.Model):
question = models.ForeignKey(Question,related_name='options')
content = models.CharField(max_length=100)
isAnswer = models.BooleanField()
def __str__(self):
return self.question.description + " " + self.content
My Serializers:
class QuestionSerializer(ModelSerializer):
class Meta:
model = Question
fields = '__all__'
The Serializer of QuestionOption is as same
My ViewSet:
class QuestionViewSet(ModelViewSet):
queryset = Question.objects.all()
serializer_class = QuestionRetriveSerilzer
I want to post a Json data,like this:
{
"options": [
{
"content": "This is the first option",
"isAnswer": false
},
{
"content": "This is the second option",
"isAnswer": true
}
],
"description": "which one is true?",
"analysis": "It's esay"
}
I hope my QuestionViewSet can create a Question and two QuestionOption for me automatically,and when I post that Json data,the options is null list,so I override the create method of QuestionViewSet,like this:
def create(self, request, *args, **kwargs):
serializer = QuestionSerializer(data=request.data)
question = serializer.save()
for data in request.data['options']:
data['question'] = question.id
optionSeializer = OptionSerializer(data=data)
print optionSeializer.is_valid()
optionSeializer.save()
return Response(serializer.data,status=status.HTTP_200_OK)
And this method can work,but I want to find a simpler way to do it,cause I must override update and other methods,it's not a easy task...
So how to design Serializers and ViewSet in order to automatically create objects and update objects with foreign key ?
drf-writable-nested may help .

Which file format django imagefield(filefield) requires?

I use django-rest-framework first time. I use json format by default.
I need to send file for creating a new instance. This file has being saved in models.ImageField. However, I don't know which format this field requires for incoming file. I tried to send it in base64, but it isn't suitable.
TestCase for this problem:
class PersonTestCase(APITestCase):
def setUp(self):
self.c = APIClient()
def test_sign_up_with_valid_data(self):
with open('persons/test/bg.jpg', 'rb') as bg:
valid_registration_data = {
...,
'background': base64.b64encode(bg.read()).decode('utf-8'),
}
response = self.c.post('/persons/sign_up', valid_registration_data)
self.assertEqual(response.status_code, 201)
self.assertEqual(Person.objects.count(), 1)
self.assertEqual(Person.objects.get('username'), 'test_client74562984')
View:
class SignUpView(APIView):
"""
Create new user
"""
def post(self, request):
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
response = Response(serializer.data, status=status.HTTP_201_CREATED)
return response
response = Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
return response

Return only funded fields in response(Django Rest SearchFilter)

I have ViewSet which have SearchFilter in filter_backends and two search_fields. How to return JSON represents the only field results?
For example if i send response for search with "jo" substring i will have only one field for this search(funded user name or full name), not both user name and email in each JSON object:
{
[{
"username": "jonh";
},
{
"fullname": "Jonh";
},
{
"username": "jo";
},
{
"fullname": "Johnson";
}
]
}
viewsets.py:
class UserViewSet(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.ListModelMixin,
viewsets.GenericViewSet):
queryset = User.objects.all()
permission_classes = (IsUserOrReadOnly,)
filter_backends = (filters.SearchFilter,)
search_fields = ('^username', '^fullname',)
def get_serializer_class(self):
if hasattr(self, 'action') and self.action == 'list':
return UserListSerializer
return UserDetailSerializer
serializers.py:
class UserListSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'email', 'fullname')
I would create a Serializer factory function that takes the search params as an an argument:
def generate_user_list_serializer(search_terms):
class UserListSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = tuple(search_terms)
return UserListSerializer
Then in your view, have the serializer generated on the fly:
def get_serializer_class(self):
# make sure that the fields are available
validated_params = [p for p in self.query_params if p in Myfields]
return generate_user_list_serializer(self.query_params)