Django rest framework bulk post object - django

I want insert bulk json via django rest_framework however, I get a error message ;
typed following line ;
{
"non_field_errors": [
"Invalid data. Expected a dictionary, but got list."
]
}
my serializer.py file include following code block;
class DrfSerializerV2(serializers.ModelSerializer):
def __init__(self,*args,**kwargs):
many=kwargs.pop('many',True)
super(DrfSerializerV2,self).__init__(many=True,*args,**kwargs)
class Meta:
model = DrfData
fields=['id','name','duration','rating','typ']
and my views.py file ;
class ActionViewSet(viewsets.ModelViewSet):
queryset = DrfData.objects.filter(typ="action")
serializer_class = serializers.DrfSerializerV2
finally send json file via post;
[
{"name":"m1","duration":120,"rating":4.7},
{"name":"m2","duration":120,"rating":4.5}
]
however, I can't handle this error message.
if I send sperataly, there is no problem.
but, I can't resolve this error for bulk insert

Related

DRF upload extracted zip files

I'm going to upload some files through my DRF API. This API receives a .zip file that has some .xlsx files in. I extract its content in the API view. Then I send this data to the serializer, But I get this error:
[
{
"file_name": [
"The submitted data was not a file. Check the encoding type on the form."
]
}
]
This is how I'm extracting my .zip file before passing data to the serializer:
def _get_serializer_initial_data(self):
with ZipFile(self.request.FILES.get('file_name')) as input_zip:
return [
{
'file_name': input_zip.open(_input_excel)
}
for _input_excel in input_zip.infolist()
]
Then I send data to the serializer this way:
initial_data = self._get_serializer_initial_data()
serializer = self.get_serializer(data=initial_data, many=True)
I checked the extracted files type in the serializer class and it's ZipExtFile, which seems to be unacceptable by DRF.
Any help would be appreciated.

Input for field is missing even after i type the correct format on the API

I have coded the following:
models.py
class Job(models.Model):
datetime = models.DateTimeField(default=timezone.now)
combinedparameters = models.CharField(max_length = 1000)
serializers.py
class JobSerializers(serializers.ModelSerializer):
class Meta:
model = Job
fields = ['combinedparameters']
views.py
#api_view(['POST'])
def create_job(request):
job = Job()
jobserializer = JobSerializers(job, data = request.data)
if jobserializer.is_valid():
jobserializer.save()
return Response(jobserializer.data, status=status.HTTP_201_CREATED)
return Response(jobserializer.errors, status=status.HTTP_400_BAD_REQUEST)
Page looks like this:
But if i copy
{'device': 177, 'configuration': {'port_range': 'TenGigabitEthernet1/0/1,TenGigabitEthernet1/0/2,TenGigabitEthernet1/0/3,TenGigabitEthernet1/0/4,TenGigabitEthernet1/0/5', 'port_mode': 'Access', 'port_status': 'Disabled', 'port_param1': 'Test\\n1\\n2\\n3', 'port_param2': 'Test\\n1\\n2\\n3'}}
And click post, got error saying the single quotes have to be double quotes. So i changed it to :
{"device": 177, "configuration": {"port_range": "TenGigabitEthernet1/0/1,TenGigabitEthernet1/0/5", "port_mode": "Access", "port_status": "Disabled", "port_param1": "1\\n2\\n3", "port_param2": "1\\n2\\n3"}}
I clicked post again and this time the following error comes out:
I dont understand why is it happening. The reason why I key in the long format because this is the format i want to save in my database and this format is created upon saving from my html that creates the job
Postman:
Updated Postman:
Your post data object does not contain the required key "combinedparameters". I'm guessing that big object you copy into content is the string you want saved into the CharField combinedparameters? If that's the case you should structure your post data like this:
{
"combinedparameters": "{'device': 177, 'configuration': {'port_range': 'TenGigabitEthernet1/0/1,TenGigabitEthernet1/0/2,TenGigabitEthernet1/0/3,TenGigabitEthernet1/0/4,TenGigabitEthernet1/0/5', 'port_mode': 'Access', 'port_status': 'Disabled', 'port_param1': 'Test\\n1\\n2\\n3', 'port_param2': 'Test\\n1\\n2\\n3'}}"
}

How to change serializer field name when validation error is triggered

