From 78641a7c981524cdb830cd87905d0a83bebacf0d Mon Sep 17 00:00:00 2001 From: Marcus Almeida Date: Wed, 12 Jul 2023 00:53:30 -0300 Subject: [PATCH] docs(README.md): update --- README.md | 25 ++++++++----------- mvc_flask/__init__.py | 7 ++++-- .../{spoofing.py => http_method_override.py} | 19 +++----------- tests/app/controllers/messages_controller.py | 6 ++++- tests/request_test.py | 25 ++++++++++++++++++- 5 files changed, 48 insertions(+), 34 deletions(-) rename mvc_flask/middleware/{spoofing.py => http_method_override.py} (64%) diff --git a/README.md b/README.md index 9dcf4ce..170a8d4 100644 --- a/README.md +++ b/README.md @@ -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`: @@ -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 @@ -150,7 +148,7 @@ user.update PATCH, PUT /api/v1/user/ ## 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 @@ -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 @@ -198,22 +196,21 @@ class MessagesController: ``` -```html +```jinja {% block content %} +
+ + - - - +
- - {{ mvc_form }} - {% endblock %} - ``` +The `` 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. diff --git a/mvc_flask/__init__.py b/mvc_flask/__init__.py index d6d801e..86a5c0f 100644 --- a/mvc_flask/__init__.py +++ b/mvc_flask/__init__.py @@ -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: @@ -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) diff --git a/mvc_flask/middleware/spoofing.py b/mvc_flask/middleware/http_method_override.py similarity index 64% rename from mvc_flask/middleware/spoofing.py rename to mvc_flask/middleware/http_method_override.py index 50b8a29..dfc5844 100644 --- a/mvc_flask/middleware/spoofing.py +++ b/mvc_flask/middleware/http_method_override.py @@ -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 @@ -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) diff --git a/tests/app/controllers/messages_controller.py b/tests/app/controllers/messages_controller.py index 9bf4d3a..316d2a9 100644 --- a/tests/app/controllers/messages_controller.py +++ b/tests/app/controllers/messages_controller.py @@ -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") diff --git a/tests/request_test.py b/tests/request_test.py index 5e01f3c..0f86404 100644 --- a/tests/request_test.py +++ b/tests/request_test.py @@ -1,3 +1,5 @@ +import json + from flask import url_for from ward import each, test @@ -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")