Skip to content

Instantly share code, notes, and snippets.

@DiKorsch
Created July 27, 2021 08:14
Show Gist options
  • Save DiKorsch/2dfb47ba31907d9b8f7d7dd8f757685e to your computer and use it in GitHub Desktop.
Save DiKorsch/2dfb47ba31907d9b8f7d7dd8f757685e to your computer and use it in GitHub Desktop.
Minimal example of not working cascaded deleting
from flask import Flask
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = f"sqlite:///testing.sqlite3"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)
db.session().execute("PRAGMA foreign_keys=ON")
migrate = Migrate(app, db)
import models
import routes
# this is just for testing purposes. uncomment to get a clean DB after each server restart
# db.drop_all()
# db.create_all()
<!-- should be placed under templates/ -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{{msg}}</title>
</head>
<body>
<p>{{msg}}</p>
<form method="post" action="/project">
<input type="submit" value="Create">
<input type="submit" formaction="/delete" value="Delete">
</form>
<h1>Projects</h1>
{% for project in projects %}
<p>{{ project }}</p>
{% endfor %}
<h1>Labels</h1>
{% for label in labels %}
<p>{{ label }}</p>
{% endfor %}
<h1>Files</h1>
{% for file in files %}
<p>{{ file }}</p>
{% endfor %}
<h1>Results</h1>
{% for result in results %}
<p>{{ result }}</p>
{% endfor %}
</body>
</html>
from app import app
from app import db
from datetime import datetime
from sqlalchemy_serializer import SerializerMixin
class BaseModel(db.Model, SerializerMixin):
__abstract__ = True
serialize_only = ("id", "name",)
date_format = '%s' # Unixtimestamp (seconds)
datetime_format = '%d. %b. %Y %H:%M:%S'
time_format = '%H:%M'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False)
def __repr__(self):
attrs = self.to_dict()
content = ", ".join([f"{attr}={value}" for attr, value in attrs.items()])
return f"<{self.__class__.__name__}: {content}>"
def delete(self, commit=True) -> None:
db.session.delete(self)
if commit:
self.commit()
@classmethod
def new(cls, commit=True, **kwargs):
obj = cls(**kwargs)
db.session.add(obj)
if commit:
obj.commit()
return obj
def commit(self):
db.session.commit()
db.session.commit()
class Project(BaseModel):
serialize_only = BaseModel.serialize_only + ("created",)
root_folder = db.Column(db.String)
created = db.Column(db.DateTime, default=datetime.utcnow,
index=True, nullable=False)
# contraints
__table_args__ = ()
files = db.relationship("File",
backref="project",
passive_deletes=True)
labels = db.relationship("Label",
backref="project",
passive_deletes=True)
class Label(BaseModel):
serialize_only = BaseModel.serialize_only + \
("created", "reference", "project_id")
project_id = db.Column(
db.Integer,
db.ForeignKey("project.id", ondelete="CASCADE"),
nullable=False)
created = db.Column(db.DateTime, default=datetime.utcnow,
index=True, nullable=False)
reference = db.Column(db.String)
__table_args__ = (
db.UniqueConstraint('project_id', 'reference'),
)
class File(BaseModel):
serialize_only = BaseModel.serialize_only + \
("path", "project_id")
project_id = db.Column(
db.Integer,
db.ForeignKey("project.id", ondelete="CASCADE"),
nullable=False)
path = db.Column(db.String, nullable=False)
results = db.relationship("Result", backref="file", passive_deletes=True)
class Result(BaseModel):
serialize_only = BaseModel.serialize_only + \
("file_id", "label_id")
file_id = db.Column(
db.Integer,
db.ForeignKey("file.id", ondelete="CASCADE"),
nullable=False)
label_id = db.Column(
db.Integer,
db.ForeignKey("label.id", ondelete="SET NULL"),
nullable=True)
flask
flask-sqlalchemy
flask-migrate
SQLAlchemy-serializer
import random
from app import app
from flask import render_template
from flask import redirect
from models import *
@app.route("/")
def index():
projects = Project.query.all()
labels = Label.query.all()
files = File.query.all()
results = Result.query.all()
return render_template("index.html",
msg="Index",
projects=projects,
labels=labels,
files=files,
results=results,
)
@app.route("/project", methods=["POST"])
def new_project():
project = Project.new(name="Project", root_folder="some_folder")
for n in range(random.randint(1, 10)):
Label.new(name="A label", project_id=project.id, reference=f"Label #{n+1:04d}")
for n in range(random.randint(1, 4)):
file = File.new(name="A file", project_id=project.id, path=f"some_file_{n:04d}.txt")
for n in range(random.randint(1, 3)):
label = random.choice(Label.query.filter_by(project_id=project.id).all())
Result.new(name="A result", file_id=file.id, label_id=label.id)
return redirect("/")
@app.route("/delete", methods=["POST"])
def del_project():
project = Project.query.first()
if project is not None:
project.delete(commit=True)
return redirect("/")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment