Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save wsantos/d0d8b6438e5d0c0d6be171fae5c807e0 to your computer and use it in GitHub Desktop.
Save wsantos/d0d8b6438e5d0c0d6be171fae5c807e0 to your computer and use it in GitHub Desktop.
Adds required keyword on_delete to ForeignKey and OneToOneField in Django migrations
#!/usr/bin/python3
"""
This script adds on_delete to Django migrations. It works on multi-line
definitions of ForeignKey/OneToOneField which may be in your codebase if you
have black'ened the migration files.
It's not perfect, but it doesn't create syntax errors and you can run black on
the code again afterwards.
First version:
https://gist.github.com/benjaoming/3e5770ffcf029c1e11d9a7f79f2e7f89
https://stackoverflow.com/questions/41571281/easy-way-to-set-on-delete-across-entire-application
https://stackoverflow.com/questions/11898998/how-can-i-write-a-regex-which-matches-non-greedy
https://stackoverflow.com/questions/15474741/python-regex-optional-capture-group
"""
import re
from pathlib import Path
regex = re.compile(
r"(ForeignKey|OneToOneField)\((\n?\s*([^\)]|\"[^\"]+\")+)(:?[\,\s\n]*)?\)(\,?\n)",
re.MULTILINE,
)
index = 0
for filename in Path(".").glob("**/migrations/*.py"):
print(filename)
contents = open(filename, "r").read()
matches = re.finditer(regex, contents)
for a in matches:
# on_delete is already part of the expression
if "on_delete" in a.group(0):
continue
max_indents = 0
for line in a.group(0).split("\n"):
indents = len(line) - len(line.strip())
max_indents = max(max_indents, indents)
# A in-line expression of kwargs
if len(a.group(0).split("\n")) < 5:
contents = contents.replace(
a.group(0),
"{}({}, on_delete=models.CASCADE\n{}),\n{}".format(
a.group(1),
a.group(2).rstrip(),
" " * (max_indents - 4),
a.group(3) or "",
),
)
continue
contents = contents.replace(
a.group(0),
"{}({} on_delete=models.CASCADE,\n{}),{}\n".format(
a.group(1), a.group(2), " " * (max_indents - 4), a.group(3) or ""
),
)
# This is the match, print it to verify
# print(a.group(0))
open(filename, "w").write(contents)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment