Git Product home page Git Product logo

Comments (29)

istommao avatar istommao commented on April 27, 2024 34

@r0fls It works but i think use html function replace text maybe better

from sanic import Sanic
from sanic.response import html

from jinja2 import Environment, PackageLoader

env = Environment(loader=PackageLoader('app', 'templates'))

app = Sanic(__name__)

@app.route('/')
async def test(request):
    data = {'name': 'name'}

    template = env.get_template('index.html')
    html_content = template.render(name=data["name"])
    return html(html_content)


app.run(host="0.0.0.0", port=8000)

from sanic.

luizberti avatar luizberti commented on April 27, 2024 14

I think this is not necessary.

It's trivial to import jinja2 and use it if you so desire, it's not like Jinja support is so complex, or needs some sort of deep integration with Sanic, to justify being pulled into the project's core. Jinja is not even hard to use by itself.

As of right now, Sanic is perfectly simple, has minimal usage of other dependencies, and in many ways it's more of a microframework than Flask itself. You can perfectly use Jinja with Sanic right now, as well as whatever templating engine you desire, it's all one import away.

The community can also create a Jinja2 integration module for Sanic if they so desire (and it's really easy to do so). The same holds true for any other templating system or format they want to use in the future.

The alternative to people who don't want to use Jinja is not as pleasing. Adding Jinja as a dependency will have everyone who intends to use Sanic as a backend tool only installing Jinja. It will also have people who want to use other templating engines be forced into having Jinja in their dependencies even though they will never use it.

From a development perspective, adding Jinja would only serve to enlarge a beautifully small core. It's also more surface to maintain, and a detraction from the idea of a microframework in my opinion. Just look at the Frankenstein that is Flask nowadays -- crossed imports from werkzeug, multiple interfaces that accomplish the same thing, no standard way of doing things, not to mention the gigantic documentation for something that is supposed to be micro.

This project has everything going for it, and a growing community, at a rate that is impressive for such a new project. Personally what drove me to this is the small footprint, in all regards. I'd much rather see the community build on top of this and keep the core small, rather than just request the devs to build everything into the core. Especially something like this which is simple and probably wouldn't take more than 100 LOC to build.

My vote is for keeping Sanic sane, slim, pluggable, and performant. And build a vibrant community of modules around it πŸ‘

from sanic.

r0fls avatar r0fls commented on April 27, 2024 12

In case anyone is confused, you can use jinja2 currently with sanic:

from jinja2 import Template
from sanic import Sanic
from sanic.response import text

template = Template('Hello {{ name }}!')

app = Sanic()

@app.route("/")
async def test(request):
        data = request.json
        return text(template.render(name=data["name"]))

app.run(host="0.0.0.0", port=8000)

Then, to see it working:

curl -d '{"name": "r0fls"}' localhost:8000

from sanic.

seemethere avatar seemethere commented on April 27, 2024 6

@r0fls That would actually be a great thing to include in examples

from sanic.

seemethere avatar seemethere commented on April 27, 2024 6

Templating will not be built into Sanic core to keep the core as lean and performant as possible. Thanks for everyone's input on the subject!

from sanic.

imbolc avatar imbolc commented on April 27, 2024 4

@seemethere @r0fls as I mention in the starting message it's very often you need context processors. So it will be much more code than you show. Of course it may be implemented as independent library. So question is why I propose to include it into framework. The answer is because many flask or django apps include templates. So they need some agreement where (in which folder) to locate it e.t.c. It may be implemented with independent template library too. But if there will be many such libs, it will cause problem to use apps that relied on different of these.

In the one sentence: I think built-in templates will increase popularity of sanic as it was with flask and django.

from sanic.

imbolc avatar imbolc commented on April 27, 2024 4

@Benozo why are you creating jinja environment each request?

  1. Try to move it into global space.
  2. Try to move even env.get_emplate() into globals. And if it will be significantly faster, try to play with jinja settings of debugging and reloading. Or just cache all the templates yourself with functools.lru_cache

from sanic.

aking1012 avatar aking1012 commented on April 27, 2024 4

If you don't mind complicating your stack a little, you can push all your template rendering client side and save it in localstorage with something like react. Then handle all the "work" rendering the template there. Only ask sanic when you need actual json data. I mean, if you gotta go fast.

That said, the class based views and models in django while slower, are really convenient.

from sanic.

roniemartinez avatar roniemartinez commented on April 27, 2024 3

πŸ‘
I'll be happy even if there is only a Jinja2 support :p

from sanic.

Benozo avatar Benozo commented on April 27, 2024 3

I think Jinja2 is slow, not that is noticeable but wrk recons otherwise .
If anyone is interested here is a simple wrk bench between Jinja2 and SimpleTemplates by Bottle..

Enviroment:
Processor: Intel(R) Core(TM) i5-5200U CPU @ 2.20GHz (4 CPUs), ~2.2GHz
Memory: 8192MB RAM
Sanic running under Windows Subsystem with Ubuntu 16 Kernel

index.html = <h1>Hello Sanic</h1>

SimpleTemplate

@app.route('/')
async def index(request):
    return html(tpl('index.html'))

Jinja2 Template

def template(tpl, **kwargs):
    env = Environment(loader=PackageLoader('main', 'views'),autoescape=select_autoescape(['html', 'xml', 'tpl']))
    template = env.get_template(tpl)
    return html(template.render(kwargs))

@app.route('/')
async def index(request):
    return template('index.html')

'''
Jinja2

wrk -c 100 -t 2 --latency -v http://localhost:8085/
wrk 4.0.0 [epoll] Copyright (C) 2012 Will Glozer
Running 10s test @ http://localhost:8085/
2 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 209.11ms 68.58ms 403.50ms 76.61%
Req/Sec 249.01 112.91 490.00 65.00%
Latency Distribution
50% 180.66ms
75% 200.99ms
90% 336.00ms
99% 374.64ms
4691 requests in 10.10s, 774.20KB read
Requests/sec: 464.66
Transfer/sec: 76.69KB

Bottle SimpleTemplate

wrk -c 100 -t 2 --latency -v http://localhost:8085/
wrk 4.0.0 [epoll] Copyright (C) 2012 Will Glozer
Running 10s test @ http://localhost:8085/
2 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 34.19ms 11.65ms 75.01ms 66.65%
Req/Sec 1.41k 153.44 1.77k 67.68%
Latency Distribution
50% 30.51ms
75% 43.01ms
90% 52.32ms
99% 61.88ms
28042 requests in 10.03s, 4.52MB read
Requests/sec: 2795.71
Transfer/sec: 461.40KB
'''

from sanic.

seemethere avatar seemethere commented on April 27, 2024 2

I'm going to close this at the end of the week, unless someone has a really good idea why we should bake jinja2 into sonic core. Jinja2 example has been added as of #193.

from sanic.

seemethere avatar seemethere commented on April 27, 2024 1

@istommao and at that point for data you could just use **data to avoid having to rename arguments. Or if you want to get the full effect of a context_processor you could just pass **locals() to the template.render.

I think this shows you can get the full effects of the template engine jinja2 without it having to be baked into sanic core.

from sanic.

axsapronov avatar axsapronov commented on April 27, 2024

+1

from sanic.

femmerling avatar femmerling commented on April 27, 2024

+1

from sanic.

istommao avatar istommao commented on April 27, 2024

+1

from sanic.

seemethere avatar seemethere commented on April 27, 2024

What benefit does this add besides you not needing to import the jinja2 package?

from sanic.

istommao avatar istommao commented on April 27, 2024

@seemethere I agree with you!

from sanic.

longtian001 avatar longtian001 commented on April 27, 2024

we also put that in blueprint,for example:
configure template into blueprint

/home/webapp
|-- main.py
|-- my_blueprint.py
templates
|-- index.html

1).main.py

