Skip to content

Instantly share code, notes, and snippets.

@benjaoming
Last active February 27, 2021 09:30
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save benjaoming/3e5770ffcf029c1e11d9a7f79f2e7f89 to your computer and use it in GitHub Desktop.
Save benjaoming/3e5770ffcf029c1e11d9a7f79f2e7f89 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