Skip to content
Open
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
70bbd68
fix: migrations to make postgresql compatible.
Nov 4, 2024
c222853
fix: duplicate column issue
Nov 4, 2024
fe65206
fix: learning sequences migration for mysql
qasimgulzar Nov 4, 2024
2335e69
fix: mysql specific change
qasimgulzar Nov 4, 2024
4fd6ca0
fix: compile dependencies
Nov 5, 2024
1c4295c
fix: migration issue
Nov 5, 2024
60c4830
fix: broken test
Nov 5, 2024
0a9cd28
fix: using models.BigAutoField instead of custom field.
Nov 18, 2024
00b235a
fix: existing migrations.
Nov 18, 2024
2614432
fix: existing migrations.
Nov 18, 2024
8c21658
fix: mismatched migrations.
Nov 18, 2024
d096773
fix: quality issues
Nov 18, 2024
63875d9
fix: quality issues
Nov 22, 2024
78c2209
Merge branch 'master' into qasim/postgres
e0d Apr 3, 2025
fc80ce2
Merge branch 'master' into qasim/postgres
qasimgulzar Apr 8, 2025
c739e41
Merge remote-tracking branch 'openedx/master' into qasim/postgres
May 4, 2025
c0f0695
Merge branch 'master' into qasim/postgres
qasimgulzar Jul 1, 2025
03b4b00
Merge branch 'master' into qasim/postgres
qasimgulzar Aug 27, 2025
43938ac
Merge branch 'master' into qasim/postgres
qasimgulzar Sep 9, 2025
1f5c9d0
Merge branch 'master' into qasim/postgres
qasimgulzar Sep 11, 2025
499c852
fix: typo
qasimgulzar Sep 15, 2025
558f5ad
Merge branch 'master' into qasim/postgres
qasimgulzar Sep 15, 2025
22dc5f9
fix: accommodated PR feedback
qasimgulzar Sep 29, 2025
139b8a6
Merge branch 'master' into qasim/postgres
qasimgulzar Sep 29, 2025
cdd8403
fix: accommodated PR feedback
qasimgulzar Sep 29, 2025
42f9b3c
fix: putting back `UnsignedBigIntAutoField` to avoid type issue for e…
qasimgulzar Oct 1, 2025
5e73119
Merge branch 'master' into qasim/postgres
qasimgulzar Oct 1, 2025
023e5b0
Merge branch 'master' into qasim/postgres
qasimgulzar Oct 27, 2025
30811ef
fix: register adapters for locators
qasimgulzar Oct 31, 2025
6e11456
Merge branch 'master' into qasim/postgres
qasimgulzar Oct 31, 2025
c44cd5d
Merge branch 'master' into qasim/postgres
qasimgulzar Dec 2, 2025
d4049f3
Merge branch 'master' into qasim/postgres
qasimgulzar Dec 19, 2025
7df2ae2
Merge branch 'master' into qasim/postgres
qasimgulzar Dec 20, 2025
aaa8a71
fix: move models.BigAutoField to UnsignedBigIntAutoField
qasimgulzar Dec 28, 2025
c4f859c
Merge branch 'master' into qasim/postgres
qasimgulzar Dec 28, 2025
edcad98
Merge branch 'master' into qasim/postgres
qasimgulzar Jan 20, 2026
c1c287c
fix: inconsistent dependencies
qasimgulzar Jan 27, 2026
f48ad00
fix: inconsistent dependencies
qasimgulzar Jan 27, 2026
41555c9
Merge branch 'master' into qasim/postgres
qasimgulzar Jan 27, 2026
4ac2812
Merge branch 'master' into qasim/postgres
qasimgulzar Jan 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,15 +1,40 @@
# Generated by Django 2.2.20 on 2021-05-07 18:29, manually modified to make "course_id" column case sensitive

from django.conf import settings
from django.db import migrations, models
from django.db import migrations, models, connection
import django.db.models.deletion
import opaque_keys.edx.django.models
import simple_history.models


def generate_split_module_sql(db_engine):
if 'mysql' in db_engine:
return 'ALTER TABLE split_modulestore_django_splitmodulestorecourseindex MODIFY course_id varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL UNIQUE;'
elif 'postgresql' in db_engine:
return """
ALTER TABLE split_modulestore_django_splitmodulestorecourseindex
ALTER COLUMN course_id TYPE VARCHAR(255),
ALTER COLUMN course_id SET NOT NULL;

ALTER TABLE split_modulestore_django_splitmodulestorecourseindex
ADD CONSTRAINT course_id_unique UNIQUE (course_id);
"""


