Skip to content

Commit

Permalink
chore(pyproject.toml): add flask-sqlalchemy as a development dependen…
Browse files Browse the repository at this point in the history
…cy to enable SQLAlchemy integration with Flask

chore(plugins): remove unused plugins

The plugins `__init__.py` and `form.py` were removed as they were no longer being used in the project. These plugins were responsible for registering and creating a form plugin for working with PUT and DELETE HTTP methods. However, they were not being utilized and were therefore removed to improve code cleanliness and reduce unnecessary dependencies.

chore(tests): remove unused test data

The file `storage.py` in the `tests/app/db` directory was removed as it contained unused test data. The data variable `[1, 2, 3]` was no longer needed for testing purposes and was therefore removed to improve code cleanliness and reduce unnecessary files.

feat(app): add support for SQLite database using SQLAlchemy

feat(messages_controller): add functionality to retrieve and display a message from the database

feat(messages_controller): add functionality to update a message in the database

feat(message.py): create Message model with id and title columns

feat(messages/edit.html): update form method to POST and add hidden input for PUT method override

feat(messages/index.html): create template to display message title

feat(fixtures.py): create and drop database tables before and after each test

fix(request_test.py): update test to use Message model and assert updated message title

fix(__init__.py): remove unused imports and variables to improve code cleanliness and readability
feat(__init__.py): add support for custom request class and spoofer middleware to handle spoofed HTTP methods
feat(spoofing.py): add middleware for spoofing HTTP methods and custom request class to handle spoofed form data

fix(format): change objects from single quotes to double quotes for consistency

docs(README.md): update
  • Loading branch information
marcuxyz committed Nov 9, 2023
1 parent f01682a commit 8f3b4ce
Show file tree
Hide file tree
Showing 15 changed files with 300 additions and 97 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
10 changes: 7 additions & 3 deletions mvc_flask/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
from importlib import import_module

from flask import Flask, render_template, request
from flask import Flask
from flask.blueprints import Blueprint
from mvc_flask import plugins

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


class FlaskMVC:
Expand All @@ -17,9 +20,10 @@ def init_app(self, app: Flask = None, path="app"):
self.path = path

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

self.register_blueprint(app)
plugins.register(app)

def register_blueprint(self, app: Flask):
# load routes defined from users
Expand Down
33 changes: 33 additions & 0 deletions mvc_flask/middleware/http_method_override.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from flask import Request
from werkzeug.formparser import parse_form_data


class HTTPMethodOverrideMiddleware:
def __init__(self, app, input_name="_method"):
self.app = app
self.input_name = input_name

def __call__(self, environ, start_response):
if environ["REQUEST_METHOD"].upper() == "POST":
stream, form, files = parse_form_data(environ)

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)


class CustomRequest(Request):
@property
def form(self):
if "wsgi._post_form" in self.environ:
return self.environ["wsgi._post_form"]
return super().form

@property
def files(self):
if "wsgi._post_files" in self.environ:
return self.environ["wsgi._post_files"]
return super().files
9 changes: 0 additions & 9 deletions mvc_flask/plugins/__init__.py

This file was deleted.

40 changes: 0 additions & 40 deletions mvc_flask/plugins/form.py

This file was deleted.

Loading

0 comments on commit 8f3b4ce

Please sign in to comment.