Meld is a full-stack framework for Flask that allows you to create dynamic frontends in Flask using Python and the Jinja2 templating engine.
Official Website - Flask-Meld.dev
Project inspiration - Ditch Javascript Frameworks For Pure Python Joy
Join the community on Discord - https://discord.gg/DMgSwwdahN
Meld is a framework for Flask to meld your frontend and backend code. What does that mean? It means you can enjoy writing dynamic user interfaces in pure Python.
Less context switching. No need to write javascript. More fun!
For the sake of example, here is a minimal Flask application to get things running:
from flask import Flask, render_template from flask_meld import Meldapp = Flask(name) app.config['SECRET_KEY'] = 'big!secret'
meld = Meld() meld.init_app(app)
socketio = app.socketio
@app.route('/') def index(): return render_template("base.html")
if name == 'main': socketio.run(app, debug=True)
{% meld_scripts %}to your base html template
This sets up the application and initializes Flask-Meld.
<title>Meld Example</title> <div> <!-- Add the line below to include the necessary meld scripts--> {% meld_scripts %} {% block content %} <!-- Using a component in your template is easy! --> {% meld 'counter' %} {% endblock %} </div> <style> </style>
Components are stored in
meld/componentseither within your application folder or in the base directory of your project.
Components are simple Python classes.
The
countercomponent:
# app/meld/components/counter.pyfrom flask_meld.component import Component
class Counter(Component): count = 0
def add(self): self.count = int(self.count) + 1 def subtract(self): self.count = int(self.count) - 1
Create a component template in
templates/meld/counter.html. By creating a file within the
templates/melddirectory just include
{% meld 'counter' %}where you want the component to load.
Here is an example for counter:
- +
Let's take a look at that template file in more detail.
The buttons use
meld:clickto call the
addor
subtractfunction of the Counter component. The input uses
meld:modelto bind the input to the
countproperty on the Counter component.
Use modifiers to change how Meld handles network requests.
debounce: Delay network requests for an amount of time after a keypress. Used to increase performance and sync when the user has paused typing for an amount of time.
debounce-250will wait 250ms before it syncs with the server. The default is 150ms.
defer: Pass the
searchfield with the next network request. Used to improve performance when realtime databinding is not necessary.
prevent: Use to prevent a default action. The following example uses
deferto delay sending a network request until the form is submitted. Idea of how this can be used: instead of adding a keydown event listener to the input field to capture the press of the
enterkey, a form with
meld:submit.prevent="search"can be used to to invoke a component's
searchfunction instead of the default form handler on form submission. Search
<!-- To get the same functionality without using meld:submit.prevent="search" you
would need to add an event listener for the enter key
<input meld:model.defer="search_text" meld:keydown.Enter="search" type="text" name="name" id="name" placeholder="Search for name">
-->
A big part of creating web applications is using forms. Flask-Meld integrates with Flask-WTF to give you real-time form validation without writing any Javascript.
Define your form with Flask-WTF just as you always do.
# forms.py from flask_wtf import FlaskForm from wtforms import StringField, PasswordField from wtforms.validators import DataRequired, Email, EqualToclass RegistrationForm(FlaskForm): email = StringField('Email', validators=[DataRequired(), Email()]) password = PasswordField('Password', validators=[DataRequired()]) password_confirm = PasswordField('Confirm Password', validators=[DataRequired(), EqualTo('password')])
Use WTForm helpers to create your form in your HTML template.
{{ form.email.label }} {{ form.email }} {{ errors.password | first }}<div> {{ form.password.label }} {{ form.password }} <span> {{ errors.password | first }} </span> </div> <div> {{ form.password_confirm.label }} {{ form.password_confirm }} <span> {{ errors.password_confirm | first }} </span> </div> <div> {{ form.submit }} </div> </form>
Using the WTForm helpers saves you some typing. Alternatively, you can define your HTML form without using the helpers. For example, to make a field use
Make sure thatmeld:model="name_of_field"exists on each field.
# meld/components/register.py from flask_meld import Component from forms import RegistrationFormclass Register(Component): form = RegistrationForm()
To make your form validate as a user types use the
updatedfunction. This will provide the form field and allow you to validate on the fly. Simply call
validateon the field.
# meld/components/register.py from flask_meld import Component from forms import RegistrationFormclass Register(Component): form = RegistrationForm()
def updated(self, field): self.validate(field)
You have options here, you can create a custom method on your component to handle submissions or you can use your regular old Flask routes.
@app.route('/register', methods=['GET', 'POST']) def register(): form = RegistrationForm() if form.validate_on_submit(): # do anything you need with your form data... return redirect(url_for("index")) return render_template("register_page.html")
Pretty simple right? You can use this to create very dynamic user interfaces using pure Python and HTML. We would love to see what you have built using Meld so please share!