Today’s article is all about cookiecutter. If you are a Python fanatic, you might’ve already heard of cookiecutter and possibly even have used it. It is a command-line tool that allows you to create boilerplate application code with a few simple steps.
This article was originally posted at: https://www.quod.ai/post/how-to-structure-your-flask-apps-using-cookiecutter
We will see how we can use cookiecutter to create a demo flask project and go through some of the important concepts present in the cookiecutter flask project. The topics we will cover today are listed below.
● Installing cookiecutter and setting up the project
● Flask-SQLAlchemy with a basic User model
● Easy database migrations with Flask-Migrate
● pytest and Factory-Boy for testing
● Configuration using environment variables
Installing cookiecutter and setting up the project
Installing cookiecutter is the easiest thing that you can do. Just run over to your command line and use the following command.
pip install cookiecutter
This will install cookiecutter in your system. Today, we are going to take a look at a sample flask-restful project. For importing this to your system, you can use the following command from the command line:
cookiecutter https://github.com/QuodAI/tutorial-cookiecutter-flask-restful.git
This will set up the basic project in your system. The folder will be stored under the path:
/users/your_user/.cookiecutters
Now, run the following command to install all the required dependencies.
pip install -r requirements.txt
There you have it, your basic flask-restful project is set up and ready to be used. Now, we will go through some of the important concepts that are detailed within that project. Below we have the file structure of the cookiecutter project. The ones that have been highlighted are the main directories that we will be looking at, but some of the others would also be linked internally.
Flask-SQLAlchemy with a basic User model
The flask-sqlalchemy library adds sqlalchemy support for your flask application. SQLAlchemy is a very popular ORM (Object Relational Mapper) that allows you to integrate the SQL capabilities into your application.
Below, we have a very simple User model that is created using Flask-SQLAlchemy.
from sqlalchemy.ext.hybrid import hybrid_property
from tutorial-cookiecutter-restful.extensions import db, pwd_context
class User(db.Model):
"""Basic user model"""
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(80), unique=True, nullable=False)
_password = db.Column("password", db.String(255), nullable=False)
active = db.Column(db.Boolean, default=True)
@hybrid_property
def password(self):
return self._password
@password.setter
def password(self, value):
self._password = pwd_context.hash(value)
def __repr__(self):
return "" % self.username
View user.py in context at Quod AI
Line 1-2: We import the hybrid-property from SQLAlchemy and the db and pwd_context from our extensions. The hybrid property depicts that a particular value would have different behaviors based on the context.
Line 3: This is a class we are going to create and we pass the db.Model base class to it. This base class instance is created when we initialize SQLAlchemy.
Line 5-9: These lines are used to declare the columns and their properties. We have 5 columns in the table, namely id, username, email, password, and active. The db.Column class is used to denote a column and the other classes denote datatypes. The unique property denotes that it will be a unique value and the nullable property denotes that it cannot be set to null or not depending on the boolean.
Line 10-17: We have a getter for the password that returns the password and we also have a setter that takes in the value and generates a hashed version of it using pwd_context import from extensions. This uses an SHA-256 to generate a hashed value. The last method is a general method that is used to represent the value of the particular type, in our case a user, with a simple string.
Easy database migrations with Flask-Migrate
Flask-Migrate is a flask extension that allows for easy db migrations through SQLAlchemy. To set up Flask-Migrate and start using it, we can follow the below code snippet.
def configure_extensions(app):
"""configure flask extensions"""
db.init_app(app)
jwt.init_app(app)
migrate.init_app(app, db)
View migrate_config.py in context with Quod AI
Line 1-5: The above code snippet shows how we can configure db migrations with Flask-Migrate. We are assuming that the app is already created in this case and passed as an argument to this function. It will initialize an SQLAlchemy instance passing the app as an argument. This db instance will be used for the migrations by calling the init_app function present inside Flask-Migrate passing in the app instance and the db instance we created earlier.
PyTest and Factory-Boy for Testing
Factory-Boy and PyTest are used in conjunction for testing. Factory-Boy is basically a library that allows you to get an instance of a particular class. It contains a model attribute under a Meta class that describes for which class the factory is being created. Below is the creation of a factory for the User class.
import factory
from tutorial-cookiecutter-restful.models import User
class UserFactory(factory.Factory):
username = factory.Sequence(lambda n: "user%d" % n)
email = factory.Sequence(lambda n: "user%d@mail.com" % n)
password = "mypwd"
class Meta:
model = User
View factories.py in context at Quod AI
Line 1-2: We import the factory library and the User model for which we are creating a factory.
Line 3-6: We create a class called UserFactory and pass in the factory.Factory subclass. Note that the username and email fields have the Sequence class from factory invoked. This is to create unique instances each time with different values of username and email. The password is set to ‘mypwd’.
Line 7-8: We then have a Meta class with the model attribute set to User which finalizes the creation of the UserFactory. This can now be used to get instances of User for testing.
Below, we have the test case for getting all users. To test a test case in Python, we can use the pytest library and use the pytest command from the command line.
def test_get_all_user(client, db, user_factory, admin_headers):
users_url = url_for('api.users')
users = user_factory.create_batch(30)
db.session.add_all(users)
db.session.commit()
rep = client.get(users_url, headers=admin_headers)
assert rep.status_code == 200
results = rep.get_json()
for user in users:
assert any(u["id"] == user.id for u in results["results"])
View test_user.py in context with Quod AI
Line 1: This line declares the function with all the required arguments. Note that we are passing in the user_factory we created earlier.
Line 2-3: We then set the URL to get all the users. Then create a batch of 30 users using Factory-Boy.
Line 4-5: Next step is to all the users to the db session and commits all of the users that we created.
Line 6-10: We then call the get method on the URL created before passing in the admin headers to get a response. If it is 200, the test proceeds further. Next step, we loop through the response and match the user ids with the user ids present inside the users variable we created.
Configuration using environment variables
The project houses a file called .flaskenv that stores all the configuration information needed through environment variables that are accessed within the program.
var server = require("net").createServer();
var io = require("socket.io")(server);
var handleClient = function (socket) {
socket.emit("message", {msg: "Hello World"});
};
io.on("connection", handleClient);
server.listen(4000);
Line 1: This sets up the environment for the flask app.
Line 2: This tells Flask how to load the application. The create_app factory is called that is present within the folder tutorial-cookiecutter-restful.app
Line 3: The SECRET_KEY variable is used to generate the JWT tokens
Line 4: The database URI for the SQLite in-memory database is present here.
Conclusion
That’s it for this one. We have gone through some of the concepts surrounding cookiecutter and how you can structure your next flask-restful app. Happy Coding!
Quod AI is code search and navigation on steroids. We turn git repositories into documentation that developers actually use. Do follow us on Twitter @quod_ai for updates on our product and DEVs community content. Check our app at: beta.quod.ai.