[PYTHON] Introducing JustPy, a high-level web framework that does not require front-end programming

What is JustPy

JustPy is a high-level web framework in Python that is object-oriented and content-based and does not require front-end programming.

An object-oriented, component based, high-level Python Web Framework that requires no front-end programming.

With Flask, Django, etc., you can complete a lot with Python alone, but you still need to write HTML using Jinja2 etc. On the other hand, this JustPy is really complete with Python alone.

Also, as it is said to be high level, the base is a web framework called Starllete, which supports Async. Also, the front end is based on Vue.js.

The following is my own summary of the results of tracing the Official Tutorial to the model and data Attributes.

Simple example

It implements HTML elements as classes. The web page itself (the entire HTML to be displayed) is also a class called WebPage (), and content is added by adding other child elements to the instantiated one.

import justpy as jp


def test():
    #p element is P()Is implemented in the class
    p = jp.P()
    p.text = 'This is test site.'

    #The web page itself is also a web page()An instance of the class.
    wp = jp.WebPage()
    #Content is added by adding a p element there.
    wp.add(p)
    
    return wp


jp.justpy(test)

After doing the above, when you access localhost: 8000 in your browser, you will see "This is test site."

By the way, it is also possible to shorten the exact same content.

def test_short():
    #The web page itself is also a web page()To an instance of the class. Add p element there
    wp = jp.WebPage()
    p = jp.P(text='This is test site.', a=wp)
    return wp

CSS For CSS, it seems that it is supposed to use a framework called Tailwind. (It is also possible to specify without using the framework)

def test_tailwind():
    wp = jp.WebPage()
    p_css = "w-64 bg-pink-500 m-2 hover:bg-pink-700 text-white font-bold py-2 px-4 rounded"
    jp.P(text='This is test site.', a=wp, classes=p_css)
    return wp

Specify the width with w-xx and the background color with bg-xxx. For example, for width, you can see the definition by looking at the Official Document. w-0 corresponds to 0.25 rem, and it seems that 0.25 rem increases for every 1 thereafter. (Up to 64) rem will be the font-size of the root element (usually HTML). Also, if it is a fraction such as 1/2, it will be specified as 1/2 of the screen width. Reference: https://qiita.com/butchi_y/items/453654828d9d6c9f94b0 It seems that this description of w-xxx is called utility. m : margin px, py: padding (px is the horizontal margin, taken at the left and right ends) text, bg: color. The number at the back is in increments of 100, and the larger the number, the darker the color.

Event handling

Events are bound to Python functions. Event occurrence such as mouse click = execution of corresponding function.

from pprint import pprint

def click(self, msg):
    self.text = 'Clicked.'
    #To check the contents of msg
    pprint(msg)


def test_event():
    wp = jp.WebPage()
    d = jp.P(text='Not clicked.', a=wp, classes='w-64 m-2 p-1 bg-pink-500 text-white')
    d.on('click', click)
    return wp


jp.justpy(test_event)

The function corresponding to the event must take two arguments, the first is the object that generates the event (recommended to be self), and the second is the details of the event that occurred (recommended to be msg). is.

{'class_name': 'P',
 'event_current_target': '1',
 'event_target': '1',
 'event_type': 'click',
 'html_tag': 'p',
 'id': 1,
 'msg_type': 'event',
 'page': WebPage(page_id: 0, number of components: 1, reload interval: None),
 'page_id': 0,
 'session_id': '49bd7917e083441493a179bd85cda70d',
 'target': P(id: 1, html_tag: p, vue_type: html_component, name: No name, number of components: 0),
 'vue_type': 'html_component',
 'websocket': <starlette.websockets.WebSocket object at 0x0000024AE46CA400>,
 'websocket_id': 0}

routing

Routing is also very simple, just specify the function to call the path in the class called Route.

def home():
    wp = jp.WebPage()
    wp.add(jp.P(text='This is Home.', classes='w-64 m-2 p-1 bg-pink-500 text-white'))
    return wp

jp.Route('/home', home)

jp.justpy()

Now when you access localhost: 8000 / home you will see it. Conversely, if home is not specified, it will be Not Found. You can also write the same content using a decorator. If you know Flask, this may be easier to understand.

@jp.SetRoute('/home')
def home():
    wp = jp.WebPage()
    wp.add(jp.P(text='This is Home.', classes='w-64 m-2 p-1 bg-pink-500 text-white'))
    return wp

input

For input, use the Input class provided like other HTML elements.

input_class = 'w-64 m-2 p-1 bg-pink-500 text-white'
output_class = 'w-64 m-2 p-1 bg-indigo-500 text-white'

async def input_test(self, msg):
    self.p.text = self.value

@jp.SetRoute('/input_test')
async def home(request):
    wp = jp.WebPage()
    input_box = jp.Input(a=wp, classes=input_class, placeholder='Inout')
    input_box.p = jp.P(text='Output', classes=output_class, a=wp)
    input_box.on('input', input_test)
    return wp

jp.justpy()

I will specify a fixed event name called input for on. The received event is processed in the corresponding function. Since the object that caused the event is included in self, the text content is rewritten to the input content.

model

In the previous example, the information in the entered text was used as is and not saved, but it can be saved in the form of a model and used by other components. The following shows the contents input to Input in another component (p element).

@jp.SetRoute('/usecase2')
async def usecase2(request):
    wp = jp.WebPage(data={ 'text': 'Initial text'})
    jp.Input(a=wp, classes=input_class, placeholder='Please type here', model=[wp, 'text'])
    jp.P(model=[wp, 'text'], classes=output_class, a=wp)
    return wp

For WebPage, you can specify dictionary format data as a model with the argument data. Both the Input element and the P element refer to the model with the argument model. The way of referencing is slightly different, and model = [wp,'text']. It seems to mean "data corresponding to the key called text in the model specified by the instance called wp". I'm investigating because it's unclear how this model will be persisted (or can).

Impressions

Except for the model persistence part, most things seem to be easier than Flask / Django. Also, looking at the official tutorial, it seems that it can be used for a wide range of purposes. Next time I make something myself, I will definitely use it.

Recommended Posts

Introducing JustPy, a high-level web framework that does not require front-end programming
I tried a neural network Π-Net that does not require an activation function
Introducing pyserde, a serialization framework that uses dataclass
When incrementing the value of a key that does not exist
A special Python codec that seems to know but does not know