"The submitted data was not a file. Check the encoding type on the form." validation error, despite uploading correct file (django rest framework) - django

I'm trying to create endpoint for uploading images, in my api, which i'm building with django rest framework.
When I try to test the endpoint with postman, i'm getting response
"image": [
"The submitted data was not a file. Check the encoding type on the form."
]
with status code 400.
When I try to print variable with image to console I get
[<TemporaryUploadedFile: test.jpg (image/jpeg)>]
I've checked out some tutorials and I think i'm sending the file correctly.
That is my post man configuration
that's the view
class ImageView(APIView):
parser_classes = (MultiPartParser, )
permission_classes = (IsAuthenticated, IsRestaurant)
def post(self, request, *args, **kwargs):
data = {
'image': request.data.pop('image'),
'info': request.user.info.pk
}
file_serializer = RestaurantImageSerializer(data=data)
if file_serializer.is_valid():
file_serializer.save()
return Response(status=status.HTTP_201_CREATED)
else:
return Response(file_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
the serializer
class RestaurantImageSerializer(serializers.ModelSerializer):
class Meta:
model = RestaurantImage
fields = '__all__'
and model
class RestaurantImage(models.Model):
info = models.ForeignKey(RestaurantInfo, related_name='images', on_delete=models.CASCADE)
image = models.ImageField()
def __str__(self):
return self.image.name

Your Postman configuration could be an issue, try removing all the wrong or unnecessary headers. I think you need only Authorization in your case. This also could help you out: https://stackoverflow.com/a/41435972/4907382

Related

How to pass data saved from a POST method to the GET method using REST API Django (without a model)?

I have created an API that allows me to upload an image using the POST method in POSTMAN. After submission, I want to display that image name after making a GET request. I am not using any model and I don't intend to grab the image from the directory it is stored in; since I will be uploading images in a server later.
I have looked at multiple sources. A few examples are this, and this.
This is my current code so far but not successful:
views.py:
class API(APIView):
parser_classes = (MultiPartParser,)
def get(self, request, *args, **kwargs):
name = self.request.GET.get('image')
if name:
return Response({"img_name": name}, status=200)
return Response({"img_name" : None}, status = 400)
def post(self, request):
file = self.request.data
img_file = file['image'] #store the image data in this variable
if img_file:
uploaded_file = img_file
img = [{"image_name": uploaded_file}]
serializer = ImgSerializer(img, many = True).data
return Response(serializer, status = 200)
else:
return Response("Please upload", status = 400)
serializers.py:
from rest_framework import serializers
class ImgSerializer(serializers.Serializer):
image_name = serializers.CharField()
My expected result within GET request should be like this:
{'image_name' : 'image_name_from_POST_Request'}
But I am getting this result instead:
None
How can I pass data from the POST request to the GET request using Django's rest framework? Is there an efficient way to deploy this requirement without using a model?
I figured it out. I just created a JSON file in the POST method and stored the necessary data in it. Finally, in order to view the data within the GET method, I opened the file and returned it as a Response.
views.py:
class API(APIView):
parser_classes = (MultiPartParser,)
def get(self, request):
with open('data.txt') as json_file:
data = json.load(json_file)
if data:
return Response(data, status=200)
return Response({"name" : None}, status = 400)
def post(self, request):
posted_file = self.request.data
img_file = posted_file['image']
if img_file:
uploaded_file = img_file
data = [{"image_name": uploaded_file}]
json_data = {"image_name": uploaded_file}
data = {}
data['key'] = []
data['key'].append(json_data)
with open('data.txt', 'w') as outfile:
json.dump(image, outfile)
serializer = ImgSerializer(image, many = True).data
return Response(serializer, status = 200)
else:
return Response(serializer.errors, status = 400)

How to make a POST request to the end point, in views in django for chatterbot?

i am new to django!
I want to make a chatterbot chatbot in my website, for which i need to make a POST request in views. I have created a model. I am using mysql database for this.
I have visited github and other website and finally got a code, but it doesn't have the POST request
this is my models.py:
class Response(models.Model):
statement = models.ForeignKey(
'Statement',
related_name='in_response_to',
on_delete=False
)
response = models.ForeignKey(
'Statement',
related_name='+',
on_delete=False
)
unique_together = (('statement', 'response'),)
occurrence = models.PositiveIntegerField(default=0)
def __str__(self):
s = self.statement.text if len(self.statement.text) <= 20 else self.statement.text[:17] + '...'
s += ' => '
s += self.response.text if len(self.response.text) <= 40 else self.response.text[:37] + '...'
return s
this is where i need to make a POST request in views.py
def post(self, request, *args, **kwargs):
response = Response.objects.all()
if request.is_ajax():
input_data = json.loads(request.read().decode('utf-8'))
else:
input_data = json.loads(request.body.decode('utf-8'))
self.validate(input_data)
response_data = self.chatterbot.get_response(input_data)
return JsonResponse(response, response_data, status=200)
def get(self, request, *args, **kwargs):
data = {
'detail': 'You should make a POST request to this endpoint.',
'name': self.chatterbot.name,
'recent_statements': self._serialize_recent_statements()
}
# Return a method not allowed response
return JsonResponse(data, status=405)
If you're using django rest framework (DRF), i recommend you start by doing QuickStart and then Serialization steps. DRF has a really good documentation and in the Serialization you could find how to make a POST request by defining:
Models
Serializers
Api
Routers

Upload image file using django rest framework in a single page application

I am trying to upload image using Vuejs and Django, but I can't figure out how to solve it.
This is the django side:
class UserDetail(models.Model):
user = models.OneToOneField(User)
profile_picture = models.ImageField(upload_to=create_file_path)
class UserDetailSerializer(serializers.ModelSerializer):
class Meta:
model = UserDetail
fields = '__all__'
class UserDetailViewSet(viewsets.ModelViewSet):
queryset = UserDetail.objects.all()
serializer_class = UserDetailSerializer
permission_classes = [AllowAny]
#detail_route(permission_classes=[AllowAny], methods=['POST'], parser_classes=[FormParser, MultiPartParser])
def create_or_update_profile_picture(self, request):
user = request.user
#
# how to create or update user detail profile picture ?
#
I am posting the data this way from Vuejs:
changeProfilePicture() {
const file_input = document.getElementById('display_profile_image');
const img = file_input.files[0];
let formData = new FormData();
formData.append("profile_picture", img);
const url = this.$store.state.website + '/api/accounts/user-detail/none/create_or_update_profile_picture/';
this.$http.post(url, formData)
.then(function (response) {
this.$store.dispatch('getUserDetail');
})
.catch(function (response) {
console.log(response);
});
}
How can I use the post data to create or update the request.user's profile_picture with Django and django rest framework inside the model viewset class, using default methods (create/update/partial_update) or by creating a new detail route?
Assuming your JS posts the request using 'multipart/form-data' (check this), you should be able to upload the image file when creating or updating the user. Also, make sure you send CSRF Token.
To be able to set the logo on its own, a detailed_route is a good way using a serializer limited to the logo.
In the detailed route, if you want to upload log for logged in user (I saw you put none as an id), you can check that in the detail route before calling get_object which will get the userdetail instance.
class UserLogoSerializer(serializers.ModelSerializer):
class Meta:
model = UserDetail
fields = ['profile_picture']
class UserDetailViewSet(viewsets.ModelViewSet):
queryset = UserDetail.objects.all()
serializer_class = UserDetailSerializer
permission_classes = [AllowAny]
#detail_route(methods=['post'])
def set_profile_picture(self, request, pk=None, format=None):
if pk in ['none', 'self']: # shortcut to update logged in user without looking for the id
try:
userdetail = self.get_queryset().get(user=request.user)
except UserDetail.DoesNotExist:
userdetail = None
else:
userdetail = self.get_object()
serializer = serializers.UserLogoSerializer(userdetail, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
If I recall correctly, permission_classes are the one set on the Viewset by default, and the default parsers should do the job.
here is example in official documentation:
http://www.django-rest-framework.org/api-guide/parsers/#fileuploadparser

Save image from media_root to Django Rest Serializer

I am currently working on a project that allows mobile app user to upload images to a Django Server.
Here is my view that serves the POST request from the user:
class ImageDetailsViewSet(APIView):
def post(self,request, *args, **kwargs):
try:
######### Accept string from the user
imgStr = request.data['image']
media_filename = os.path.join(settings.MEDIA_ROOT, 'img.jpg')
######## Create decoded string to a JPEG file and save it to media_root
img = Image.open(StringIO(imgStr.decode('base64')))
img.save(media_filename, 'JPEG')
###### Update request data to include the newly created image to the request
user = request.user.get_username()
data1 = {'image': media_filename, 'category': 1, 'status': 'Y', 'user': user}
serializer = ImageDetailsSerializer(data=data1)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.data, status=status.HTTP_400_BAD_REQUEST)
except:
raise
return Response(serializer.errors, status=status.HTTP_415_BAD_REQUEST)
My ImageDetailsSerializer:
class ImageDetailsSerializer(serializers.ModelSerializer):
class Meta:
model = ImageDetails
fields= ('image','status','category', 'user')
The code always returns an HTTP 400 error which means that the serializer is not valid.
Here are the solutions I tried to apply but doesn't work in this case:
Change the media_filename from data1 = {'image': media_filename, 'category': 1, 'status': 'Y', 'user': user} to img but it returns TypeError: <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=2976x3968 at 0x841D2F0> is not JSON serializable error
Replace media_filename to media_url/img.jpg, it returns the same error.
Update image field in the serializer by adding (see code below) but it does make any improvements at all:
class ImageDetailsSerializer(serializers.ModelSerializer):
image = serializers.ImageField(use_url=True)
class Meta:
model = ImageDetails
fields= ('image','status','category', 'user')
My questions are:
What should be stored in an ImageField of a serializer? an image, image URL or the directory of which the image is stored?
Is this the correct way/technique to save data from a remote user? Or are there any other effective way to implement this?
It's the path relative to the media_root
You can change data1 to a copy of request.data and merge key "user" into the new dict
The answer to this problem is to use Django-extra-fields plugin. :D
Read https://github.com/Hipo/drf-extra-fields for more details.

Retrieving images from GridFS using django-tastypie-mongoengine

I have a project in Django, and I'm using mongoengine to save images into a Mongo database using GridFSStorage.
All ok so far, but the problem is... when trying to retrieve the images via http request, with a REST API made with django-tastypie-mongoengine, I get back a json object like this:
{"file": "<GridFSProxy: 516ed7cf56ba7d01eb09f522>", "id": "516ed7cf56ba7d01eb09f524", "resource_uri": "/api/v1/pic/516ed7cf56ba7d01eb09f524/"}
Does anybody know how could I get the file from GridFS via http request?
Many thanks!
You'll need to write your own view, but you can make it seem like it's part of the API. First, the view:
def api_image(pk):
obj = get_object_or_404(Model, pk=pk)
image_file = obj.file
return Response(image_file.read(),
mime_type='image/png') # or whatever the MIME type is
Then, you can map it in your urls.py:
url('^/api/v1/pic/(?P<pk>\w+)/file/$', api_image)
And to make sure tastypie shows what you want in the output:
def dehydrate_file(self, bundle):
return '/api/v1/pic/%s/file/' % (bundle.obj.id)
Just make sure the fake API view appears ahead of your actual API definitions, and you should be all set!
Paul's hint was very useful. Here i have implemented this completely in tastypie manner for uploading and downloading images.
Here you go..
1. Overriding deseriazer to support 'multipart'.
class MultipartResource(object):
def deserialize(self, request, data, format=None):
if not format:
format = request.META.get('CONTENT_TYPE', 'application/json')
if format == 'application/x-www-form-urlencoded':
return request.POST
if format.startswith('multipart'):
data = request.POST.copy()
data.update(request.FILES)
return data
return super(MultipartResource, self).deserialize(request, data, format)
2. Model class
class Research(Document):
user = ReferenceField(User)
academic_year = StringField(max_length=20)
subject = StringField(max_length=150)
topic = StringField(max_length=50)
pub_date = DateTimeField()
authored = StringField(max_length=20)
research_level = StringField(max_length=20)
paper_presented = BooleanField()
thesis_written = BooleanField()
proof_image = ImageField()
3. Resource class
class ResearchResource(MultipartResource, MongoEngineResource):
class Meta:
queryset = Research.objects.all()
list_allowed_methods = ['get','post']
resource_name = 'research'
authentication = SessionAuthentication()
authorization = Authorization()
def prepend_urls(self):
return [
url(r"^(?P<resource_name>%s)/$" % self._meta.resource_name,
self.wrap_view('dispatch_list'), name="api_dispatch_list"),
#url to download image file.
url(r"^(?P<resource_name>%s)/(?P<pk>\w+)/file/$"% self._meta.resource_name,
self.wrap_view('get_image'), name="api_get_image"),
]
#Preparing image url dynamically
def dehydrate_proof_image(self, bundle):
return '/api/v1/%s/%s/file/' % (self._meta.resource_name,bundle.obj.id)
#view will call based on image url to download image.
def get_image(self, request, **kwargs):
obj = Research.objects.get(id=kwargs['pk'])
image_file = obj.proof_image
return HttpResponse(image_file.read(), content_type="image/jpeg"))
Hope this will be very useful for everyone in future. :)