def generate_split_history_module_sql(db_engine):
if 'mysql' in db_engine:
return 'ALTER TABLE split_modulestore_django_historicalsplitmodulestorecourseindex MODIFY course_id varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL;'
elif 'postgresql' in db_engine:
return """
ALTER TABLE split_modulestore_django_historicalsplitmodulestorecourseindex
ALTER COLUMN course_id TYPE VARCHAR(255),
ALTER COLUMN course_id SET NOT NULL,
ALTER COLUMN course_id SET DATA TYPE VARCHAR(255) COLLATE "C";
"""
class Migration(migrations.Migration):

initial = True
db_engine = connection.settings_dict['ENGINE']

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
Expand Down Expand Up @@ -65,11 +90,11 @@ class Migration(migrations.Migration):
# Custom code: Convert columns to utf8_bin because we want to allow
# case-sensitive comparisons for CourseKeys, which were case-sensitive in MongoDB
migrations.RunSQL(
'ALTER TABLE split_modulestore_django_splitmodulestorecourseindex MODIFY course_id varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL UNIQUE;',
generate_split_module_sql(db_engine),
reverse_sql=migrations.RunSQL.noop,
),
migrations.RunSQL(
'ALTER TABLE split_modulestore_django_historicalsplitmodulestorecourseindex MODIFY course_id varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL;',
generate_split_history_module_sql(db_engine),
reverse_sql=migrations.RunSQL.noop,
),
]
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.auth.models import User
from django.db import migrations, models
from django.db import migrations, models, transaction

USERNAME = settings.ECOMMERCE_SERVICE_WORKER_USERNAME
EMAIL = USERNAME + '@fake.email'

def forwards(apps, schema_editor):
"""Add the service user."""
User = get_user_model()
user, created = User.objects.get_or_create(username=USERNAME, email=EMAIL)
if created:
user.set_unusable_password()
user.save()
with transaction.atomic():
user, created = User.objects.get_or_create(username=USERNAME, email=EMAIL)
if created:
user.set_unusable_password()
user.save()

def backwards(apps, schema_editor):
"""Remove the service user."""
User.objects.get(username=USERNAME, email=EMAIL).delete()
with transaction.atomic():
User.objects.get(username=USERNAME, email=EMAIL).delete()

class Migration(migrations.Migration):

Expand Down
4 changes: 2 additions & 2 deletions lms/djangoapps/courseware/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def db_type(self, connection):
# is an alias for that (https://www.sqlite.org/autoinc.html). An unsigned integer
# isn't an alias for ROWID, so we have to give up on the unsigned part.
return "integer"
elif connection.settings_dict['ENGINE'] == 'django.db.backends.postgresql_psycopg2':
elif "postgresql" in connection.settings_dict['ENGINE']:
# Pg's bigserial is implicitly unsigned (doesn't allow negative numbers) and
# goes 1-9.2x10^18
return "BIGSERIAL"
Expand All @@ -30,7 +30,7 @@ def rel_db_type(self, connection):
return "bigint UNSIGNED"
elif connection.settings_dict['ENGINE'] == 'django.db.backends.sqlite3':
return "integer"
elif connection.settings_dict['ENGINE'] == 'django.db.backends.postgresql_psycopg2':
elif "postgresql" in connection.settings_dict['ENGINE']:
return "BIGSERIAL"
else:
return None
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,5 @@ class Migration(migrations.Migration):
]

operations = [
migrations.RunPython(move_overrides_to_edx_when)
migrations.RunPython(move_overrides_to_edx_when, reverse_code=migrations.RunPython.noop)
]
21 changes: 16 additions & 5 deletions lms/djangoapps/courseware/migrations/0011_csm_id_bigint.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,38 @@
# Generated by Django 1.11.23 on 2019-08-28 15:50


import lms.djangoapps.courseware.fields

from django.conf import settings
from django.db import migrations
from django.db import migrations, models
from django.db.migrations import AlterField