from sanic import Sanic
from my_blueprint import bp

app = Sanic(__name__)
app.blueprint(bp)

app.run(host='0.0.0.0', port=8000, debug=True)

2).my_blueprint.py

# more my_blueprint.py 
from sanic.response import json, text, html
from sanic import Blueprint
from jinja2 import Environment, PackageLoader
env = Environment(loader=PackageLoader('my_blueprint', 'templates'))

bp = Blueprint('my_blueprint')

@bp.route('/')
async def bp_root(request):
    template = env.get_template('index.html')
    content=template.render(title='Sanic',people='David')
    return html(content)

3).index.html

<!doctype html>
<title>{{ title }}</title>
<div class=page>
  <h1>hello, {{ people }}</h1>
</div>

from sanic.

m85091081 avatar m85091081 commented on April 27, 2024

i write a little plugin to use flask style render_template , if any one want i will publish it .
screenshot from 2016-12-29 23-33-21

from sanic.

Benozo avatar Benozo commented on April 27, 2024

This is very easy to implement, and +1 on not including it in the Sanic core.

here is a basic function to use Jinja2 with Sanic.

from sanic import Sanic
from sanic.response import json, html, text
from jinja2 import Environment, PackageLoader, select_autoescape

env = Environment(loader=PackageLoader('main', 'templates'),autoescape=select_autoescape(['html', 'xml', 'tpl']))


