pythonjinja2sanic

Sanic how to locate to static file


I want to locate to static file, because there are many relative path in the html, like:

<a href="1.html"> page1 </a>
<a href="2.html"> page2 </a>
....

I can use app.send_static_file() in flask to made it.

from flask import Flask
app = Flask(__name__, static_url_path='')
@app.route('/')
def index():
    return app.send_static_file('index.html')
if __name__ == '__main__':
    app.run(host="0.0.0.0",debug=True,port=8888)

But for Sanic I didn't find the relevant method.

from sanic import Sanic
app = Sanic(__name__)
app.static('/static', './static')
@app.route('/')
async def index(request):
    #return "static/index.html" file with static state.
if __name__=='__main__':
    app.run(host='0.0.0.0',port=8888,debug=True, auto_reload=True)

Is there any way to achieve this? Or sanic-jinja2, sanic-mako etc. method is fine, too.


Solution

  • It is a little unclear to me exactly what you are looking to do, so I will provide a couple of examples that might be what you are looking for. Please let me know if this does or does not solve the problem and I can amend the answer.


    Static files

    If you have a single static file (this also works for a directory of static files) that you would like to serve, then you use app.static

    app.static("/static", "/path/to/directory")
    # So, now a file like `/path/to/directory/foo.jpg`
    # is available at http://example.com/static/foo.jpg
    

    This would also apply to deeply nested files in /path/to/directory.

    You can also choose to use this pattern on a single file, often helpful with index.html for example:

    app.static("/", "/path/to/index.html")
    

    Retrieving (or looking up) a URL for a static file

    If by "locating" a file you mean you want to get access to its URL, then you would use app.url_for

    app.static(
        "/user/uploads",
        "/path/to/uploads",
        name="uploads",
    )
    app.url_for(
        "static",  # Note, for any file registered with app.static, this value is "static"
        name="uploads",
        filename="image.png",
    )
    

    Serving files from a route handler

    If on the other hand you have a regular route handler and would like to respond with a file (meaning you are doing something more than just serving a static file), then you can use sanic.response.file.

    Let's imagine a scenario where you need to lookup a user and fetch their profile image:

    @app.get("/current-user/avatar")
    async def serve_user_avatar(request: Request):
        user = await fetch_user_from_request(request)
        return await file(user.avatar)
    

    Templating

    Since you brought up jinja and mako, Sanic Extensions is an officially supported plugin that adds templating:

    pip install "sanic[ext]"
    
    @app.get("/")
    @app.ext.template("foo.html")
    async def handler(request: Request):
        return {"seq": ["one", "two"]}
    

    See this PR for alternative methods of serving templates with a render function

    Looking back to your example...

    Your example shows this:

    app.static('/static', './static')
    
    @app.route('/')
    async def index(request):
        #return "static/index.html" file with static state.
    

    To me, it looks like you have a file in ./static/index.html that you want to serve just that file. In this case, the @app.route definition is unnecessary, since it will be server because of your app.static definition. If you have a folder structure like this:

    ./root
    ├── static
    │   └── index.html
    └── server.py
    

    Then all you need is:

    app.static("/static", "./static")
    

    And now you will have: http://example.com/static/index.html