class CsmBigInt(AlterField):
'''
Subclass AlterField migration class to split SQL between two different databases
We can't use the normal AlterField migration operation because Django generate and routes migrations at the model
We can't use the normal AlterField migration operation because Django generates and routes migrations at the model
level and the coursewarehistoryextended_studentmodulehistoryextended table is in a different database
'''
def database_forwards(self, app_label, schema_editor, from_state, to_state):
if hasattr(schema_editor.connection, 'is_in_memory_db') and schema_editor.connection.is_in_memory_db():
# sqlite3 doesn't support 'MODIFY', so skipping during tests
return

to_model = to_state.apps.get_model(app_label, self.model_name)

if schema_editor.connection.alias == 'student_module_history':
if settings.FEATURES["ENABLE_CSMH_EXTENDED"]:
schema_editor.execute("ALTER TABLE `coursewarehistoryextended_studentmodulehistoryextended` MODIFY `student_module_id` bigint UNSIGNED NOT NULL;")
if schema_editor.connection.vendor == 'mysql':
schema_editor.execute("ALTER TABLE `coursewarehistoryextended_studentmodulehistoryextended` MODIFY `student_module_id` bigint UNSIGNED NOT NULL;")
elif schema_editor.connection.vendor == 'postgresql':
schema_editor.execute("ALTER TABLE coursewarehistoryextended_studentmodulehistoryextended ALTER COLUMN student_module_id TYPE bigint;")
elif self.allow_migrate_model(schema_editor.connection.alias, to_model):
schema_editor.execute("ALTER TABLE `courseware_studentmodule` MODIFY `id` bigint UNSIGNED AUTO_INCREMENT NOT NULL;")
if schema_editor.connection.vendor == 'postgresql':
# For PostgreSQL
schema_editor.execute("ALTER TABLE courseware_studentmodule ALTER COLUMN id SET DATA TYPE bigint;")
schema_editor.execute("ALTER TABLE courseware_studentmodule ALTER COLUMN id SET NOT NULL;")
else:
# For MySQL
schema_editor.execute("ALTER TABLE `courseware_studentmodule` MODIFY `id` bigint UNSIGNED AUTO_INCREMENT NOT NULL;")

def database_backwards(self, app_label, schema_editor, from_state, to_state):
# Make backwards migration a no-op, app will still work if column is wider than expected
Expand All @@ -33,6 +43,7 @@ class Migration(migrations.Migration):
dependencies = [
('courseware', '0010_auto_20190709_1559'),
]

if settings.FEATURES["ENABLE_CSMH_EXTENDED"]:
dependencies.append(('coursewarehistoryextended', '0002_force_studentmodule_index'))

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
# Generated by Django 1.11.20 on 2019-06-05 13:59


