mirror of
https://github.com/ansible/awx.git
synced 2026-05-08 09:57:35 -02:30
Upgrade to Django 5.2 LTS (#16185)
Upgrade to Django 5.2 LTS with compatibility fixes across fields, migrations, dispatch config, tests, and dev deps. Dependencies: - Upgrade django to 5.2.8 and relax requirements.in to >=5.2,<5.3. - Bump django-debug-toolbar to >=6.0 for compatibility. Backend: - awx/conf/fields.py: switch URL TLD regex to use DomainNameValidator.ul in custom URLField. - awx/main/management/commands/gather_analytics.py: use datetime.timezone.utc for naïve datetime handling. - awx/main/dispatch/config.py: add mock_publish option; avoid DB access for test runs, set default max_workers, and support a noop broker. Migrations (SQLite/Postgres compatibility): - Add awx/main/migrations/_sqlite_helper.py with db-aware AlterIndexTogether/RenameIndex wrappers; consume in 0144_event_partitions.py and 0184_django_indexes.py. - Update 0187_hop_nodes.py to use CheckConstraint(condition=...). - Add 0205_alter_instance_peers_alter_job_hosts_and_more.py adjusting through_fields/relations on instance.peers, job.hosts, and role.ancestors. - _dab_rbac.py: iterate roles with chunk_size=1000 for migration performance. Tests: Include hcp_terraform in default credential types in test_credential.py. --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Alan Rominger <arominge@redhat.com>
This commit is contained in:
@@ -6,7 +6,7 @@ import urllib.parse as urlparse
|
|||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
from django.core.validators import URLValidator, _lazy_re_compile
|
from django.core.validators import URLValidator, DomainNameValidator, _lazy_re_compile
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
# Django REST Framework
|
# Django REST Framework
|
||||||
@@ -160,10 +160,11 @@ class StringListIsolatedPathField(StringListField):
|
|||||||
class URLField(CharField):
|
class URLField(CharField):
|
||||||
# these lines set up a custom regex that allow numbers in the
|
# these lines set up a custom regex that allow numbers in the
|
||||||
# top-level domain
|
# top-level domain
|
||||||
|
|
||||||
tld_re = (
|
tld_re = (
|
||||||
r'\.' # dot
|
r'\.' # dot
|
||||||
r'(?!-)' # can't start with a dash
|
r'(?!-)' # can't start with a dash
|
||||||
r'(?:[a-z' + URLValidator.ul + r'0-9' + '-]{2,63}' # domain label, this line was changed from the original URLValidator
|
r'(?:[a-z' + DomainNameValidator.ul + r'0-9' + '-]{2,63}' # domain label, this line was changed from the original URLValidator
|
||||||
r'|xn--[a-z0-9]{1,59})' # or punycode label
|
r'|xn--[a-z0-9]{1,59})' # or punycode label
|
||||||
r'(?<!-)' # can't end with a dash
|
r'(?<!-)' # can't end with a dash
|
||||||
r'\.?' # may have a trailing dot
|
r'\.?' # may have a trailing dot
|
||||||
|
|||||||
@@ -11,13 +11,22 @@ def get_dispatcherd_config(for_service: bool = False, mock_publish: bool = False
|
|||||||
Parameters:
|
Parameters:
|
||||||
for_service: if True, include dynamic options needed for running the dispatcher service
|
for_service: if True, include dynamic options needed for running the dispatcher service
|
||||||
this will require database access, you should delay evaluation until after app setup
|
this will require database access, you should delay evaluation until after app setup
|
||||||
|
mock_publish: if True, use mock values that don't require database access
|
||||||
|
this is used during tests to avoid database queries during app initialization
|
||||||
"""
|
"""
|
||||||
|
# When mock_publish=True (e.g., during tests), use a default value to avoid
|
||||||
|
# database access in get_auto_max_workers() which queries settings.IS_K8S
|
||||||
|
if mock_publish:
|
||||||
|
max_workers = 20 # Reasonable default for tests
|
||||||
|
else:
|
||||||
|
max_workers = get_auto_max_workers()
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
"version": 2,
|
"version": 2,
|
||||||
"service": {
|
"service": {
|
||||||
"pool_kwargs": {
|
"pool_kwargs": {
|
||||||
"min_workers": settings.JOB_EVENT_WORKERS,
|
"min_workers": settings.JOB_EVENT_WORKERS,
|
||||||
"max_workers": get_auto_max_workers(),
|
"max_workers": max_workers,
|
||||||
},
|
},
|
||||||
"main_kwargs": {"node_id": settings.CLUSTER_HOST_ID},
|
"main_kwargs": {"node_id": settings.CLUSTER_HOST_ID},
|
||||||
"process_manager_cls": "ForkServerManager",
|
"process_manager_cls": "ForkServerManager",
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
|
import datetime
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from awx.main import analytics
|
from awx.main import analytics
|
||||||
from dateutil import parser
|
from dateutil import parser
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
from django.utils import timezone
|
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
@@ -38,10 +38,10 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
since = parser.parse(opt_since) if opt_since else None
|
since = parser.parse(opt_since) if opt_since else None
|
||||||
if since and since.tzinfo is None:
|
if since and since.tzinfo is None:
|
||||||
since = since.replace(tzinfo=timezone.utc)
|
since = since.replace(tzinfo=datetime.timezone.utc)
|
||||||
until = parser.parse(opt_until) if opt_until else None
|
until = parser.parse(opt_until) if opt_until else None
|
||||||
if until and until.tzinfo is None:
|
if until and until.tzinfo is None:
|
||||||
until = until.replace(tzinfo=timezone.utc)
|
until = until.replace(tzinfo=datetime.timezone.utc)
|
||||||
|
|
||||||
if opt_ship and opt_dry_run:
|
if opt_ship and opt_dry_run:
|
||||||
self.logger.error('Both --ship and --dry-run cannot be processed at the same time.')
|
self.logger.error('Both --ship and --dry-run cannot be processed at the same time.')
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ class Migration(migrations.Migration):
|
|||||||
db_index=False, editable=False, on_delete=models.deletion.DO_NOTHING, related_name='system_job_events', to='main.SystemJob'
|
db_index=False, editable=False, on_delete=models.deletion.DO_NOTHING, related_name='system_job_events', to='main.SystemJob'
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterIndexTogether(
|
dbawaremigrations.AlterIndexTogether(
|
||||||
name='adhoccommandevent',
|
name='adhoccommandevent',
|
||||||
index_together={
|
index_together={
|
||||||
('ad_hoc_command', 'job_created', 'event'),
|
('ad_hoc_command', 'job_created', 'event'),
|
||||||
@@ -245,11 +245,11 @@ class Migration(migrations.Migration):
|
|||||||
('ad_hoc_command', 'job_created', 'uuid'),
|
('ad_hoc_command', 'job_created', 'uuid'),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.AlterIndexTogether(
|
dbawaremigrations.AlterIndexTogether(
|
||||||
name='inventoryupdateevent',
|
name='inventoryupdateevent',
|
||||||
index_together={('inventory_update', 'job_created', 'counter'), ('inventory_update', 'job_created', 'uuid')},
|
index_together={('inventory_update', 'job_created', 'counter'), ('inventory_update', 'job_created', 'uuid')},
|
||||||
),
|
),
|
||||||
migrations.AlterIndexTogether(
|
dbawaremigrations.AlterIndexTogether(
|
||||||
name='jobevent',
|
name='jobevent',
|
||||||
index_together={
|
index_together={
|
||||||
('job', 'job_created', 'counter'),
|
('job', 'job_created', 'counter'),
|
||||||
@@ -258,7 +258,7 @@ class Migration(migrations.Migration):
|
|||||||
('job', 'job_created', 'parent_uuid'),
|
('job', 'job_created', 'parent_uuid'),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.AlterIndexTogether(
|
dbawaremigrations.AlterIndexTogether(
|
||||||
name='projectupdateevent',
|
name='projectupdateevent',
|
||||||
index_together={
|
index_together={
|
||||||
('project_update', 'job_created', 'uuid'),
|
('project_update', 'job_created', 'uuid'),
|
||||||
@@ -266,7 +266,7 @@ class Migration(migrations.Migration):
|
|||||||
('project_update', 'job_created', 'counter'),
|
('project_update', 'job_created', 'counter'),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.AlterIndexTogether(
|
dbawaremigrations.AlterIndexTogether(
|
||||||
name='systemjobevent',
|
name='systemjobevent',
|
||||||
index_together={('system_job', 'job_created', 'uuid'), ('system_job', 'job_created', 'counter')},
|
index_together={('system_job', 'job_created', 'uuid'), ('system_job', 'job_created', 'counter')},
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ from django.conf import settings
|
|||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
from ._sqlite_helper import dbawaremigrations
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
dependencies = [
|
dependencies = [
|
||||||
@@ -15,92 +17,92 @@ class Migration(migrations.Migration):
|
|||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.RenameIndex(
|
dbawaremigrations.RenameIndex(
|
||||||
model_name='adhoccommandevent',
|
model_name='adhoccommandevent',
|
||||||
new_name='main_adhocc_ad_hoc__1e4d24_idx',
|
new_name='main_adhocc_ad_hoc__1e4d24_idx',
|
||||||
old_fields=('ad_hoc_command', 'job_created', 'uuid'),
|
old_fields=('ad_hoc_command', 'job_created', 'uuid'),
|
||||||
),
|
),
|
||||||
migrations.RenameIndex(
|
dbawaremigrations.RenameIndex(
|
||||||
model_name='adhoccommandevent',
|
model_name='adhoccommandevent',
|
||||||
new_name='main_adhocc_ad_hoc__e72142_idx',
|
new_name='main_adhocc_ad_hoc__e72142_idx',
|
||||||
old_fields=('ad_hoc_command', 'job_created', 'event'),
|
old_fields=('ad_hoc_command', 'job_created', 'event'),
|
||||||
),
|
),
|
||||||
migrations.RenameIndex(
|
dbawaremigrations.RenameIndex(
|
||||||
model_name='adhoccommandevent',
|
model_name='adhoccommandevent',
|
||||||
new_name='main_adhocc_ad_hoc__a57777_idx',
|
new_name='main_adhocc_ad_hoc__a57777_idx',
|
||||||
old_fields=('ad_hoc_command', 'job_created', 'counter'),
|
old_fields=('ad_hoc_command', 'job_created', 'counter'),
|
||||||
),
|
),
|
||||||
migrations.RenameIndex(
|
dbawaremigrations.RenameIndex(
|
||||||
model_name='inventoryupdateevent',
|
model_name='inventoryupdateevent',
|
||||||
new_name='main_invent_invento_f72b21_idx',
|
new_name='main_invent_invento_f72b21_idx',
|
||||||
old_fields=('inventory_update', 'job_created', 'uuid'),
|
old_fields=('inventory_update', 'job_created', 'uuid'),
|
||||||
),
|
),
|
||||||
migrations.RenameIndex(
|
dbawaremigrations.RenameIndex(
|
||||||
model_name='inventoryupdateevent',
|
model_name='inventoryupdateevent',
|
||||||
new_name='main_invent_invento_364dcb_idx',
|
new_name='main_invent_invento_364dcb_idx',
|
||||||
old_fields=('inventory_update', 'job_created', 'counter'),
|
old_fields=('inventory_update', 'job_created', 'counter'),
|
||||||
),
|
),
|
||||||
migrations.RenameIndex(
|
dbawaremigrations.RenameIndex(
|
||||||
model_name='jobevent',
|
model_name='jobevent',
|
||||||
new_name='main_jobeve_job_id_40a56d_idx',
|
new_name='main_jobeve_job_id_40a56d_idx',
|
||||||
old_fields=('job', 'job_created', 'parent_uuid'),
|
old_fields=('job', 'job_created', 'parent_uuid'),
|
||||||
),
|
),
|
||||||
migrations.RenameIndex(
|
dbawaremigrations.RenameIndex(
|
||||||
model_name='jobevent',
|
model_name='jobevent',
|
||||||
new_name='main_jobeve_job_id_3c4a4a_idx',
|
new_name='main_jobeve_job_id_3c4a4a_idx',
|
||||||
old_fields=('job', 'job_created', 'uuid'),
|
old_fields=('job', 'job_created', 'uuid'),
|
||||||
),
|
),
|
||||||
migrations.RenameIndex(
|
dbawaremigrations.RenameIndex(
|
||||||
model_name='jobevent',
|
model_name='jobevent',
|
||||||
new_name='main_jobeve_job_id_51c382_idx',
|
new_name='main_jobeve_job_id_51c382_idx',
|
||||||
old_fields=('job', 'job_created', 'counter'),
|
old_fields=('job', 'job_created', 'counter'),
|
||||||
),
|
),
|
||||||
migrations.RenameIndex(
|
dbawaremigrations.RenameIndex(
|
||||||
model_name='jobevent',
|
model_name='jobevent',
|
||||||
new_name='main_jobeve_job_id_0ddc6b_idx',
|
new_name='main_jobeve_job_id_0ddc6b_idx',
|
||||||
old_fields=('job', 'job_created', 'event'),
|
old_fields=('job', 'job_created', 'event'),
|
||||||
),
|
),
|
||||||
migrations.RenameIndex(
|
dbawaremigrations.RenameIndex(
|
||||||
model_name='projectupdateevent',
|
model_name='projectupdateevent',
|
||||||
new_name='main_projec_project_449bbd_idx',
|
new_name='main_projec_project_449bbd_idx',
|
||||||
old_fields=('project_update', 'job_created', 'uuid'),
|
old_fields=('project_update', 'job_created', 'uuid'),
|
||||||
),
|
),
|
||||||
migrations.RenameIndex(
|
dbawaremigrations.RenameIndex(
|
||||||
model_name='projectupdateevent',
|
model_name='projectupdateevent',
|
||||||
new_name='main_projec_project_69559a_idx',
|
new_name='main_projec_project_69559a_idx',
|
||||||
old_fields=('project_update', 'job_created', 'counter'),
|
old_fields=('project_update', 'job_created', 'counter'),
|
||||||
),
|
),
|
||||||
migrations.RenameIndex(
|
dbawaremigrations.RenameIndex(
|
||||||
model_name='projectupdateevent',
|
model_name='projectupdateevent',
|
||||||
new_name='main_projec_project_c44b7c_idx',
|
new_name='main_projec_project_c44b7c_idx',
|
||||||
old_fields=('project_update', 'job_created', 'event'),
|
old_fields=('project_update', 'job_created', 'event'),
|
||||||
),
|
),
|
||||||
migrations.RenameIndex(
|
dbawaremigrations.RenameIndex(
|
||||||
model_name='role',
|
model_name='role',
|
||||||
new_name='main_rbac_r_content_979bdd_idx',
|
new_name='main_rbac_r_content_979bdd_idx',
|
||||||
old_fields=('content_type', 'object_id'),
|
old_fields=('content_type', 'object_id'),
|
||||||
),
|
),
|
||||||
migrations.RenameIndex(
|
dbawaremigrations.RenameIndex(
|
||||||
model_name='roleancestorentry',
|
model_name='roleancestorentry',
|
||||||
new_name='main_rbac_r_ancesto_b44606_idx',
|
new_name='main_rbac_r_ancesto_b44606_idx',
|
||||||
old_fields=('ancestor', 'content_type_id', 'role_field'),
|
old_fields=('ancestor', 'content_type_id', 'role_field'),
|
||||||
),
|
),
|
||||||
migrations.RenameIndex(
|
dbawaremigrations.RenameIndex(
|
||||||
model_name='roleancestorentry',
|
model_name='roleancestorentry',
|
||||||
new_name='main_rbac_r_ancesto_22b9f0_idx',
|
new_name='main_rbac_r_ancesto_22b9f0_idx',
|
||||||
old_fields=('ancestor', 'content_type_id', 'object_id'),
|
old_fields=('ancestor', 'content_type_id', 'object_id'),
|
||||||
),
|
),
|
||||||
migrations.RenameIndex(
|
dbawaremigrations.RenameIndex(
|
||||||
model_name='roleancestorentry',
|
model_name='roleancestorentry',
|
||||||
new_name='main_rbac_r_ancesto_c87b87_idx',
|
new_name='main_rbac_r_ancesto_c87b87_idx',
|
||||||
old_fields=('ancestor', 'descendent'),
|
old_fields=('ancestor', 'descendent'),
|
||||||
),
|
),
|
||||||
migrations.RenameIndex(
|
dbawaremigrations.RenameIndex(
|
||||||
model_name='systemjobevent',
|
model_name='systemjobevent',
|
||||||
new_name='main_system_system__e39825_idx',
|
new_name='main_system_system__e39825_idx',
|
||||||
old_fields=('system_job', 'job_created', 'uuid'),
|
old_fields=('system_job', 'job_created', 'uuid'),
|
||||||
),
|
),
|
||||||
migrations.RenameIndex(
|
dbawaremigrations.RenameIndex(
|
||||||
model_name='systemjobevent',
|
model_name='systemjobevent',
|
||||||
new_name='main_system_system__73537a_idx',
|
new_name='main_system_system__73537a_idx',
|
||||||
old_fields=('system_job', 'job_created', 'counter'),
|
old_fields=('system_job', 'job_created', 'counter'),
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ class Migration(migrations.Migration):
|
|||||||
),
|
),
|
||||||
migrations.AddConstraint(
|
migrations.AddConstraint(
|
||||||
model_name='instancelink',
|
model_name='instancelink',
|
||||||
constraint=models.CheckConstraint(check=models.Q(('source', models.F('target')), _negated=True), name='source_and_target_can_not_be_equal'),
|
constraint=models.CheckConstraint(condition=models.Q(('source', models.F('target')), _negated=True), name='source_and_target_can_not_be_equal'),
|
||||||
),
|
),
|
||||||
migrations.RunPython(automatically_peer_from_control_plane),
|
migrations.RunPython(automatically_peer_from_control_plane),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
# Generated by Django 5.2.8 on 2025-11-20 18:39
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('main', '0204_squashed_deletions'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='instance',
|
||||||
|
name='peers',
|
||||||
|
field=models.ManyToManyField(
|
||||||
|
related_name='peers_from', through='main.InstanceLink', through_fields=('source', 'target'), to='main.receptoraddress'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='job',
|
||||||
|
name='hosts',
|
||||||
|
field=models.ManyToManyField(editable=False, related_name='jobs', through='main.JobHostSummary', through_fields=('job', 'host'), to='main.host'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='role',
|
||||||
|
name='ancestors',
|
||||||
|
field=models.ManyToManyField(
|
||||||
|
related_name='descendents', through='main.RoleAncestorEntry', through_fields=('descendent', 'ancestor'), to='main.role'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -194,7 +194,7 @@ def migrate_to_new_rbac(apps, schema_editor):
|
|||||||
# NOTE: this import is expected to break at some point, and then just move the data here
|
# NOTE: this import is expected to break at some point, and then just move the data here
|
||||||
from awx.main.models.rbac import role_descriptions
|
from awx.main.models.rbac import role_descriptions
|
||||||
|
|
||||||
for role in Role.objects.prefetch_related('members', 'parents').iterator():
|
for role in Role.objects.prefetch_related('members', 'parents').iterator(chunk_size=1000):
|
||||||
if role.singleton_name:
|
if role.singleton_name:
|
||||||
continue # only bothering to migrate object roles
|
continue # only bothering to migrate object roles
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,78 @@
|
|||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class AlterIndexTogether(migrations.AlterIndexTogether):
|
||||||
|
"""
|
||||||
|
Database-aware AlterIndexTogether that handles SQLite's missing indexes gracefully.
|
||||||
|
|
||||||
|
In Django 5.2+, SQLite table rewrites (triggered by AlterField operations)
|
||||||
|
can drop multi-column indexes. For SQLite, this catches the ValueError and
|
||||||
|
ignores it when the index doesn't exist. For PostgreSQL, uses standard behavior.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
|
if not schema_editor.connection.vendor.startswith('postgres'):
|
||||||
|
# SQLite-specific handling: ignore missing indexes from table rewrites
|
||||||
|
try:
|
||||||
|
super().database_forwards(app_label, schema_editor, from_state, to_state)
|
||||||
|
except ValueError as exc:
|
||||||
|
if "Found wrong number (0) of constraints" in str(exc) or "Found wrong number (0) of indexes" in str(exc):
|
||||||
|
return
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
# PostgreSQL: standard behavior
|
||||||
|
super().database_forwards(app_label, schema_editor, from_state, to_state)
|
||||||
|
|
||||||
|
def database_backwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
|
if not schema_editor.connection.vendor.startswith('postgres'):
|
||||||
|
# SQLite-specific handling: ignore missing indexes from table rewrites
|
||||||
|
try:
|
||||||
|
super().database_backwards(app_label, schema_editor, from_state, to_state)
|
||||||
|
except ValueError as exc:
|
||||||
|
if "Found wrong number (0) of constraints" in str(exc) or "Found wrong number (0) of indexes" in str(exc):
|
||||||
|
return
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
# PostgreSQL: standard behavior
|
||||||
|
super().database_backwards(app_label, schema_editor, from_state, to_state)
|
||||||
|
|
||||||
|
|
||||||
|
class RenameIndex(migrations.RenameIndex):
|
||||||
|
"""
|
||||||
|
Database-aware RenameIndex that handles SQLite's missing indexes gracefully.
|
||||||
|
|
||||||
|
In Django 5.2+, SQLite table rewrites (triggered by AlterField operations)
|
||||||
|
can drop multi-column indexes. For SQLite, this catches the ValueError and
|
||||||
|
ignores it when the index doesn't exist. For PostgreSQL, uses standard behavior.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def database_forwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
|
if not schema_editor.connection.vendor.startswith('postgres'):
|
||||||
|
# SQLite-specific handling: ignore missing indexes from table rewrites
|
||||||
|
try:
|
||||||
|
super().database_forwards(app_label, schema_editor, from_state, to_state)
|
||||||
|
except ValueError as exc:
|
||||||
|
if "Found wrong number (0) of constraints" in str(exc) or "wrong number (0) of indexes" in str(exc):
|
||||||
|
return
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
# PostgreSQL: standard behavior
|
||||||
|
super().database_forwards(app_label, schema_editor, from_state, to_state)
|
||||||
|
|
||||||
|
def database_backwards(self, app_label, schema_editor, from_state, to_state):
|
||||||
|
if not schema_editor.connection.vendor.startswith('postgres'):
|
||||||
|
# SQLite-specific handling: ignore missing indexes from table rewrites
|
||||||
|
try:
|
||||||
|
super().database_backwards(app_label, schema_editor, from_state, to_state)
|
||||||
|
except ValueError as exc:
|
||||||
|
if "Found wrong number (0) of constraints" in str(exc) or "wrong number (0) of indexes" in str(exc):
|
||||||
|
return
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
# PostgreSQL: standard behavior
|
||||||
|
super().database_backwards(app_label, schema_editor, from_state, to_state)
|
||||||
|
|
||||||
|
|
||||||
class RunSQL(migrations.operations.special.RunSQL):
|
class RunSQL(migrations.operations.special.RunSQL):
|
||||||
"""
|
"""
|
||||||
Bit of a hack here. Django actually wants this decision made in the router
|
Bit of a hack here. Django actually wants this decision made in the router
|
||||||
@@ -56,6 +128,8 @@ class RunPython(migrations.operations.special.RunPython):
|
|||||||
class _sqlitemigrations:
|
class _sqlitemigrations:
|
||||||
RunPython = RunPython
|
RunPython = RunPython
|
||||||
RunSQL = RunSQL
|
RunSQL = RunSQL
|
||||||
|
AlterIndexTogether = AlterIndexTogether
|
||||||
|
RenameIndex = RenameIndex
|
||||||
|
|
||||||
|
|
||||||
dbawaremigrations = _sqlitemigrations()
|
dbawaremigrations = _sqlitemigrations()
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ cryptography
|
|||||||
Cython
|
Cython
|
||||||
daphne
|
daphne
|
||||||
distro
|
distro
|
||||||
django==4.2.26 # CVE-2025-32873
|
django>=5.2,<5.3 # Django 5.2 LTS, allow patch updates
|
||||||
django-cors-headers
|
django-cors-headers
|
||||||
django-crum
|
django-crum
|
||||||
django-extensions
|
django-extensions
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ dispatcherd==2025.5.21
|
|||||||
# via -r /awx_devel/requirements/requirements.in
|
# via -r /awx_devel/requirements/requirements.in
|
||||||
distro==1.9.0
|
distro==1.9.0
|
||||||
# via -r /awx_devel/requirements/requirements.in
|
# via -r /awx_devel/requirements/requirements.in
|
||||||
django==4.2.26
|
django==5.2.8
|
||||||
# via
|
# via
|
||||||
# -r /awx_devel/requirements/requirements.in
|
# -r /awx_devel/requirements/requirements.in
|
||||||
# channels
|
# channels
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
build
|
build
|
||||||
django-debug-toolbar==3.2.4
|
django-debug-toolbar>=6.0 # Django 5.2 compatibility
|
||||||
django-test-migrations
|
django-test-migrations
|
||||||
drf-spectacular>=0.27.0 # Modern OpenAPI 3.0 schema generator
|
drf-spectacular>=0.27.0 # Modern OpenAPI 3.0 schema generator
|
||||||
# pprofile - re-add once https://github.com/vpelletier/pprofile/issues/41 is addressed
|
# pprofile - re-add once https://github.com/vpelletier/pprofile/issues/41 is addressed
|
||||||
@@ -28,4 +28,3 @@ pip>=21.3,<=24.0 # PEP 660 – Editable installs for pyproject.toml based builds
|
|||||||
debugpy
|
debugpy
|
||||||
remote-pdb
|
remote-pdb
|
||||||
sdb
|
sdb
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user