Subclass HttpResponse to get JSON output in Django - python

I have a number of views in a Django app that all return something like this:
return HttpResponse(jsonpickle.encode(data, unpicklable=False), 'application/json')
This works well, but I'd like to create an abstraction over the JSON encoding and creating the response object, so that I can do something like
return JsonResponse(data)
and the class JsonResponse does all the heavy lifting for me.
I tried something like this:
class JsonResponse(HttpResponse):
def __init__(self, obj):
super(HttpResponse, self).__init__(jsonpickle.encode(obj, unpicklable=False), 'application/json')
but when I have that, I get the standard A server error occurred. Please contact the administrator. when I view the web page. I've also tried with self as the first argument to the inner call to __init__ as well as with the arguments named (content and content_type respectively) and with and without a named status=200. Neither of these changes seem to change anything.
The terminal output from the dev server is a little more descriptive, but not by much:
Traceback (most recent call last):
File "/usr/lib/python2.7/wsgiref/handlers.py", line 85, in run
self.result = application(self.environ, self.start_response)
File "/usr/local/lib/python2.7/dist-packages/Django-1.5.1-py2.7.egg/django/core/handlers/wsgi.py", line 267, in __call__
start_response(force_str(status), response_headers)
File "/usr/lib/python2.7/wsgiref/handlers.py", line 175, in start_response
assert int(status[:3]),"Status message must begin w/3-digit code"
ValueError: invalid literal for int() with base 10: 'app'
[02/Jun/2013 00:51:06] "GET / HTTP/1.1" 500 59
I know I could just create a method that returns the HttpResponse instead, like so:
def json(obj):
return HttpResponse(...)
but I'd like to learn a way to do this the way I originally imagined it if it's possible - if nothing else then for my learning (and it also seems to align with the design of Django, which I like).
Is there a way to get a subclass like JsonResponse above to work? If so, what am I doing wrong?

You have to pass JsonResponse as the first argument of super, otherwise you are calling the constructor of HttpResponseBase:
class JsonResponse(HttpResponse):
def __init__(self, obj):
super(JsonResponse, self).__init__(jsonpickle.encode(obj, unpicklable=False), 'application/json')

Related

Tornado-swirl not picking up the params in a URL