from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import simple_history.models
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('grades', '0014_persistentsubsectiongradeoverridehistory'),
Expand All @@ -28,15 +27,24 @@ class Migration(migrations.Migration):
('history_id', models.AutoField(primary_key=True, serialize=False)),
('history_date', models.DateTimeField()),
('history_change_reason', models.CharField(max_length=100, null=True)),
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
('grade', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='grades.PersistentSubsectionGrade')),
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
('history_type',
models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
('history_user',
models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+',
to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ('-history_date', '-history_id'),
'get_latest_by': 'history_date',
'verbose_name': 'historical persistent subsection grade override',
},
bases=(simple_history.models.HistoricalChanges, models.Model),
options = {
'ordering': ('-history_date', '-history_id'),
'get_latest_by': 'history_date',
'verbose_name': 'historical persistent subsection grade override',
},
bases = (simple_history.models.HistoricalChanges, models.Model),
),
migrations.AddField(
model_name='historicalpersistentsubsectiongradeoverride',
name='grade',
field=models.ForeignKey(blank=True, db_constraint=False, null=True,
on_delete=django.db.models.deletion.DO_NOTHING, related_name='+',
to='grades.PersistentSubsectionGrade'),
),
]
21 changes: 20 additions & 1 deletion openedx/core/djangoapps/common_initialization/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
Common initialization app for the LMS and CMS
"""


from django.apps import AppConfig
from django.db import connection


class CommonInitializationConfig(AppConfig): # lint-amnesty, pylint: disable=missing-class-docstring
Expand All @@ -14,6 +14,7 @@ def ready(self):
# Common settings validations for the LMS and CMS.
from . import checks # lint-amnesty, pylint: disable=unused-import
self._add_mimetypes()
self._add_required_adapters()

@staticmethod
def _add_mimetypes():
Expand All @@ -26,3 +27,21 @@ def _add_mimetypes():
mimetypes.add_type('application/x-font-opentype', '.otf')
mimetypes.add_type('application/x-font-ttf', '.ttf')
mimetypes.add_type('application/font-woff', '.woff')

@staticmethod
def _add_required_adapters():
"""
Register CourseLocator in psycopg2 extensions
:return:
"""
if 'postgresql' in connection.vendor.lower():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Why is this necessary for course locators and not other opaque key types?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure it is. LibraryLocator at least also seems to require it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AntonOfTheWoods is it breaking for you? Because I have tested it with postgresql 14 and it working fine for me so I have reverted that change from CourseLocator.

Copy link

@AntonOfTheWoods AntonOfTheWoods Oct 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@qasimgulzar It's not working fine for me on PG18 with psycopg3 when I try and import the demo course (manually in a pod, obviously not using tutor). Both are the officially recommended "best" versions for each project, and should be fine for Django.

Django says psycopg3 is the recommended and psycopg2 might be deprecated (soon?).

I had a play around trying to add the adapter where you were doing it but it wasn't getting picked up when running commands (was working fine when running a shell). Mr Sonnet (the 4.5th) suggested using a DB Wrapper instead, and that works. It also seemed like a good way to isolate pg-specific stuff, so I thought why not. It seems to get much further now, though there is still a slight issue trying to import the demo course (the demo library imports fine with that change).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you share the stacktrace

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  File "/openedx/edx-platform/xmodule/modulestore/split_mongo/mongo_connection.py", line 668, in get_course_index
    return SplitModulestoreCourseIndex.objects.get(**query).as_v1_schema()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/django/db/models/manager.py", line 87, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/django/db/models/query.py", line 633, in get
    num = len(clone)
          ^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/django/db/models/query.py", line 380, in __len__
    self._fetch_all()
  File "/openedx/venv/lib/python3.11/site-packages/django/db/models/query.py", line 1881, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/django/db/models/query.py", line 91, in __iter__
    results = compiler.execute_sql(
              ^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/django/db/models/sql/compiler.py", line 1562, in execute_sql
    cursor.execute(sql, params)
  File "/openedx/venv/lib/python3.11/site-packages/django/db/backends/utils.py", line 67, in execute
    return self._execute_with_wrappers(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/django/db/backends/utils.py", line 80, in _execute_with_wrappers
    return executor(sql, params, many, context)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/django/db/backends/utils.py", line 84, in _execute
    with self.db.wrap_database_errors:
  File "/openedx/venv/lib/python3.11/site-packages/django/db/utils.py", line 91, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "/openedx/venv/lib/python3.11/site-packages/django/db/backends/utils.py", line 89, in _execute
    return self.cursor.execute(sql, params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/psycopg/cursor.py", line 97, in execute
    raise ex.with_traceback(None)
django.db.utils.ProgrammingError: cannot adapt type 'LibraryLocator' using placeholder '%t' (format: TEXT)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using this as the engine seems to make that issue go away

from django.db.backends.postgresql import base
import logging

log = logging.getLogger(__name__)


class DatabaseWrapper(base.DatabaseWrapper):
    """
    PostgreSQL database wrapper with OpaqueKey adapter registration.

    This class extends Django's PostgreSQL DatabaseWrapper to automatically
    register psycopg3 adapters for OpaqueKey types when connections are created.
    """

    def get_new_connection(self, conn_params):
        """
        Create a new database connection and register OpaqueKey adapters.

        This method is called by Django whenever a new connection to the database
        needs to be established. We override it to register our custom psycopg3
        adapters after the connection is created.
        """
        connection = super().get_new_connection(conn_params)

        # Register psycopg3 adapters for OpaqueKey types
        self._register_opaque_key_adapters(connection)

        return connection

    def _register_opaque_key_adapters(self, connection):
        """
        Register psycopg3 type adapters for OpaqueKey types on the given connection.

        Args:
            connection: The psycopg3 connection object
        """
        try:
            import psycopg.adapt
            from opaque_keys.edx.keys import OpaqueKey

            class OpaqueKeyDumper(psycopg.adapt.Dumper):
                """
                Psycopg3 dumper for OpaqueKey subclasses.
                Converts opaque keys to their string representation for database storage.
                """

                def dump(self, obj):
                    return str(obj).encode("utf-8")

            # Register the dumper on this connection's adapter map
            if hasattr(connection, "adapters"):
                connection.adapters.register_dumper(OpaqueKey, OpaqueKeyDumper)
                log.debug(
                    f"Registered OpaqueKey dumper on new connection {id(connection)}"
                )
        except ImportError as e:
            # psycopg3 or opaque_keys not installed - this is fine for non-psycopg3 setups
            log.debug(f"Could not register OpaqueKey adapters: {e}")
        except Exception as e:
            # Log but don't fail - the connection should still work for non-OpaqueKey queries
            log.warning(f"Error registering OpaqueKey adapters: {e}", exc_info=True)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AntonOfTheWoods i believe once this PR is merged you can add this wrapper as a separate PR, or even feel free to create PR against this one.

from opaque_keys.edx.locator import CourseLocator, LibraryLocator, BlockUsageLocator
from psycopg2.extensions import QuotedString, register_adapter

def adapt_course_locator(course_locator):
return QuotedString(course_locator._to_string()) # lint-amnesty, pylint: disable=protected-access
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Why does str(course_locator) not work here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QuotedString is meant to wrap the string with double quotes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well it was breaking with postgresql<14 only for CourseLocator as there as special character involved. However now I have tested with postgresql14 and it is even working without this change. I am going to remove this change.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I mean why course_locator._to_string()? But if you're deleting it anyway, it's a moot point.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ormsbee because each locator class contains it's own implementation.
image


# Register the adapter
register_adapter(CourseLocator, adapt_course_locator)
register_adapter(LibraryLocator, adapt_course_locator)
register_adapter(BlockUsageLocator, adapt_course_locator)
Original file line number Diff line number Diff line change
@@ -1,45 +1,42 @@
from django.db import migrations, models, connection

def table_description():
"""Handle Mysql/Pg vs Sqlite"""
# django's mysql/pg introspection.get_table_description tries to select *
# from table and fails during initial migrations from scratch.
# sqlite does not have this failure, so we can use the API.
# For not-sqlite, query information-schema directly with code lifted
# from the internals of django.db.backends.mysql.introspection.py

"""Handle MySQL/Postgres vs SQLite compatibility for table introspection"""
if connection.vendor == 'sqlite':
fields = connection.introspection.get_table_description(connection.cursor(), 'course_overviews_courseoverview')
return [f.name for f in fields]
else:
cursor = connection.cursor()
cursor.execute("""
SELECT column_name
FROM information_schema.columns
WHERE table_name = 'course_overviews_courseoverview' AND table_schema = DATABASE()""")
if connection.vendor == 'mysql':
cursor.execute("""
SELECT column_name
FROM information_schema.columns
WHERE table_name = 'course_overviews_courseoverview' AND table_schema = DATABASE()
""")
elif connection.vendor == 'postgresql':
cursor.execute("""
SELECT column_name
FROM information_schema.columns
WHERE table_name = 'course_overviews_courseoverview' AND table_catalog = current_database()
""")
rows = cursor.fetchall()
return [r[0] for r in rows]


class Migration(migrations.Migration):

dependencies = [
('course_overviews', '0008_remove_courseoverview_facebook_url'),
]

# An original version of 0008 removed the facebook_url field We need to
# handle the case where our noop 0008 ran AND the case where the original
# 0008 ran. We do that by using the standard information_schema to find out
# what columns exist. _meta is unavailable as the column has already been
# removed from the model
operations = []
fields = table_description()

# during a migration from scratch, fields will be empty, but we do not want to add
# an additional facebook_url
# Ensure 'facebook_url' is added if it does not exist in the table
if fields and not any(f == 'facebook_url' for f in fields):
operations += migrations.AddField(
model_name='courseoverview',
name='facebook_url',
field=models.TextField(null=True),
),
operations.append(
migrations.AddField(
model_name='courseoverview',
name='facebook_url',
field=models.TextField(null=True),
)
)
Comment on lines +36 to +42

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is an unrelated bug (even if it's necessary for pg to work), I would put it in a separate, neutral, bugfix PR that should get merged before the new stuff.

From the look of the code, you might argue that there is already pg-specific code and at some point in the past pg probably was supported and that support was never really properly dropped (or there wouldn't be any pg-specific code left). So this whole PR is actually just a bugfix, making pg work properly again. But I'm not sure the maintainers see it this way :-).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am going to take care of it in other PR, as it is not tightly coupled with this change.

Loading
Loading