Created
July 27, 2021 08:14
-
-
Save DiKorsch/2dfb47ba31907d9b8f7d7dd8f757685e to your computer and use it in GitHub Desktop.
Minimal example of not working cascaded deleting
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- 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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
flask | |
flask-sqlalchemy | |
flask-migrate | |
SQLAlchemy-serializer |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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