Sharing a models.py file

Nick Rodriguez
4 min readAug 8, 2022

--

Flask API and apscheduler scripts that use one models.py file

Photo by Fahim Muntashir on Unsplash

The purpose of this application is to experiment with a few things:

1. Using apscheduler

2. Using two scripts that share the same model.py file

Other features in this repo:

1. Builds flask API

2. SQLite database

Github Repository: https://github.com/costa-rica/weatherApp02

This article is the result of documenting important details I intend to leverage for a more complicated app that will combine recurring weather as well as other user data. That future application will probably use flask Blueprints. I’m not sure it will scale well but if it does, I’ll try to follow up this post.

Using Apscheduler

apscheduler is a python library that runs reoccurring code. I know it can do more stuff, but I focused on the ‘cron’ trigger. The trigger is the direction for how you want to scheduler to set off.

For example, the cron trigger in this application is set to run on the hour every hour. It runs 1am, 2am, 3am, etc. Also, I could have set the cron trigger to run Every Tuesday at 3pm.

The other trigger that is common is ‘interval’. An example of this trigger is, say, you just want it to run every 15 minutes or 15 seconds.

You might be asking why I didn’t just use an interval to run your job since I just want to run it every hour?

If I used the interval trigger for the job I would have to start the app exactly on the hour. Using the cron trigger the apscheduler knows to execute on the next hour, i.e. when the minutes in a clock are all at zero, regardless when I start the application.

The code for using this library can be simple. Here is a very simple example:

from apscheduler.schedulers.background import BackgroundScheduler
from datetime import datetime
def scheduler_funct():
scheduler = BackgroundScheduler()
job_call_weather = scheduler.add_job(call_weather, ‘cron’, hour = ‘*’, minute = ‘*’, second=’*/15')
scheduler.start()
while True:
pass
def call_weather():
print(f’@Calling weather {datetime.now()}’)
if __name__ == ‘__main__’:
scheduler_funct()

The code above will print to the terminal “@Calling weather {time}”. This is basically what I am using for this application, which I’ve shared the github repo to at the top.

My terminal when I run the apscheduler script above

Sharing models.py file with two independent apps/scripts

This might be a little hacky, but it works. In fact, the stackoverflow post I used to help me with the model sharing got a negative point before I one up’ed it. I welcome anyone’s explanation of what’s wrong here. I will try to use this in a larger app using flask Blueprints… we’ll see how it goes.

The keys here are:

1. Build db in models.py

2. import sess object to each script file as well as the models you’re using

Since I have three tables/models at the top of my non-models.py files I import

from models import sess, Users, Locations, Weather

where sess is my Session() object. When I use flask-sqlahchemy I’m used to importing “db” which is:

from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()

However, when I’m just using sqlalchemy I use:

from sqlalchemy.orm import sessionmaker, Session, relationship
sess = Session()

Where I was doing “db.session.query…”, “db.session.add…”, etc. now I’m doing “sess.query”, “sess.add”, etc.,

Models.py differences

The models.py file has a few notable differences compared to when using the flask-sqlalchemy version but I think the changes a pretty transparent and don’t require a lot of steps to see the analogous code.

The imports are a lot but for the most part they seem to make sense.

from sqlalchemy import create_engine, inspect
from sqlalchemy import Column, Integer, String, Text, Float, DateTime, ForeignKey
from sqlalchemy.ext.declarative import declarative_basefrom sqlalchemy.orm import sessionmaker, Session, relationship

Building the tables/models are similar except there is no “db” object. For example instead of using db.Model as the parent class I am using “Base” which is the declarative_base() callable. In my version this is how I set up a model class:

Base = declarative_base()
class Users(Base):
__tablename__ = ‘users’
id = Column(Integer, primary_key = True)
username = Column(Text)

Column is now its own class from the sqlachemy library whereas before it was an attribute of “db”.

Creating the database can be done in a few places. I have chosen to build it in the models.py file so I don’t have to import “Base” or “engine” to another file. This will run before any other app runs as long as at least one model is imported to that file.

I think the logic is pretty straightforward, since you’ll be importing a model to any file that uses it, Python will execute what is in the models.py file before going on to do anything else with the database data.

Placing this bit of code in the models.py file makes the most sense.

if ‘users’ in inspect(engine).get_table_names():
print(‘db already exists’)
else:
Base.metadata.create_all(engine)
print(‘NEW db created.’

Previously, I had this code in other places like the route of the api and the scheduler.py file. That works fine so if for some reason you want to do that, you’ll just need to import the “Base” and “engine” objects.

--

--

Nick Rodriguez
Nick Rodriguez

Written by Nick Rodriguez

Problem solver, dreamer, pragmatic (as deadlines approach) https://nick-rodriguez.info

No responses yet