2021-12-22 18:03:21 +00:00
|
|
|
"""Adds and removes category relations on the database."""
|
2024-04-15 17:43:22 +00:00
|
|
|
|
2015-05-13 20:08:35 +00:00
|
|
|
from django.apps import apps
|
2022-09-21 14:47:06 +00:00
|
|
|
from django.db import DatabaseError, connection, transaction
|
2022-09-21 15:56:12 +00:00
|
|
|
from django.db.utils import OperationalError, ProgrammingError
|
2015-05-13 20:08:35 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def table_exists(table_name):
|
|
|
|
|
"""
|
2021-12-22 18:03:21 +00:00
|
|
|
Check if a table exists in the database.
|
2015-05-13 20:08:35 +00:00
|
|
|
"""
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def field_exists(app_name, model_name, field_name):
|
|
|
|
|
"""
|
|
|
|
|
Does the FK or M2M table exist in the database already?
|
|
|
|
|
"""
|
|
|
|
|
model = apps.get_model(app_name, model_name)
|
|
|
|
|
table_name = model._meta.db_table
|
|
|
|
|
cursor = connection.cursor()
|
|
|
|
|
field_info = connection.introspection.get_table_description(cursor, table_name)
|
|
|
|
|
field_names = [f.name for f in field_info]
|
2020-03-13 18:55:27 +00:00
|
|
|
|
|
|
|
|
# Return True if the many to many table exists
|
|
|
|
|
field = model._meta.get_field(field_name)
|
2021-12-05 14:34:46 +00:00
|
|
|
if hasattr(field, "m2m_db_table"):
|
2020-03-13 18:55:27 +00:00
|
|
|
m2m_table_name = field.m2m_db_table()
|
2022-09-21 14:47:06 +00:00
|
|
|
try:
|
|
|
|
|
m2m_field_info = connection.introspection.get_table_description(cursor, m2m_table_name)
|
|
|
|
|
except DatabaseError: # Django >= 4.1 throws DatabaseError
|
|
|
|
|
m2m_field_info = []
|
2020-03-13 18:55:27 +00:00
|
|
|
if m2m_field_info:
|
|
|
|
|
return True
|
|
|
|
|
|
2015-05-13 20:08:35 +00:00
|
|
|
return field_name in field_names
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def drop_field(app_name, model_name, field_name):
|
|
|
|
|
"""
|
2021-12-22 18:03:21 +00:00
|
|
|
Drop the given field from the app's model.
|
2015-05-13 20:08:35 +00:00
|
|
|
"""
|
|
|
|
|
app_config = apps.get_app_config(app_name)
|
|
|
|
|
model = app_config.get_model(model_name)
|
|
|
|
|
field = model._meta.get_field(field_name)
|
|
|
|
|
with connection.schema_editor() as schema_editor:
|
|
|
|
|
schema_editor.remove_field(model, field)
|
|
|
|
|
|
|
|
|
|
|
2015-05-13 21:20:58 +00:00
|
|
|
def migrate_app(sender, *args, **kwargs):
|
2015-05-13 20:08:35 +00:00
|
|
|
"""
|
2021-12-22 18:03:21 +00:00
|
|
|
Migrate all models of this app registered.
|
2015-05-13 20:08:35 +00:00
|
|
|
"""
|
|
|
|
|
from .registration import registry
|
2021-12-05 14:34:46 +00:00
|
|
|
|
|
|
|
|
if "app_config" not in kwargs:
|
2015-05-13 21:20:58 +00:00
|
|
|
return
|
2021-12-05 14:34:46 +00:00
|
|
|
app_config = kwargs["app_config"]
|
2015-05-13 20:08:35 +00:00
|
|
|
|
|
|
|
|
app_name = app_config.label
|
|
|
|
|
|
2016-02-10 17:47:30 +00:00
|
|
|
fields = [fld for fld in list(registry._field_registry.keys()) if fld.startswith(app_name)]
|
2015-05-13 20:08:35 +00:00
|
|
|
|
2015-05-29 01:24:48 +00:00
|
|
|
sid = transaction.savepoint()
|
|
|
|
|
for fld in fields:
|
2021-12-05 14:34:46 +00:00
|
|
|
model_name, field_name = fld.split(".")[1:]
|
2015-05-29 01:24:48 +00:00
|
|
|
if field_exists(app_name, model_name, field_name):
|
|
|
|
|
continue
|
|
|
|
|
model = app_config.get_model(model_name)
|
|
|
|
|
try:
|
|
|
|
|
with connection.schema_editor() as schema_editor:
|
|
|
|
|
schema_editor.add_field(model, registry._field_registry[fld])
|
2017-10-13 03:47:22 +00:00
|
|
|
if sid:
|
|
|
|
|
transaction.savepoint_commit(sid)
|
2022-09-21 15:56:12 +00:00
|
|
|
# Django 4.1 with sqlite3 has for some reason started throwing OperationalError
|
|
|
|
|
# instead of ProgrammingError, so we need to catch both.
|
|
|
|
|
except (ProgrammingError, OperationalError):
|
2017-10-13 03:47:22 +00:00
|
|
|
if sid:
|
|
|
|
|
transaction.savepoint_rollback(sid)
|
2015-05-29 01:24:48 +00:00
|
|
|
continue
|