I have an issue with my post request. This is my code:
def add_review(request, dealer_id):
if request.method == "GET":
context = {
"cars": CarModel.objects.all().filter(dealerId = dealer_id),
"dealerId": dealer_id
}
return render(request, 'djangoapp/add_review.html', context)
if request.method == "POST":
if request.user.is_authenticated:
form = request.POST
review = {
"dealership": int(dealer_id),
"name": request.user.username,
"review": form["review"],
"purchase": form.get("purchasecheck") == 'on',
}
if form.get("purchasecheck"):
review["purchase_date"] = datetime.strptime(form.get("purchasedate"), "%m/%d/%Y").isoformat()
car = CarModel.objects.get(pk=form["car"])
review["car_make"] = car.make.name
review["car_model"] = car.name
review["car_year"]= int(car.year.strftime("%Y"))
json_payload = {"review": review}
url = "https://4fbfebf7.us-south.apigw.appdomain.cloud/api/review"
post_request(url=url, json_payload=json_payload, dealer_id=dealer_id)
return redirect("djangoapp:dealer_details", dealer_id=dealer_id)
else:
return redirect("/djangoapp/login")
And this:
def post_request(url, json_payload, **kwargs):
json_data = json.dumps(json_payload, indent=4)
print(f"{json_data}")
try:
# Call get method of requests library with URL and parameters
response = requests.post(url, params=kwargs, json=json_data)
except Exception as e:
# If any error occurs
print("Network exception occurred")
print(f"Exception: {e}")
print(f"With status {response.status_code}")
print(f"Response: {response.text}")
I am receiving Response is not valid 'application/json' error as you can see here.
Meanwhile, when I copy the exact same JSON to IBM Cloud to test my APIs, all is working fine and the record is created as you can see here.
I guess it's a very silly mistake, but where?
When you pass json to request.post it should be a serializable object (not already serialized)
def post_request(url, json_payload, **kwargs):
# json_data = json.dumps(json_payload, indent=4). << delete
print(f"{json_payload}")
try:
# Call get method of requests library with URL and parameters
response = requests.post(url, params=kwargs, json=json_payload)
except Exception as e:
# If any error occurs
print("Network exception occurred")
print(f"Exception: {e}")
print(f"With status {response.status_code}")
print(f"Response: {response.text}")
Related
I use pytest-django to do unit test on my django project. The view is
def news(request):
"""
Interface for newslist
"""
page = 1
if request.method == 'POST':
content = request.body
try:
content = json.loads(content)
except ValueError as error:
return err_response("Value Error of post: {}".format(error))
if 'page' in content:
page = content['page']
articlelist = Article.objects.all().order_by('-time')
paginator = Paginator(articlelist, 10)
try:
current_list = paginator.page(page)
except InvalidPage as error:
return err_response(error)
# coping with the paginator
...
newsnum = len(Article.objects.all())
return JsonResponse({
'newsnum': newsnum,
'pagelist': list(pagelist),
'data': [{
'title': newsitem.title,
'source': newsitem.source,
'time': newsitem.time.strftime("%Y-%m-%d %H:%M:%S"),
'content': newsitem.content,
'href': newsitem.href,
'image': newsitem.image,
} for newsitem in current_list]
}, status=200)
When I use pytest-django to test it
#pytest.mark.django_db
def test_view_news(client):
"""
Test view news
"""
url = reverse("news")
data = {
'page': 1
}
response = client.post(url, data=data)
assert response.status_code == 200
It gives Bad Request and code 400. But when I use client.get(), the response is normal (code 200).In the settings, I already set
DEBUG = True
ALLOWED_HOSTS = ['*']
Can anyone tells me what happened?
Override the default server_name used by client
Just override the default server name used by client to match one of those you have in allowed hosts e.g
ALLOWED_HOSTS = ['localhost',...]
...
.....
response = client.post(url, data, SERVER_NAME='localhost')
I am trying to write unit test cases for flask APIs. I am unable to figure out how to write test cases for 500 internal server errors and custom exceptions in API response.
Here are my books api to get the book by id
#BOOKS_BP.route('/<book_id>', methods=['GET'])
def get_book(book_id):
try:
book = Book.query.filter(Book.id == book_id).scalar()
if not book:
raise DBRecordNotFound('No Record Found with ID - {}'.format(book_id))
book_schema = BookSchema()
return jsonify({'status': 'success', 'book': book_schema.dump(book)}), HTTPStatus.OK
except DBRecordNotFound as ex:
return jsonify({'status': 'error', 'message': str(ex)}), HTTPStatus.NOT_FOUND
except Exception as ex:
logger.error(ex, exc_info=True)
return jsonify({'status': 'error', 'message': str(ex)}), HTTPStatus.INTERNAL_SERVER_ERROR
Here is my get book by id test case.
import json
from tests.test_base import BaseTestCase
from tests.factories import BookFactory
from http import HTTPStatus
class BooksTestCase(BaseTestCase):
#classmethod
def setUpClass(cls):
super(BooksTestCase, cls).setUpClass()
book = BookFactory(name='Test Book')
book.save()
cls.test_book_id = book.id
def test_book_by_id(self):
# For 200 Status
response = self.client.get('/api/books/{}'.format(self.test_book_id))
data = json.loads(response.data)
assert response.status_code == HTTPStatus.OK
assert data['book']['name'] == 'Test Book'
# For 404 Status
response = self.client.get('/api/books/123456')
data = json.loads(response.data)
assert response.status_code == HTTPStatus.NOT_FOUND
assert data['message'] == 'No Record Found with ID - 123456'
# For 500 Status
Background:
I have integration test which is working fine, but later on failed when I
added the customized middleware
def test_mobile_update_customer(self):
user = User.objects.create(username='warhead')
self.client.force_authenticate(user=user)
mommy.make(Customer, family_name='IBM', created_user=self.soken_staff, updated_user=self.soken_staff)
data = {
"family_name": "C0D1UM"
}
customer = Customer.objects.first()
res = self.client.patch(reverse('api:customer-detail', kwargs={'pk': customer.id}), data=data)
self.assertEqual(200, res.status_code)
customer.refresh_from_db()
self.assertEqual('C0D1UM', customer.family_name)
self.assertEqual('spearhead', customer.created_user.username)
self.assertEqual('warhead', customer.updated_user.username)
Problem:
The middleware break it with Exception
File "/Users/el/Code/norak-cutter/soken/soken-web/soken_web/middleware.py", line 47, in process_request
data['PATCH'] = json.loads(request.body)
File "/Users/el/.pyenv/versions/soken/lib/python3.6/site-packages/django/http/request.py", line 264, in body
raise RawPostDataException("You cannot access body after reading from request's data stream")
django.http.request.RawPostDataException: You cannot access body after reading from request's data stream
The problem is data has been read before the RESTful api do the job.
Then the program raises an exception.
def process_request(self, request):
if request.path.startswith('/api/'):
data = collections.OrderedDict()
data["user"] = request.user.username
data["path"] = request.path
data["method"] = request.method
data["content-type"] = request.content_type
if request.method == 'GET':
data['GET'] = request.GET
elif request.method == 'POST':
data['POST'] = request.POST
# https://stackoverflow.com/questions/4994789/django-where-are-the-params-stored-on-a-put-delete-request
# elif request.method == 'PUT':
# data['PUT'] = json.loads(request.body)
# test_mobile_update_customer
# raise RawPostDataException("You cannot access body after reading from request's data stream")
# django.http.request.RawPostDataException: You cannot access body after reading from request's data stream
# elif request.method == 'PATCH':
# data['PATCH'] = json.loads(request.body)
elif request.method == 'DELETE':
pass
self.__uuid = str(uuid.uuid4())
request_logger.info(f'{self.__uuid} {json.dumps(data)}')
Update2
Attempt:
I change client constructor refer to https://github.com/encode/django-rest-framework/issues/2774
def test_mobile_update_customer(self):
user = User.objects.create(username='warhead')
# self.client.force_authenticate(user=user)
from django.test import Client
client = Client()
client.force_login(user)
mommy.make(Customer, family_name='IBM', created_user=self.soken_staff, updated_user=self.soken_staff)
data = {
"family_name": "C0D1UM"
}
customer = Customer.objects.first()
res = client.patch(reverse('api:customer-detail', kwargs={'pk': customer.id}), data=data, content_type='application/json')
self.assertEqual(200, res.status_code)
customer.refresh_from_db()
self.assertEqual('C0D1UM', customer.family_name)
self.assertEqual('spearhead', customer.created_user.username)
self.assertEqual('warhead', customer.updated_user.username)
It does not work. The Client misinterpret the payload
>>> res.content
b'{"detail":"JSON parse error - Expecting property name enclosed in double quotes: line 1 column 2 (char 1)"}'
Workaround:
I don't know this is correct for all cases or not, but I workaround by this
test.py
https://gist.github.com/elcolie/88eb7c90cfca1c369a020ac232c7fbcc
middleware.py
https://gist.github.com/elcolie/5d9b1a2f890a0efcb46fdb95c0e90908
result.py
https://gist.github.com/elcolie/298e595b404c1a5839ed8dd584d2f07f
Question:
How do I do integration test of PATCH with the same time that testcase will not break by my middleware?
Right now I have to choose either one of them.
I need to send POST request from one Django app to another under the same project. The request arrives, but without POST data.
Why is that? And how to send POST data properly?
Sender part, app 1 view:
def get_project_data(request):
if request.method == "POST":
if request.is_ajax():
response = etl_post('get_data', [request.user.project.id], request.POST)
def etl_post(path, identifiers=None, post_data=None):
def date_handler(obj):
if hasattr(obj, 'isoformat'):
return obj.isoformat()
else:
raise TypeError
json_data = json.dumps(post_data, default=date_handler) if post_data else None
return _request(path, identifiers, json_data)
def _request(path, identifiers=None, post_data=None, method=None):
data = None
try:
url = urlparse.urljoin(settings.ETL_WEB_API_URL, path)
if identifiers is not None:
for o in identifiers:
url += "/" + str(o)
if post_data:
url += "/"
request = urllib2.Request(url, data=post_data)
request.add_header("Content-Type", "application/json")
request.add_header("X-ETL-Authorization", settings.ETL_WEB_API_KEY)
if method:
request.get_method = lambda: method
result = urllib2.urlopen(request)
data_str = result.read()
if result.getcode() == 200:
data = json.loads(data_str)
else:
logger.error("Unexpected response %s" % result)
except Exception as e:
logger.exception(e.message)
return data
Also, I tried result = urllib2.urlopen(request, data=post_data), no success.
post_data example:
{"project_id": "nYhRTAmGkkHSlLr8BfPR", "project_name": "rocket-launch", "salt": "805b2892c16369275eerec4dd401f5f", ...}
(Pdb) type(post_data)
<type 'str'>
Receiver part, app 2 view:
#csrf_exempt
def get_project_data(request, trust_id):
if request.method == 'POST':
pdb.set_trace()
The arrived message:
(Pdb) request
<WSGIRequest: POST '/pipeline/get_project_data/2/'>
(Pdb) request.POST
<QueryDict: {}>
You're sending JSON, not form-encoded data. That is found in request.body, not request.POST.
I must say though, if these two apps are in the same project there are much easier ways of sending data between them than by making HTTP requests.
I have this strange problem with my view which is returning response in json format.My view looks like this:
def CheckPlayer(request,client_id):
if request.method == 'GET':
try:
user = User.objects.get(id = client_id)
except:
return Error(message = "User doesnot exists.")
message = request.GET.get('message','')
if not message:
return Error(message = "Argument Missing.")
response = {}
result = MakingRequest(message)
result = json.loads(result)
if result['failure'] == '0':
response['failure'] = '0'
else:
response['failure'] = '1'
return HttpResponse(json.dumps(response), mimetype="application/javascript")
else:
return Error()
def MakingRequest(message):
values = {'message':message}
rObjects = Ram.objects.all()
temp = []
for i in rObjects:
temp.append(i.appId)
values['registration_ids'] = temp
param = json.dumps(values)
req = urllib2.Request("https://android.googleapis.com/gcm/send", param)
req.add_header( 'Content-Type' , 'application/json' )
req.add_header( 'Authorization' , 'key=7FcEMnl0FRTSBjhfjfhjfHi1Rmg04Ns' )
response = urllib2.urlopen(req)
return response.read()
I have tested it on my local server it works perfectly , but if I run it on my server (nginx,gunicorn,django-mongoDB,mongoDB) then it gives me this Error.I know about this error that if a view doesnot return HttpResponse from a view then it djangi raises error "Nonetype object has no attribute csrf_exempt' " but in my case i am returning response which is in json format but still its giving me error.Please help me
You aren't returning an HttpResponse when you return Error(), so Django can't apply the decorator to it.