Cant get Information out of request data (Django/Postman) - django

Im trying to build an api with Django. I think i build it correctly but from, for example Post-request data, i get as the field values "none"
Maybe you can help me to solve this problem :)
Heres the api:
def apiRequests(request):
if request.method == "POST":
print(request.POST.get("name"))
print(request.POST.get("publisher"))
print(request.POST.get("price"))
#Game.objects.create(name= request.POST.get('name'),publisher = request.POST.get("publisher"),price = request.POST.get("price"))
elif request.method == "GET":
response = Game.objects.filter(name = request.GET.get("name"))
return render(request,"apirequests.html")
As you may see i'm printing out the data i receive. This looks like this:
None
None
None
[26/Aug/2022 08:40:09] "POST /api/ HTTP/1.1" 200 263
Here's the model class:
class Game(models.Model):
name = models.CharField(max_length=200)
publisher = models.CharField(max_length=200)
price = models.BigIntegerField()
def __str__(self):
return str(self.id) + " " + self.name
And here is the data I'm sending as a Post-request from Postman to the api:
{
"name": "FarCry",
"publisher": "EA",
"price": "35.66"
}
I think i should say that i got Problems with the CsrfViewMiddleware-Token so i commented it out in the settings.py, maybe there is the problem.
Thanks for helping

If you are using Postman, send the body as form-data.

Related

How can I customize drf-yasg endpoints's example response?

on my Django project, I'm using DRF and drf-yasg. At some endpoint, the example response body shows the incorrect example. like the following example:
But some of them don't show the correct example response body.
This endpoint actually returns access_token and refresh_token, doesn't return the email and password. It's wrong information for the front-end devs. Is there any way to change this?
Below is an example using #swagger_auto_schema annotation with 3 serializers. 1 request serializer and 2 response serializers (success and error serializers).
class RequestSerializer(serializers.Serializer):
param = serializers.CharField()
class SucessSerializer(serializers.Serializer):
success = serializers.BooleanField()
message = serializers.CharField()
class ErrorSerializer(serializers.Serializer):
success = serializers.BooleanField()
errors = serializers.IntegerField()
class ExampleViewView(APIView):
#swagger_auto_schema(
request_body = RequestSerializer,
responses={
'200': SucessSerializer,
'500': ErrorSerializer,
},
operation_description = 'Doc description'
)
def post(self, request):
return successResponse({
'sucess': True
})

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

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

Django REST testing - how to specify pk argument referring to the model instance created in setUp function

I have a model "Article" and I want to test if authorized user can GET an individual article.
The testing class is:
class TestPost(APITestCase):
def setUp(self):
self.factory = APIRequestFactory()
self.user = User.objects.create_user(
username='Name', email='test#company.com', password='secret')
self.article = Article.objects.create(
author = 'Author', title = 'Article title', body = 'Body content ...')
def test_detail_user(self):
request = self.factory.get(reverse('article_id', kwargs={'pk': 1}))
request.user = self.user
response = ArticleDetail.as_view()(request, pk=1)
self.assertEqual(response.status_code, 200,
f'Expected Response Code 200 - OK, received {response.status_code} instead.')
The URL pattern is:
path('<int:pk>/', ArticleDetail.as_view(), name = 'article_id'),
And when running tests I get the following error:
f'Expected Response Code 200 - OK, received {response.status_code} instead.')
AssertionError: 404 != 200 : Expected Response Code 200 - OK, received 404 instead.
I suppose the problem is in the specified 'pk', but I cannot figure out how to specify pk without stating an exact figure of 1. How can I refer to the article created in setUp function instead?
I may be misunderstanding, but you should be able to reference it by simply doing something like:
def test_detail_user(self):
article_id = self.article.pk
...
# the rest of your code here using article_id as the id of
# the article you are retrieving

Field is required on POST requets with GeoFeatureModelSerializer and ListCreateAPIView

it was hard to find a good title for this thread.
I'm developping webservices with django, geodjango (postgis), django-rest-framework and rest_framework_gis. Those webservices will be used in interactive maps.
One of my model is the following:
class Polygon(models.Model):
fk_owner = models.ForeignKey(User, on_delete=models.DO_NOTHING) # the owner of this polygon (User)
external_id = models.CharField(max_length=25) # id in data warehouse
func_type = models.CharField(max_length=15) # e.g 'field', 'building', ...
coordinates = models.PolygonField()
properties = JSONField(default={}) # JSON containing attributes and actions
The serializer of this model:
class PolygonSerializer(GeoFeatureModelSerializer):
class Meta:
model = Polygon
geo_field = "coordinates"
fields = ('external_id', 'fk_owner', 'func_type', 'properties')
And the endpoint
class FieldList(generics.ListCreateAPIView):
serializer_class = PolygonSerializer
lookup_field = 'external_id'
lookup_url_kwarg = 'external_id_field'
def get_queryset(self):
id_user = User.objects.get(external_id=self.kwargs['external_id_user']).id
queryset = Polygon.objects.filter(func_type="field").filter(fk_owner=id_user).all()
return queryset
def perform_create(self, serializer):
user = User.objects.get(external_id=self.kwargs['external_id_user'])
serializer.save(fk_owner=user)
When I use the following curl request:
curl -X POST http://xxx.yyy.zzz/api/v2/users/aZ523AsZm/fields/ -d '{"external_id": "aE15feg64AzaP", "func_type": "field", "coordinates": "POLYGON((62780.8532226825 5415035.177460473, 62941.3759284064 5415283.89540161, 63187.058044587146 5415364.391565912, 63257.96856022246 5414992.852982632, 62780.8532226825 5415035.177460473, 62780.8532226825 5415035.177460473))", "properties": {"a": "b"}}' -H "Content-Type: application/json"
I get {"fk_owner":["This field is required."],"external_id":["This field is required."],"coordinates":["This field is required."],"func_type":["This field is required."]}
However, when I replace GeoFeatureModelSerializer by a simple ModelSerializer, eveything is fine. Why ?
It took me like 1 hour to find the guilty, and it's soon the end of the daywork for me. Any help would be appreciate ! Thanks, and sorry for the long post.
[EDIT 10/11]: My workaround is to use 2 serializers: one for GET and one for CREATE
class PolygonList(generics.ListCreateAPIView):
queryset = Point.objects.all()
filter_backends = (drfg_filters.InBBoxFilter,)
def get_serializer_class(self):
if self.request.method == 'POST':
self.serializer_class = PolygonSerializerCreate
if self.request.method == 'GET':
self.serializer_class = PolygonSerializerRetrieve
return self.serializer_class
The django-rest-framework-gis repo contains a few examples of a POST request to create new objects, for example take a look at this one:
unit test code
view code
serializer code
model code
As you can see, POSTing should work, if it doesn't, it's either a bug or the code you are using is wrong.
From the what you posted in your question it looks like the JSON format you are using is not right. You told me you tried to send GeoJSON in the POST request, but I ask you to take a careful look at the links I just posted and try again. If you think it's a bug, we should test it and fix it.
Federico

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. :)