This content originally appeared on DEV Community and was authored by Brandon Arreguin
In this tutorial, I’m going to show you how to work with subdomains in your Flask application.
But first …
What is a subdomain?
A subdomain is a simple extension of the main domain; it’s almost like a username, but at the start of this. For example, the most commonly used on the web is www
, where the main website of a product is frequently hosted. Another example of a subdomain is music.apples.com
, where music.
is a subdomain of apple.com
Subdomains in Flask
Flask can work easily with subdomains, and a third-party extension isn’t needed for this. Yay!.
You can do it using Nginx, but Nginx is out of the range of this tutorial.
Preparing the environment
First, we need to create a new Python environment to start working with Flask, and update our hosts local file.
- Create a new folder: mkdir flask-subdomains
- Enter the folder and start a Python virtualenv inside of this.
python -m venv venv
- Activate your virtualenv.
- Make a new file named main.py. Also, the templates folder.
- Open your hosts file and add the domain as follows.
127.0.0.1 superdomain.com
127.0.0.1 admin.superdomain.com
127.0.0.1 user1.superdomain.com
If you don’t know where the hosts file is located. For Linux, go to etc/hosts, and for Windows, run Notepad as administrator, follow the next path
c:\Windows\System32\drivers\etc
, here is the hosts file located on Windows, then change the search filter from Text Files to All Files, and now you can open your hosts file and edit it.
A minimal Flask application
Now, in our main.py
file, let’s create a Flask instance and add some routes.
from flask import Flask, render_template
app = Flask(__name__)
app.config['SERVER_NAME'] = 'superdomain.com:5000'
@app.route('/')
def index():
context = { 'page_title': 'Home' }
return render_template('site/index.html.jinja', **context)
Now we have our environment and our minimal Flask application ready to work with.
Our first subdomain
In our main.py
file, we need to add a new route and set the subdomain
parameter in the decorator
@app.route('/', subdomain='admin')
def admin():
context = { 'page_title': 'Admin Page' }
return render_template('admin/index.html', **context)
The subdomain parameter must match the subdomains defined in the hosts file. Let’s run the server.
flask -A main:app --debug run
Open the browser, and run superdomain.com:5000; now, we can access the main page. If we visit admin.superdomain.com:5000
, we can see the admin page… Wait, there’s a problem.
The admin route is rendering the site template. What’s wrong?
Fixing the problem
In Flask, we need to set one more thing: The subdomain_matching
parameter.
from flask import Flask, render_template
app = Flask(__name__, subdomain_matching=True)
Stop the server, and run it again. This time, we were able to access the subdomain index route.
And… Yay!!! Now, our routes are working well.
Working with Blueprints
Flask has the concept of Blueprints, which lets us make our application modular when we need more flexibility and a better structure for larger projects. The Blueprint object can also set a subdomain without passing it in each new route. This is great if you are building a big application.
Let’s modify our current application.
First, let’s create an app folder. The app folder will contain all the new code, and the main.py
file will serve as our entrypoint.
Inside the app folder add the __init__.py
file and the blueprints folder with the following files: __init__.py
, admin.py
, site.py
, and tenant.py
.
It should look like this:
app
|-blueprints
|-admin.py
|-site.py
|-tenant.py
|-__init__.py
|-__init__.py
main.py
Now, we need to define the blueprints for each module, and set the subdomain parameter, as follows…
# blueprints/admin.py
mod = Blueprint('admin', __name__, subdomain='admin')
@mod.route('/')
def index():
return render_template('admin/index.html.jinja')
# blueprints/site.py
mod = Blueprint('site', __name__)
@mod.route('/')
def index:
return render_template('site/index.html.jinja')
# blueprints/tenant.py
mod = Blueprint('tenant', __name__, subdomain='<string:subdomain>')
@mod.route('/')
def index(subdomain: str):
template_name = 'tenant/index.html.jinja'
return render_template(template_name, subdomain=subdomain)
We set the tenant subdomain to be dynamic and passed it to the index decorated function.
Then, we have to register each blueprint in our main.py
file
from flask import Flask
from app.blueprints import admin, site, tenant
app = Flask(__name__, subdomain_matching=True)
app.config['SERVER_NAME'] = 'superdomain.com:5000'
app.register_blueprint(admin.mod)
app.register_blueprint(site.mod)
app.register_blueprint(tenant.mod)
If we visit the user1.superdomain.com:5000
, we can see the dynamic tenant route working.
Dynamic subdomains could be helpful in some cases, for example, vercel, or the postcard.page site, which allows users to host a site using their domain.
Also, the subdomain allows you to retrieve information from the database related to an organization or user, something like this:
@mod.route('/')
def index(subdomain: str):
tenant = tenants.get_by_subdomain_or_404(subdomain)
all_post = posts.get_all_by_tenant(tenant_id=tenant.id)
return render_template('tenant/index.html.jinja', **{
'tenant': tenant,
'posts': all_posts
})
Conclusion
In this simple tutorial, you learned how to work with subdomains in your Flask application. Remember, this is just at the app level; you’ll need to configure the subdomains in your hosting or domain name providers and use something like Nginx alongside Flask.
I hope you enjoy this post, and thanks for reading. See you next time.
#flask
#webdevelopment
#python
This content originally appeared on DEV Community and was authored by Brandon Arreguin