diff --git a/docs/patterns/index.rst b/docs/patterns/index.rst index f765cd8a..eed8d101 100644 --- a/docs/patterns/index.rst +++ b/docs/patterns/index.rst @@ -22,6 +22,7 @@ collected in the following pages. distribute fabric sqlite3 + mysql sqlalchemy fileuploads caching diff --git a/docs/patterns/mysql.rst b/docs/patterns/mysql.rst new file mode 100644 index 00000000..f19c8a7c --- /dev/null +++ b/docs/patterns/mysql.rst @@ -0,0 +1,317 @@ +Using MySQL with Flask +====================== + +.. currentmodule:: flask_mysqldb + +Flask and MySQL have a nice partnership. With an easy setup, Flask can connect to your MySQL database. Inserting, +updating, deleting, and selecting data from MySQL can all be done in one simple setup. + + +Installation +------------ + +Install and update using `pip `_:: + + $ pip install mysqlclient + $ pip install flask-mysql + +A Minimal Application +--------------------- + +In order to have MySQL integrated with Flask, the flask module needs to be imported with Flask and flask_mysqldb needs +to be imported with MySQL. For the purpose of this document rendor_template, request, redirect, url_for will also be +used from the module flask. Below is a snippet that can be used for this implementation:: + + from flask import Flask, rendor_template, request, redirect, url_for + from flask_mysqldb import MySQL + +To get things up and running, the flask app needs to be setup. Also, the MySQL configuration needs to have the MySQL +credentials. The following is the basic setup that is needed to connect MySQL to Flask. This can be placed at the top +of the routes file that will handle MySQL data and below the modules that are imported. +Be sure to fill in the proper credentials for host, port, user, and password, database name:: + + app = Flask(__name__) + app.config['MYSQL_HOST'] = 'HOST' + app.config['MYSQL_PORT'] = 'PORT' + app.config['MYSQL_USER'] = 'USER' + app.config['MYSQL_PASSWORD'] = 'PASSWORD' + app.config['MYSQL_DB'] = 'DATABASE NAME' + app.config['MYSQL_CURSORCLASS'] = 'DictCursor' + mysql = MySQL(app) + +It is recommended that you set app.config['MYSQL_CURSORCLASS'] = 'DictCursor' to easily parse form data passed to Flask. +This makes all incoming form data passed as a dictionary style object. It is very similar to a dictionary but not a true +dictionary. Each field in the form is a key and the input is the value assigned to the key. Also, the information from +database can be passed to HTML templates and easily used in the Jinja syntax. This tutorial assumes DictCursor has been +setup. + +Selecting Database Information and Displaying it +------------------------------------------------ + +To grab data from the database, a cursor needs to be opened and saved to variable name of your choice using +mysql.connection.cursor(). To perform a select statement, place it within .execute(). To pull everything after a +statement execution, the command .fetchall() can be used and saved to a dictionary style variable with name of your +choosing. After the data is saved to a variable, be sure to close the cursor with .close() so the connection is +properly closed. The information pulled from MySQL can be placed within the render_template function in the return +statement. This will send the data to the desired HTML template to be displayed to users. The following snippet shows an +example of MySQL table named Customers and the data being rendered to a page called customers.html. It is also placed +in a function named customers() with the Flask route decoration to page /customers/:: + + @app.route('/customers/', methods=['POST','GET']) + def customers(): + cur = mysql.connection.cursor() + cur.execute("SELECT * FROM customers") + customers = cur.fetchall() + cur.close() + + return render_template('customers.html', customers=customers) + +The MySQL data has now been passed to the customers.html file. In order to display the data, the Jinja syntax is used. +The Jinja syntax is used to parse data from the customers object passed in rendor_tmplate. Below is an example of +how Jinja syntax can be used to display the MySQL data in an html data format:: + + + + + + + + + + + + {% for customer in customers %} + + + + + + + +
Customer IDFirst NameLast NamePhone Number
{{ customer.customer_id }}{{ customer.first_name }}{{ customer.last_name }}{{ customer.phone_number }}
+ +If only certain fields or specific entries need to be pulled, the fields can be placed instead of the * and using the where +clause can filter out unneeded entries. Below is an example of pulling only first_name and last_name where customer_id +is some input saved in cid:: + + cur.execute("SELECT first_name, last_name FROM customers WHERE customer_id = %s", (cid)) + +Creating and Inserting Data into a Database Table +------------------------------------------------- + +Flask can gather data from an HTML form, pass it a to Flask route, and then use MySQL to insert data into a table. +This is where the url_for is used to pass html form data to Flask. Below is an example of a simple form for capturing +data and passing it to a Flask route. The form is using Bootstrap for styling:: + +
+ +
+ +Within the form action, the Jinja syntax {{ url_for('update_customer') }} will pass what is captured in the form to +the route update_customer. Each id in the input will be the key in the dictionary style object that will be used to +insert data into the table. Below is the route and associated function that the information in the form is sent to:: + + @app.route('/add_customer/', methods=['POST', 'GET']) + def add_customer(): + + if request.method == 'POST': + + fname = request.form['fname'] + lname = request.form['lname'] + phone = request.form['phone'] + + cur = mysql.connection.cursor() + cur.execute("INSERT INTO customers (first_name, last_name, phone_number) VALUES (%s, %s, $s)", (fname, lname, phone)) + mysql.connection.commit() + cur.close() + + return redirect(url_for('customers')) + +The above snippet is the route, add_customer, that was used in the action= of the form. As mentioned before, it is +passed in a dictionary type object. Within the add_customer function, the request module is used. The POST method needs +to be checked to make sure the POST was used in the form. Each field is pulled by the id used in the form. In the +snippet, fname = request.form['fname'] will pull the valude form key 'fname' and assign it to a Python variable called +fname. As with the select, a cursor needs to be opened. Once the cursor is opened, the Python variables can be placed +into the execute command. Using **"INSERT INTO customers (first_name, last_name, phone_number) VALUES (%s, %s, $s)", +(fname, lname, phone)** is the same as running **INSERT INTO customers (first_name, last_name, phone_number) VALUES +('John', 'Smith', '8005882300')**. In Python syntax, the variables fname, lname, and phone will be placed in %s. The app need needs +to commit the changes and close the cursor. In the return statement, redirect and url_for will jump back to the customers +function and then the data will be pulled and displayed on the page customers.html page. + +Deleting an Entry from a MySQL Table +------------------------------------ + +Deleting an entry is very simple. A user can select a database entry by the primary key and use Python SQL syntax to +delete the object. Building on the select statement section, a delete option can be implemented for each row. Below, +is an updated version of the HTML table that includes the field for delete:: + + + + + + + + + + + + + {% for customer in customers %} + + + + + + + + +
Customer IDFirst NameLast NamePhone NumberDelete
{{ customer.customer_id }}{{ customer.first_name }}{{ customer.last_name }}{{ customer.phone_number }}Delete Customer
+ +