---
# System prepended metadata

title: 08 WSGI form input
tags: [web, day1]

---

---
tags: web,day1
robots: noindex, nofollow
lang: pt-br
---
https://github.com/rochacbruno/python-web-api/tree/main/docs

# 08 WSGI form input

E se quisermos agora permitir que o usuário escreva novas postagens?

Vamos criar uma função nova responsável por receber um dicionário com os dados do post 

```py
# Exemplo de entrada
{
    'title': 'Novo post',
    'content': 'Este é um post novo...',
    'author': 'Bruno Rocha'
}
```

E efetuar a consulta SQL responsável por gravar o novo post no banco de dados.

```py
def add_new_post(post):
    cursor = conn.cursor()
    cursor.execute(
        """\
        INSERT INTO post (title, content, author)
        VALUES (:title, :content, :author);
        """,
        post,
    )
    cursor.commit()
```

E alterar o roteamento na função `application` para interceptar uma requisição post e pegar os dados enviados pelo form.


```py
import cgi
# ...

#def application(...):
#    ...

    elif path == "/new" and method == "POST":
        form = cgi.FieldStorage(
            fp=environ['wsgi.input'],
            environ=environ,
            keep_blank_values=1
        )
        post = {item.name: item.value for item in form.list}
        add_new_post(post)
        body = b"New post Created with Success!"
        status = "201 Created"


# headers = ...
```

Agora precisamos adicionar também um formulário e para isso vamos criar mais um template

`form.template.html` contendo os campos necessários para inserir um novo post no blog.

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Blog</title>
</head>
<body>
    <h1>New Post</h1>
    <form action="/new" method="post">
        <label for="title">Title:</label><br>
        <input type="text" name="title" /><br>
        <label for="content">Content:</label><br>
        <textarea name="content" cols="30" rows="5"></textarea><br>
        <label for="author">Author:</label><br>
        <input type="text" name="author" /><br>
        <input type="submit" value="Enviar">
    </form>
</body>
</html>
```

E por fim adicionamos mais uma rota

```py
elif path == "/new" and method == "GET":
    body = render_template("form.template.html")
    status = "200 OK"

# headers = ...
```

O programa completo:

```py
import cgi
from pathlib import Path
from database import conn


def add_new_post(post):
    cursor = conn.cursor()
    cursor.execute(
        """\
        INSERT INTO post (title, content, author)
        VALUES (:title, :content, :author);
        """,
        post,
    )
    conn.commit()


def render_template(template_name, **context):
    template = Path(template_name).read_text()
    return template.format(**context).encode("utf-8")


def get_posts_from_database(post_id=None):
    cursor = conn.cursor()
    fields = ("id", "title", "content", "author")

    if post_id:
        results = cursor.execute("SELECT * FROM post WHERE id = ?;", post_id)
    else:
        results = cursor.execute("SELECT * FROM post;")

    return [dict(zip(fields, post)) for post in results]


def get_post_list(posts):
    post_list = [
        f"""<li><a href="/{post['id']}">{post['title']}</a></li>"""
        for post in posts
    ]
    return "\n".join(post_list)


def application(environ, start_response):
    path = environ["PATH_INFO"]
    method = environ["REQUEST_METHOD"]
    body = b"Content Not Found"
    status = "404 Not Found"

    if path == "/" and method == "GET":
        posts = get_posts_from_database()
        body = render_template(
            "list.template.html",
            post_list=get_post_list(posts)
        )
        status = "200 OK"

    elif path.split("/")[-1].isdigit() and method == "GET":
        post_id = path.split("/")[-1]
        body = render_template(
            "post.template.html",
            post=get_posts_from_database(post_id=post_id)[0],
        )
        status = "200 OK"

    elif path == "/new" and method == "POST":
        form = cgi.FieldStorage(
            fp=environ["wsgi.input"], environ=environ, keep_blank_values=1
        )
        post = {item.name: item.value for item in form.list}
        add_new_post(post)
        body = b"New post Created with Success!"
        status = "201 Created"

    elif path == "/new" and method == "GET":
        body = render_template("form.template.html")
        status = "200 OK"

    headers = [("Content-type", "text/html")]
    start_response(status, headers)
    return [body]


if __name__ == "__main__":
    from wsgiref.simple_server import make_server

    server = make_server("0.0.0.0", 8000, application)
    server.serve_forever()
```


![](https://github.com/rochacbruno/python-web-api/raw/main/docs/day1/imgs/new_post.png)


Ao submeter verá:

```
New post Created with Success!
```

Agora basta voltar a raiz `/` do site

![](https://github.com/rochacbruno/python-web-api/raw/main/docs/day1/imgs/new_post_list.png)

E ao clicar para ir a `/3` verá

![](https://github.com/rochacbruno/python-web-api/raw/main/docs/day1/imgs/new_post_detail.png)


## Conclusão


No dia a dia é muito melhor e mais produtivo utilizar um framework que já cai trazer a maior parte dessas funcionalidades de forma abstraida e fácil de usar,

O ponto desta aula é que é possível programar para web em Python sem a necessidade de usar frameworks, para isso basta seguir o padrão do protocolo `WSGI`, 
esse conhecimento de como essa parte funciona por baixo dos frameworks é essencial para que você inclusive saiba usar melhor qualquer um dos
frameworks do mercado e quem sabe até criar o seu próprio framework se desejar.