Views

If you have read QuickStart CRAX you already know the basics. Now let’s talk about Crax views in more detail.

BaseView

BaseView All Crax views are inherited from this view. Takes initial parameters:
request:

The first parameter of every Crax view must be request. It doesn’t matter if your handler inherits from Crax views or you wrote your own opinion. The first parameter should always be a request that for an instance of crax.Request.

# Custom coroutine based view
async def custom_coroutine_view(request, scope, receive, send):
    response = TextResponse(request, "Hello world")
    await response(scope, receive, send)

# Custom class based view
class CustomView:
    def __init__(self, request):
        self.request = request

    async def __call__(self, scope, receive, send):
        response = TextResponse(self.request, "Hello world")
        await response(scope, receive, send)

This is the correct way to create your custom handlers that do not inherit from Crax views. Of course if you create your handlers that inherit from Crax views, you don’t need to define a request.

from crax.views import BaseView

class CustomView(BaseView):
    async def get(self):
        pass
context:

One of the ways to store data and pass it to Response.

class CustomView(TemplateView):
    template = 'index.html'

    # We don't need to return anything, template will be rendered with request parameters
    # because we set the context
    async def get(self):
        self.context = self.request.params
args

Any additional arguments.

kwargs:

Any additional arguments.

BaseView and all child classes have attributes:
methods:

List type. The default is [“GET”]. By default, all handlers should only care about the “GET” method. If that’s what you want, don’t define anything. If you want to increase or change the default methods, set this attribute. Note that this attribute cannot be empty, or an exception will be raised.

from crax.views import BaseView

class CustomView(BaseView):
    methods = ['GET', 'POST', 'PATCH']
    async def get(self):
        pass

The note! If you are going to create your own coroutine based views, you will need to manage the available the methods themselves.

class MyView(BaseView):
    methods = ['GET', 'POST']
    # For all methods except "GET" and "POST" will be returned 405 response
    async def get(self):
        pass


class CustomView:
    methods = ['GET', 'POST']
    # For all methods except "GET" and "POST" will be returned 405 response

    def __init__(self, request):
        self.request = request


async def my_custom_coroutine_view(request, scope, receive, send):
    # All methods are supported
    if request.method == "GET":
        response = TextResponse(self.request, "Hello world")
        await response(scope, receive, send)
    elif request.method == "POST":
        response = JSONResponse(self.request, {"error": "Method not allowed"}, status_code=405)
        return response
login_required:

Bool type. The default is False. Change it to True to give access only to authorized users.

from crax.views import TemplateView

class LoginRequired(TemplateView):
    login_required = True
    methods = ["GET"]


class AuthorizedViewOne(LoginRequired):
    template = 'index.html'

class AuthorizedViewTwo(LoginRequired):
    template = 'cabinet.html'
staff_only:

Type of bool. Default value is False. If you want to grant access staff only persons, change it to True.

superuser_only:

Type of bool. Default value is False. If you want to grant access superuser only, change it to True.

Why would you rather inherit your handlers from Crax views than write your own. Simply because Crax Views provides most of the methods out of the box.

from crax.views import BaseView

# Written your own stuff
class CustomView:
    methods = ['GET', 'POST']
    def __init__(self, request):
        self.request = request

    async def __call__(self, scope, receive, send):
        if self.request.method == 'GET':
            response = TextResponse(self.request, "Hello world")
            await response(scope, receive, send)
        elif self.request.method == 'POST':
            response = JSONResponse(self.request, {"Hello": "world"})
            await response(scope, receive, send)

# Crax based stuff
class CustomView(BaseView):
    methods = ['GET', 'POST']

    async def get(self):
        response = TextResponse(self.request, "Hello world")
        return response

    async def post(self):
        response = JSONResponse(self.request, {"Hello": "world"})
        return response


class CustomersList(TemplateView):
    template = 'second.html'

    # No need return anything in case if it is TemplateView.
    # Template will be rendered with params
    async def get(self):
        self.context['params'] = self.request.params

BaseView methods. The first thing to consider is that all methods must be defined as coroutines. And all methods must return a Response object. See section Responses for details

get():

Define this method if you want to process HTTP “GET” requests. Default status code to return - 200

post():

Define this method if you want to process HTTP “POST” requests. Default status code to return - 201

put():

Define this method if you want to process HTTP “PUT” requests. Default status code to return - 204

patch():

Define this method if you want to process HTTP “PATCH” requests. Default status code to return - 204

delete():

Define this method if you want to process HTTP “DELETE” requests. Default status code to return - 204

If you want to customize status code, just set status code you want to response.

from crax.views import BaseView

class CustomView(BaseView):
    methods = ['POST']
    async def post(self):
        response = JSONResponse(self.request, {"Hello": "world"})
        response.status_code = 200
        return response

JSONView

JSONView View that returns JSONResponse out of the box for HTTP “GET” requests.

from crax.views import JSONView

class JsonEmptyTest(JSONView):
    methods = ["GET"]
    # This will return an empty dict


class JsonTest(JSONView):
    methods = ["GET"]
    # No need to return anything. Just set some value to context attribute
    # And it will be returned as JSONResponse

    async def get(self):
        self.context = {'Hello': "World"}

Of course, you can override the default behavior and return something else. JSONView takes the same parameters as BaseView. However, he has one special method. create_context():

Therefore, you should not return anything for HTTP “GET” requests. It will be called every time your handler receives a request of type “GET”.

from crax.views import JSONView


class JsonTest(JSONView):
    methods = ["GET"]
    # We can do something with create_context() as usual

    async def create_context(self):
        self.context = {'Hello': "World"}
        return await super(JsonTest, self).create_context()

And finally we want to create some other default methods.

from crax.views import JSONView

class JsonTest(JSONView):
    methods = ["POST"]

    # Note that all methods except of get() should always return instance of Response
    async def post(self):
        self.context = {'Hello': "World"}
        response = JSONResponse(self.request, self.context)
        return response

TemplateView

TemplateView is the View for template rendering.

The first thing you should think about using this view is defining the template attribute.

from crax.views import TemplateView

class Home(TemplateView):
    template = 'index.html'
    # You need nothing more. Now template "index.html" will be rendered

The TemplateView takes the same parameters as the BaseView. However it has one special method. render_response()

It will be called every time your handler receives a “GET” request. It is the same behavior with JSONView, but here we render templates instead of sending JSON.

from crax.views import TemplateView

class Home(TemplateView):
    methods = ["GET", "POST"]
    template = 'index.html'

    # No need to return anything - template will be rendered with context
    async def get(self):
        self.context = {'Hello': "World"}

    async def post(self):
        self.context = {'Hello': "World"}
        response = JSONResponse(self.request, self.context)
        return response

How does Crax know where you store your templates? Good. You don’t have to define template directories. But there is just one rule: all of your template directories should be named templates. Jinja FileSystemLoader will be try to find your templates in all app directories defined in project config. See: ref: settings section for details. You should be aware that all templates will render asynchronously as well. Crax uses Jinja2 templates - this is a template processor, so whatever you can do with Jinja, you can do with Crax. However, sometimes you need custom template functions. See Template rendering and Static Files for details.

SwaggerView

SwaggerView Swagger View is just a kind of TemplateView displaying interactive documentation. He predestined template, and its enable_csrf attribute is set to False.