I have an API which is built in Tornado, and I'm trying to document it using tornado-swirl. For some reason, it's unable to pick the optional query param from the defined URL. How could this be solved? I'm not sure what I'm doing wrong, or what I'm missing here.
I've changed the pattern and even used the exact one used in the
docs and tut.
import tornado.web
import tornado_swirl as swirl
from .base import BaseHandler
#swirl.restapi('/item/(?P<id>[\w-]+)?')
class ItemHandler(BaseHandler):
def post(self, id):
"""Item
Creating a new item
Tags:
Item
"""
# store the item
pass
async def get(self, id):
"""Item
Get items or item
Tags:
Item
"""
# return all items if no id was provided
# or return item by id when provided
pass
I'm getting the following error:
Traceback (most recent call last):
File "/Users/.../venv/lib/python3.7/site-packages/tornado/web.py", line 1697, in _execute
result = method(*self.path_args, **self.path_kwargs)
File "/Users/.../venv/lib/python3.7/site-packages/tornado_swirl/views.py", line 101, in get
for path, spec, operations in apis},
File "/Users/.../venv/lib/python3.7/site-packages/tornado_swirl/views.py", line 100, in <dictcomp>
'paths': {path: self.__get_api_spec(spec, operations)
File "/Users/.../venv/lib/python3.7/site-packages/tornado_swirl/views.py", line 368, in find_api
['{%s}' % arg for arg in [param.name for param in vals]]
TypeError: not enough arguments for format string
Apparently, it's not getting the arguments. I think it has something to do with how I'm defining the URL there.
You just need to inform the path parameter in the docstring, something like that:
"""Item
Creating a new item
Path Params:
id (string) -- Your id
Tags:
Item
"""

flask_restplus add_namespace keep getting no attribute 'as_view'

I writing a flask, trying to organize it by using Blueprint with Namespace, following this tutorial
I had faced some problem, and had look around internet and had review solution in 1 and 2. The first one is not relevant to what I doing, and the second one the solution just doesn't fix my problem.
Here are my code:
project/project.py
from flask import Flask, jsonify, url_for
from .apis.apis import api
app = Flask(__name__)
app.register_blueprint(api, url_prefix="/api")
project/apis/apis.py
from flask import Blueprint
from .user.authentication import auth
from flask_restplus import Api, apidoc, Resource
blueprint = Blueprint("api", __name__)
api = Api(blueprint, doc='/docs', ui=False)
api.add_namespace(auth, path="/auth") #Keep getting error at this line
project/apis/user/authentication.py
from flask_restplus import Namespace
auth = Namespace('auth', description='Authentication')
#auth.route("/test")
def authentication():
return "test"
Stack Trace
Traceback (most recent call last):
File "/home/gaara/Python/Flask-Api/project/__init__.py", line 1, in <module>
from .project import app
File "/home/gaara/Python/Flask-Api/project/project.py", line 3, in <module>
from .apis.apis import api
File "/home/gaara/Python/Flask-Api/project/apis/apis.py", line 13, in <module>
api.add_namespace(auth, path="/auth")
File "/home/gaara/Python/Flask-Api/venv/lib/python3.6/site-packages/flask_restplus/api.py", line 413, in add_namespace
self.register_resource(ns, resource, *self.ns_urls(ns, urls), **kwargs)
File "/home/gaara/Python/Flask-Api/venv/lib/python3.6/site-packages/flask_restplus/api.py", line 255, in register_resource
self._register_view(self.app, resource, *urls, **kwargs)
File "/home/gaara/Python/Flask-Api/venv/lib/python3.6/site-packages/flask_restplus/api.py", line 276, in _register_view
resource_func = self.output(resource.as_view(endpoint, self, *resource_class_args,
AttributeError: 'function' object has no attribute 'as_view'
I am not sure why I keep getting this error, had try few approach, include put apis.py all in __init__.py and change the import, but always getting the same error.
What I wish is to code api in an organize way, and when go to localhost:5000/api/auth/test it will output me test
You defined a function, but Flask restplus requires a class, as you can also see in your tutorial.
So it should look like this:
from flask_restplus import Resource
#auth.route("/test")
class Authentication(Resource):
def get(self):
return "test"
While the approved answer is fully correct, let me dispose why we always say, that if something is possible, does not mean that you should do!
So the following to be for everyone a lesson (at 1st place for myself) of an ANTI-PATTERN!
I was a bit tinkering here & there, I found out what is needed for a function like you mentioned in order to be registered and usable by a framework, like F-Restplus (I've used in my case F-RestX==0.5.0, but in reality is a fork of that), and here we go:
def avg(dummy_self_var=''):
# the dummy_self_var is needed in order to trick and pretend to be as an instance method
result = 'any-calculation-that-has-to-be-made'
logging.debug(f'AVG result is: {result}')
return Response(str(result))
# imitating that this function is a Resource :D
avg.view_class = Resource
avg.as_view = Resource.as_view # at the end, it could be the following function as well: `lambda x,y: avg`
avg.view_class.methods = {'GET', }
avg.view_class.get = avg
api.add_resource(avg, '/asd')
With the help of this I achieved to have the same functionality, it works &
gets registered automatically by the Swagger-UI docs:
So, while nearly everything is possible, I could not imagine a situation where someone needs this 'workaround', instead, to be forward-compatible, I would definitely refactor instead of producing this mess in the long-run. Of course, the choice is up to you.

Strange issue at subclassing?

Let's have a class representing a Django controller, with one of methods called _onSuccess :
class ConfirmController(object):
...
def _onSuccess(self, controller):
...
The class is instantiated later with:
def credit_confirm_info(request, payment_module, template='/some/template.html'):
controller = ConfirmController(request, payment_module)
controller.confirm() # this method calls self._onSuccess
return controller.response
credit_confirm_info = never_cache(credit_confirm_info)
I'm trying to use subclass of ConfirmController:
class ConfirmControllerEx(ConfirmController):
def _onSuccess(self, controller):
# shortened to demonstrate even simple call to super
# causes a different behaviour
super(ConfirmControllerEx, self)._onSuccess(controller)
I've probably missed something at python learning but can anybody explain why is not the above sublassed _onSuccess equivalent to the original method ?
If I do use the above sublass ConfirmControllerEx:
def credit_confirm_info(request, payment_module, template='/some/template.html'):
controller = ConfirmControllerEx(request, payment_module)
controller.confirm() # this method calls self._onSuccess
return controller.response
credit_confirm_info = never_cache(credit_confirm_info)
I'm getting NoneType has no method has_header error, like credit_confirm_info is called again but with request parameter equal to None.
I expect the sublass and subclassed method _onSuccess with the plain call to super won't differ from the original. Am I missing something here ?
Update (traceback of the exception):
Traceback:
File "/home/dunric/Projects/Example.com/satchmo/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
111. response = callback(request, *callback_args, **callback_kwargs)
File "/home/dunric/Projects/Example.com/satchmo/gastroceny_cz/localsite/views.py" in cod_confirm_info
279. template='shop/checkout/cod/confirm.html')
File "/home/dunric/Projects/Example.com/satchmo/lib/python2.7/site-packages/django/views/decorators/cache.py" in _wrapped_view_func
90. add_never_cache_headers(response)
File "/home/dunric/Projects/Example.com/satchmo/lib/python2.7/site-packages/django/utils/cache.py" in add_never_cache_headers
129. patch_response_headers(response, cache_timeout=-1)
File "/home/dunric/Projects/Example.com/satchmo/lib/python2.7/site-packages/django/utils/cache.py" in patch_response_headers
119. if not response.has_header('Last-Modified'):
Exception Type: AttributeError at /checkout/cod/confirm/
Exception Value: 'NoneType' object has no attribute 'has_header'
I'm not up on the specifics of django involved here, but this method:
def _onSuccess(self, controller):
# shortened to demonstrate even simple call to super
# causes a different behaviour
super(ConfirmControllerEx, self)._onSuccess(controller)
Is not equivalent to the _onSuccess of the parent class. It calls the parent implementation through super, but it ignores whatever that call returns and just returns None (implicitly, by execution reaching the end of the method definition). Given you later get an error that seems to indicate you have a None object (instance of NoneType) where something else was expected, this would be my guess at the error. That's not going to be it if the contract of the _onSuccess method is to always return None, however.

How do modules work in Python?

I was wondering how does a module really work in Python.For example I have this code
import requests
r = requests.get("http://www.google.com")
print r.status_code
Now according to my understanding, the requests module should have a python file which would be containing a class called "get" and within the "get" class there must be a member variable called "status_code"
So when I create the object "r", I get the variable status_code for it.
However, when I looked at all the files that come in the package, I could not find any class named "get".
I could however find a function called "get", under a class called "response". But since we did not create the object as an instance of the "response" class, how can we access the "get" function inside it?
I think I am missing a key concept here, can someone point it out for me please?
Thanks
When you import requests file __init__.pyis executed, if you examine that file in your case, you will find this line:
from .api import request, get, head, post, patch, put, delete, options
Which means that from api.py you are importing get() function:
def get(url, **kwargs):
kwargs.setdefault('allow_redirects', True)
return request('get', url, **kwargs)
And as you can see it calls request function from api.py that looks like:
def request(method, url, **kwargs):
session = sessions.Session()
return session.request(method=method, url=url, **kwargs)
That creates an object Session defined inside session.py, then calls its method request. This method will call method send() which returns a Responseobject which is defined in the class Response inside models.py (I copy the first lines):
class Response(object):
def __init__(self):
super(Response, self).__init__()
self._content = False
self._content_consumed = False
#: Integer Code of responded HTTP Status.
self.status_code = None
...
Here is where status_code is defined, so when you invoke r = requests.get("http://www.google.com") you are retrieving this object and then you can access to status_code
Your understanding is not entirely correct.
The requests module is an object; .get is then an attribute lookup on that object; it has to be a callable object because you try to call it with the (...) syntax. That means it can be a class, or a function or any other object with a __call__ method.
That callable returns something; all callables do. For a class, generally an instance is returned, but for a function that can be any Python object. Whatever .get() does, it returns an object that has a .status_code attribute, or has a .__getattr__ method that returns something when called with the name status_code.
In this specific case, get() is a function, which has been imported into the requests/__init__.py package initializer module. This function, indirectly, creates a Session() instance, and calls the .request() method on that instance. That method, eventually, returns a Response instance, which does have a .status_code attribute.

Why do I get TypeError: get() takes exactly 2 arguments (1 given)? Google App Engine

I have been trying and trying for several hours now and there must be an easy way to retreive the url. I thought this was the way:
#from data.models import Program
import basehandler
class ProgramViewHandler(basehandler.BaseHandler):
def get(self,slug):
# query = Program.all()
# query.filter('slug =', fslug)
self.render_template('../presentation/program.html',{})
Whenever this code gets executed I get this error on the stacktrace:
appengine\ext\webapp__init__.py", line 511, in call
handler.get(*groups)
TypeError: get() takes exactly 2 arguments (1 given)
I have done some debugging, but this kind of debugging exceeds my level of debugging. When I remove the slug from def get(self,slug) everything runs fine.
This is the basehandler:
import os
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
class BaseHandler(webapp.RequestHandler):
def __init__(self,**kw):
webapp.RequestHandler.__init__(BaseHandler, **kw)
def render_template(self, template_file, data=None, **kw):
path = os.path.join(os.path.dirname(__file__), template_file)
self.response.out.write(template.render(path, data))
If somebody could point me in the right direction it would be great! Thank you! It's the first time for me to use stackoverflow to post a question, normally I only read it to fix the problems I have.
You are getting this error because ProgramViewHandler.get() is being called without the slug parameter.
Most likely, you need to fix the URL mappings in your main.py file. Your URL mapping should probably look something like this:
application = webapp.WSGIApplication([(r'/(.*)', ProgramViewHandler)])
The parenthesis indicate a regular expression grouping. These matched groups are passed to your handler as arguments. So in the above example, everything in the URL following the initial "/" will be passed to ProgramViewHandler.get()'s slug parameter.
Learn more about URL mappings in webapp here.
If you do this:
obj = MyClass()
obj.foo(3)
The foo method on MyClass is called with two arguments:
def foo(self, number)
The object on which it is called is passed as the first parameter.
Maybe you are calling get() statically (i.e. doing ProgramViewHandler.get() instead of myViewHandlerVariable.get()), or you are missing a parameter.

Categories

Resources