Skip to content

Commit

Permalink
docs(README.md): update
Browse files Browse the repository at this point in the history
  • Loading branch information
marcuxyz committed Nov 8, 2023
1 parent 3675a8a commit 78641a7
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 34 deletions.
25 changes: 11 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

You can use the mvc pattern in your flask application using this extension.

This real world implementation `FLASK MVC` example: https://github.com/negrosdev/negros.dev

## Installation

Run the follow command to install `mvc_flask`:
Expand Down Expand Up @@ -48,7 +46,7 @@ def create_app():

Now, you can use `src` as default directory for prepare your application.

You structure should be look like this:
You structure should be look like this:

```text
app
Expand Down Expand Up @@ -150,7 +148,7 @@ user.update PATCH, PUT /api/v1/user/<id>

## Controller

Now that configure routes, the `home_controller.py` file must contain the `HomeController` class, registering the `action`, e.g:
Now that configure routes, the `home_controller.py` file must contain the `HomeController` class, registering the `action`, e.g:

```python
from flask import render_template
Expand All @@ -177,10 +175,10 @@ class HomeController:

The previous example describes the `hi(self)` will be called every times that the visitors access the controller.

## PUT / DELETE
## PUT / PATCH / DELETE ...

we know that the HTML form doesn't send payload to `action` with `put` or `delete` method as attribute of `form tag`. But,
the `FLASK MVC` does the work for you, everything you need is add the `{{ mvc_form }} tag in HTML template. Look:
the `FLASK MVC` does the work for you, everything you need is add the tag in HTML template. Look:


```python
Expand All @@ -198,22 +196,21 @@ class MessagesController:
```


```html
```jinja
<!-- app/views/messages/edit.html -->
{% block content %}
<form action="{{ url_for('messages.update', id=1) }}" method="POST">
<input type="hidden" name="_method" value="PUT">
<input type="text" name="title" id="title" value="Yeahh!">
<form action='{{ url_for("messages.update", id=1) }}' method="put">
<textarea name="message"></textarea>
<input type="submit" value="update" />
<input type="submit" value="send">
</form>

{{ mvc_form }}

{% endblock %}

```

The `<input type="hidden" name="_method" value="PUT">` is necessary to work sucessfully!

## Views

Flask use the `templates` directory by default to store `HTMLs` files. However, using the `mvc-flask` the default becomes `views`. You can use the `app/views` directory to stores templates.
Expand Down
7 changes: 5 additions & 2 deletions mvc_flask/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
from flask.blueprints import Blueprint

from .router import Router
from .middleware.spoofing import SpooferMiddleware, CustomRequest
from .middleware.http_method_override import (
HTTPMethodOverrideMiddleware,
CustomRequest,
)


class FlaskMVC:
Expand All @@ -18,7 +21,7 @@ def init_app(self, app: Flask = None, path="app"):

app.template_folder = "views"
app.request_class = CustomRequest
app.wsgi_app = SpooferMiddleware(app.wsgi_app)
app.wsgi_app = HTTPMethodOverrideMiddleware(app.wsgi_app)

self.register_blueprint(app)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,7 @@
from werkzeug.formparser import parse_form_data


class InputProcessed:
def read(self, *args):
raise EOFError(
'The wsgi.input stream has already been consumed, check environ["wsgi._post_form"] \
and environ["wsgi._post_files"] for previously processed form data.'
)

readline = readlines = __iter__ = read


class SpooferMiddleware:
class HTTPMethodOverrideMiddleware:
def __init__(self, app, input_name="_method"):
self.app = app
self.input_name = input_name
Expand All @@ -21,13 +11,10 @@ def __call__(self, environ, start_response):
if environ["REQUEST_METHOD"].upper() == "POST":
stream, form, files = parse_form_data(environ)

environ["wsgi.input"] = InputProcessed()

environ["wsgi._post_form"] = form
environ["wsgi._post_files"] = files

method = form.get(self.input_name)
if method:
environ["wsgi._post_form"] = form
environ["wsgi._post_files"] = files
environ["REQUEST_METHOD"] = method
return self.app(environ, start_response)

Expand Down
6 changes: 5 additions & 1 deletion tests/app/controllers/messages_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ def new(self):
return {}, 200

def create(self):
return {}, 201
message = Message(title=request.json["title"])
db.session.add(message)
db.session.commit()

return {"title": message.title}, 201

def edit(self, id):
return render_template("messages/edit.html")
Expand Down
25 changes: 24 additions & 1 deletion tests/request_test.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import json

from flask import url_for
from ward import each, test

Expand Down Expand Up @@ -28,12 +30,33 @@ def _(client=client):


@test("should return status 201 for POST (CREATE)", tags=["request"])
def _(client=client, resource=each("messages", "user", "posts")):
def _(client=client, resource=each("user", "posts")):
message = Message(title="Message One")
db.session.add(message)
db.session.commit()

resp = client.post(url_for(f"{resource}.create"))

assert resp.status_code == 201


@test("request create a messages with json", tags=["create"])
def _(client=client):
message = Message(title="Message One")
db.session.add(message)
db.session.commit()

data = {"title": "hello, andrews"}
res = client.post(
url_for("messages.create"),
data=json.dumps(data),
headers={"Content-Type": "application/json"},
)

assert res.status_code == 201
assert res.json["title"] == "hello, andrews"


@test("must update data from form", tags=["request"])
def _(browser=browser):
message = Message(title="Message One")
Expand Down

0 comments on commit 78641a7

Please sign in to comment.