In response to a question asked in Gitter.
Hey
I’ve just stumbled onto Sanic, and I want to build class views similar pyramid eg:
@route('/user/<username>') class UserView(ClassViewParent): def set_context(self, username): self.request.user = ORM.objects.get_or_404(username=username) @app.route("/", methods=["GET"]) def show_profile(self): # here we have access to self.request and self.context which is the user object # show the user profile @app.route("/", methods=["PUT"]) def update_user(self): # here we have access to self.request and self.context which is the user object @app.route("/delete", methods=["GET"]) def delete_user_confirm(self): # here we have access to self.request and self.context which is the user object # sends user to confirm page to delete account @app.route("/delete", methods=["DELETE"]) def delete_user(self): # here we have access to self.request and self.context which is the user object # deletes account
should I be creating a considering creating my own class that does this?
am I wrong to want todo things this way?
can you suggest a better way or perhaps code that is already out there that I should try?I have created this class type view in flask before, however I remember is not being as awesome as I wanted it to be
…
Thanks @ahopkins, as far as I can see the ClassViews only allow you to add get, port, put, etc methods to that class, where I am looking for more of a functional view encased in a class. I’m not sure if my idea is a bad idea, perhaps I am looking for something between a mix of Class Views and Blueprints
This is (IMO) one of the places where Sanic being “unopionated” comes through. There are a few different ways this could be handled, but I will present two here: middleware and decorators.
Also, for sake of completeness, I am putting part of the example inside a Blueprint.
from sanic import Sanic, Blueprint
from sanic.views import HTTPMethodView
from sanic.response import text
from sanic.exceptions import InvalidUsage
app = Sanic("nesting")
app.config.FALLBACK_ERROR_FORMAT = "text"
bp = Blueprint("user", url_prefix="/user/<username>")
@app.middleware
async def inject_xyz(request):
print("Execute on all requests")
request.ctx.xyz = "XYZ"
@bp.middleware
async def inject_user_id(request):
print("Execute on /user requests")
request.ctx.user_id = 99
def inject_abc(fn):
def wrapper(request):
request.ctx.abc = "ABC"
return fn(request)
return wrapper
class Foo(HTTPMethodView):
decorators = [inject_abc]
async def get(self, request):
return text(request.ctx.abc)
async def post(self, request):
return text(request.ctx.xyz)
class UserRoot(HTTPMethodView):
async def get(self, request, username):
return text(f"User ID for {username} is {request.ctx.user_id}")
class UserDelete(HTTPMethodView):
async def delete(self, request, username):
if username == "superman":
raise InvalidUsage("You cannot defeat Superman!")
return text("Deleted")
bp.add_route(UserRoot.as_view(), "/")
bp.add_route(UserDelete.as_view(), "/delete")
app.add_route(Foo.as_view(), "/foo")
app.blueprint(bp)
app.run(debug=True, port=9999)
Now, let’s query:
$ curl localhost:9999/foo
ABC
$ curl localhost:9999/foo -X POST
XYZ
$ curl localhost:9999/user/superman
User ID for superman is 99
$ curl localhost:9999/user/superman/delete -X DELETE
⚠️ 400 — Bad Request
====================
You cannot defeat Superman!
And, the server logs:
[2021-01-27 13:19:29 +0200] [2705884] [INFO] Goin' Fast @ http://127.0.0.1:9999
[2021-01-27 13:19:29 +0200] [2705884] [INFO] Starting worker [2705884]
Execute on all requests
[2021-01-27 13:20:16 +0200] - (sanic.access)[INFO][127.0.0.1:44014]: GET http://localhost:9999/foo 200 3
Execute on all requests
[2021-01-27 13:20:20 +0200] - (sanic.access)[INFO][127.0.0.1:44018]: POST http://localhost:9999/foo 200 3
Execute on all requests
Execute on /user requests
[2021-01-27 13:20:25 +0200] - (sanic.access)[INFO][127.0.0.1:44020]: GET http://localhost:9999/user/superman 200 26
Execute on all requests
Execute on /user requests
[2021-01-27 13:20:30 +0200] - (sanic.access)[INFO][127.0.0.1:44022]: DELETE http://localhost:9999/user/superman/delete 400 77