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 03c550f
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 48 deletions.
25 changes: 12 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

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
This real world implementation `FLASK MVC` example: https://github.com/negrosdev/negros.dev

## Installation

Expand Down Expand Up @@ -48,7 +48,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 +150,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 +177,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 +198,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
8 changes: 3 additions & 5 deletions mvc_flask/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
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 +18,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 All @@ -30,9 +30,7 @@ def register_blueprint(self, app: Flask):
controller = route[0]
blueprint = Blueprint(controller, controller)

obj = import_module(
f"{self.path}.controllers.{controller}_controller"
)
obj = import_module(f"{self.path}.controllers.{controller}_controller")
view_func = getattr(obj, f"{controller.title()}Controller")

self.hook.register(view_func, blueprint)
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
12 changes: 3 additions & 9 deletions mvc_flask/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,12 @@ def namespace(name: str):
@staticmethod
def get(path: str, resource: str):
controller, action = resource.split("#")
Router.ROUTES.append(
{controller: Model(["GET"], path, controller, action)}
)
Router.ROUTES.append({controller: Model(["GET"], path, controller, action)})

@staticmethod
def post(path: str, resource: str):
controller, action = resource.split("#")
Router.ROUTES.append(
{controller: Model(["POST"], path, controller, action)}
)
Router.ROUTES.append({controller: Model(["POST"], path, controller, action)})

@staticmethod
def put(path: str, resource: str):
Expand All @@ -49,9 +45,7 @@ def put(path: str, resource: str):
@staticmethod
def delete(path: str, resource: str):
controller, action = resource.split("#")
Router.ROUTES.append(
{controller: Model(["DELETE"], path, controller, action)}
)
Router.ROUTES.append({controller: Model(["DELETE"], path, controller, action)})

@staticmethod
def all(resource: str, only=None, base_path=""):
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
4 changes: 1 addition & 3 deletions tests/routes_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,7 @@ def _(

@test("and view registered endpoints", tags=["routes"])
def _(client=client, resource=each("messages", "user")):
endpoints = [
route.endpoint for route in client.application.url_map.iter_rules()
]
endpoints = [route.endpoint for route in client.application.url_map.iter_rules()]

assert f"{resource}.index" in endpoints
assert f"{resource}.show" in endpoints
Expand Down

0 comments on commit 03c550f

Please sign in to comment.