I need to change the view of the error displayed when I validate the field.
serializer.py
class ElementCommonInfoSerializer(serializers.ModelSerializer):
self_description = serializers.CharField(required=False, allow_null=True,
validators=[RegexValidator(regex=r'^[a-zA-Z0-9,.!? -/*()]*$',
message='The system detected that the data is not in English. '
'Please correct the error and try again.')]
)
....
class Meta:
model = Elements
fields = ('self_description',......)
This error is displayed
{
"self_description": [
"The system detected that the data is not in English. Please correct the error and try again."
]
}
The key of error dict is field name - self_description. For FE I need to send another format like:
{
"general_errors": [
"The system detected that the data is not in English. Please correct the error and try again."
]
}
How to change this?
One way this could be achieved is via custom exception handler
from copy import deepcopy
from rest_framework.views import exception_handler
def genelalizing_exception_handler(exc, context):
# Call REST framework's default exception handler first,
# to get the standard error response.
response = exception_handler(exc, context)
# Now add the HTTP status code to the response.
if 'self_description' in response.data:
data = deepcopy(response.data)
general_errors = data.pop('self_description')
data['general_errors'] = general_errors
response.data = data
return response
in settings
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'my_project.my_app.utils. genelalizing_exception_handler'
}
Another solution is to rewrite the validate method.
def validate(self, data):
self_description = str((data['self_description']))
analyst_notes = str((data['analyst_notes']))
if re.match(r'^[a-zA-Z0-9,.!? -/*()]*$', self_description) or re.match(r'^[a-zA-Z0-9,.!? -/*()]*$', analyst_notes):
raise serializers.ValidationError({
"general_errors": [
"The system detected that the data is not in English. Please correct the error and try again."
]
})
return data
The solution is very simple.
you can rename the key field by using serializer method (source attribute)
below you can find an example code.
class QuestionSerializer(serializers.ModelSerializer):
question_importance = serializers.IntegerField(source='importance')
question_importance = serializers.IntegerField(required=False)
class Meta:
model = create_question
fields = ('id','question_importance','complexity','active')
Above you can see I have an importance field which is present in django model But here I renamed this field to question_importance by using source attribute .
In your case it will be like below,
class ElementCommonInfoSerializer(serializers.ModelSerializer):
general_errors = serializer.CharField(source="self_description")
general_error = serializers.CharField(required=False, allow_null=True,
validators=[])
class Meta:
model = Elements
fields = ('general_error',......)

How to return customized JSON response for an error in django-graphene?

I am learning to use django-graphene for graphql purpose.
For mutation, all I know is it would return error message of its own.
Let's say if I have a token field, and checked if token field is bad, I only know how to return None which would give the front end a query result of null instead of a customized json response for status and error
I have these codes
class ProductType(DjangoObjectType):
class Meta:
model = Product
filter_fields = {'description': ['icontains']}
interfaces = (graphene.relay.Node,)
class ProductInput(graphene.InputObjectType):
token = graphene.String()
title = graphene.String()
barcode = graphene.String(required=True)
class CreateProduct(graphene.Mutation):
class Arguments:
product_input = ProductInput()
product = graphene.Field(ProductType)
def mutate(self, info, product_input=None):
if not product_input.get('token'):
return None # instead of return None, I would like to return error code, status with message
product = Product.objects.create(barcode=product_input.barcode, title=product_input.title)
return CreateProduct(product=product)
class ProductMutation(graphene.ObjectType):
create_product = CreateProduct.Field()
Thanks in advance
Instead of return None you can throw an exception. The exception will be handled by graphene and passed on as an error.
For example, raise Exception('Error 123456') will result in a response something like
{
"errors": [
{
"message": "Error 123456'",
"locations": [
{
"line": 1,
"column": 3
}
]
}
],
"data": {
"product": null
}
}
The presence of errors in the output JSON can trigger the frontend error handling.
Please note that in general, any exceptions passed to graphql will be visible to the outside world, so it's worth considering the security ramifications of all of your graphene queries and mutation exceptions.

django api post without bring json still work?

Because django rest framework did not support bulk create
So I write one
And I found a strange problem
if I POST the api with a json like :
[{'address':'1','name':'2','start':'3'},
{'address':'10','name':'20','start':'30'}]
it works!
But if I kust POST the api without bring json
I still got bulk create success message.
Why would this happen??
Where do I write wrong??
This is my API view
class BulkTestList(APIView):
def post(self, request, format=None):
duplicateList = []
for data in request.data:
message = {}
if not 'address' in data.keys():
message['address'] = [ "This field is required."]
elif not data['address']:
message["address"] = [ "This field may not be blank."]
if not 'name' in data.keys():
message["name"] = [ "This field is required."]
elif not data['name']:
message["name"]= [ "This field may not be blank."]
if not 'star' in data.keys():
message["star"] = [ "This field is required."]
elif not data['star']:
message["star"]= [ "This field may not be blank."]
if message:
return Response(message, status=status.HTTP_400_BAD_REQUEST)
for data in request.data:
address = data['address'].upper()
bulkCreateObjects = Data(address=address, name=data['name'], star=data['star'], datetime=datetime.datetime.now(pytz.utc))
bulkCreateObjects.save()
message = {"bulk create success"}
return Response(data=message, status=status.HTTP_201_CREATED)
Django REST framework doesn't have bulk out of the box but you have a third party app that does.
Your current view just doesn't call a serializer therefore you won't get the validation at any point. See http://www.django-rest-framework.org/tutorial/3-class-based-views/#rewriting-our-api-using-class-based-views
Note that for bulk you'll add a many=True to the serializer so it will be able to deal with list of data.
Your issue that the view returns a 201 "{bulk create success}" is due to the fact that you iteration over request.data does not check if reuqest.data is actually empty. A for loop over an empty list will just skip over the for block. As Linovia mentions, you need to add some validation to your view.