def template(tpl, **kwargs):
    template = env.get_template(tpl)
    return html(template.render(kwargs))

app = Sanic(__name__)
app.static('/static', './static')

@app.route('/')
async def test(request):
    test = {'pip':'pop','foo':'bar'}
    print(test)
    return template('index.html', title='Sanic',data='blob', test=test)
	

if __name__ == "__main__":
    app.run(host='0.0.0.0',port=8085)

Index.html

<!DOCTYPE html>
<html>
  <head>
    <title>{{title}}</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="http://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" media="screen">
    <link rel="stylesheet" href="static/css/main.css">
  </head>
  <body>
    <div class="container">
      <h1>{{data}}</h1>
      {% for key, value in test.item %}
          {{key}} {{value}}
      {% endfor %}
    </div>
    <script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
    <script src="http://netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
  </body>
</html>

Easy as py :-) .

from sanic.

Benozo avatar Benozo commented on April 27, 2024

@imbolc Yes your correct after i moved the Jinja2 Environment into global space all was fast again, thanks for pointing that out. πŸ‘ .

from sanic import Sanic
from sanic.response import html
from bottle import template as tpl 
from jinja2 import Environment, PackageLoader, select_autoescape

app = Sanic(__name__)

env = Environment(loader=PackageLoader('main', 'views'),autoescape=select_autoescape(['html', 'xml']))

@app.route('/')
async def index(request):
    template = env.get_template('index.tpl')
    return html(template.render())
    #return html(tpl('index')) # Uncomment for Stpl bench

Bottle Stpl

wrk -c 100 -t 2 --latency -v http://localhost:8085/
wrk 4.0.0 [epoll] Copyright (C) 2012 Will Glozer
Running 10s test @ http://localhost:8085/
  2 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    28.83ms    8.53ms  67.77ms   80.37%
    Req/Sec     1.70k   100.46     1.89k    74.00%
  Latency Distribution
     50%   26.52ms
     75%   29.00ms
     90%   43.37ms
     99%   54.57ms
  34047 requests in 10.07s, 6.72MB read
Requests/sec:   3381.78
Transfer/sec:    683.62KB

Jinja2

wrk -c 100 -t 2 --latency -v http://localhost:8085/
wrk 4.0.0 [epoll] Copyright (C) 2012 Will Glozer
Running 10s test @ http://localhost:8085/
  2 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    29.15ms    8.45ms  69.20ms   81.96%
    Req/Sec     1.69k    97.07     1.88k    72.50%
  Latency Distribution
     50%   27.00ms
     75%   29.00ms
     90%   42.00ms
     99%   55.19ms
  33726 requests in 10.06s, 6.66MB read
Requests/sec:   3353.10
Transfer/sec:    677.82KB

from sanic.

siripuramrk avatar siripuramrk commented on April 27, 2024

Any progress regarding render_template ..?

from sanic.

yunstanford avatar yunstanford commented on April 27, 2024

@siripuramrk https://github.com/yunstanford/jinja2-sanic

from sanic.

patic-fr avatar patic-fr commented on April 27, 2024

I'm thinking about using a template engine with Sanic.
I already posted here https://stackoverflow.com/questions/46040053/sanic-template-in-async-mode-and-jinja2 and others before seeing this post.
After reading, I understand that using Jinja2 directly with its API is a good idea.
What is the interest of using the asynchronous mode of Jinja2.
First, reading the template file does not use any asynchronous system (even if aiofiles is not really asynchronous).
Then, a test bench seems to show a decrease of almost 50% in asynchronous mode ...
In your opinion what is the best practice to follow to optimize and keep Sanic's performance, including whether to change template engine?

The template : exemple_jinja2_02.html

<!DOCTYPE html>
<html>
  <head>
    <title>{{title}}</title>
  </head>
  <body>
    <div>
      <h1>{{data}}</h1>
      {% for key, value in test.items() %}
	  {{key}} {{value}} <br>
      {% endfor %}
    </div>
  </body>
</html>

The python file :

from sanic import Sanic
from sanic.response import json, html, text

from jinja2 import Environment, PackageLoader, select_autoescape

env = Environment(loader=PackageLoader('exemple_jinja2_02', 'templates'), autoescape=select_autoescape(['html', 'xml', 'tpl']), enable_async=True)

async def template(tpl, **kwargs):
    template = env.get_template(tpl)
    content = await template.render_async(kwargs)
    return html(content)

app = Sanic(__name__)
app.static('/static', './static')

test = {'pip': 'pop', 'foo': 'bar'}

@app.route('/')
async def index(request):
    content = await template('test_jinja2_02.html', title='Sanic', data='blob', test=test)
    return content

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=8000, debug=True)

I tested with wrk -c 100 -t 2 --latency -v http://0.0.0.0:8000/

in mode asynchronous :

wrk 4.0.0 [epoll] Copyright (C) 2012 Will Glozer
Running 10s test @ http://0.0.0.0:8000/
  2 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    55.45ms    5.19ms 113.79ms   97.09%
    Req/Sec     0.90k   192.56     1.01k    81.50%
  Latency Distribution
     50%   54.53ms
     75%   56.14ms
     90%   57.59ms
     99%   65.56ms
  17992 requests in 10.01s, 13.25MB read
Requests/sec:   1797.40
Transfer/sec:      1.32MB

in mode synchronous :

wrk -c 100 -t 2 --latency -v http://0.0.0.0:8000/
wrk 4.0.0 [epoll] Copyright (C) 2012 Will Glozer
Running 10s test @ http://0.0.0.0:8000/
  2 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    32.10ms    3.88ms  67.35ms   92.74%
    Req/Sec     1.56k   211.24     2.02k    77.50%
  Latency Distribution
     50%   31.36ms
     75%   32.75ms
     90%   34.54ms
     99%   54.93ms
  31098 requests in 10.01s, 22.90MB read
Requests/sec:   3106.24
Transfer/sec:      2.29MB

from sanic.

patic-fr avatar patic-fr commented on April 27, 2024

I forgot, for the people who read this issue, there is an example with Jinja2 in async mode here : https://github.com/channelcat/sanic/pull/641/files
I don't know why but this exemple is not here : https://github.com/channelcat/sanic/tree/master/examples

from sanic.

seemethere avatar seemethere commented on April 27, 2024

@patic-fr Those examples were moved to the wiki: https://github.com/channelcat/sanic/wiki/Examples#jinja

from sanic.

luizberti avatar luizberti commented on April 27, 2024

@patic-fr Reading template files in async is just a bad idea, this should be done once during program startup and then they should be kept cached in memory. Reading them every time you serve a request is just wasteful.

Spawning a coroutine for rendering is another bad idea, rendering your templates is inherently CPU bound and will put pressure on your event loop no matter where they are, there is nothing to be gained by rendering them asynchronously.

In short: Stop reading the file every time, don't render in a separate async function.

from sanic.

imbolc avatar imbolc commented on April 27, 2024

@luizberti

there is nothing to be gained by rendering them asynchronously

actually there is, imagine you have some handlers in a single process, answering different time, e.g. simple json responses (which renders milliseconds) and heavy inherited templates (which renders about a second), with async rendering json responses will become faster. Whole the system probably will become somehow slowly, but smoothly

from sanic.

patic-fr avatar patic-fr commented on April 27, 2024

@luizberti
Ok, I'm dumb, of course, the files are not read every time, there is a cache.

And when I checked the code of Jinja2, I didn't find a async method to read the file.

So, why the async mode in the exemple above with Jinja give bad result in benchmark ?

from sanic.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.