|
7 | 7 | from django.contrib import admin |
8 | 8 | from django.core.exceptions import ValidationError |
9 | 9 | from django.db import models |
10 | | -from django.db.models.functions import Concat, Length, Lower, Right |
11 | | -from django.db.models.lookups import Exact |
| 10 | +from django.db.models import F |
| 11 | +from django.db.models.functions import Length, Lower, StrIndex |
| 12 | +from django.db.models.lookups import GreaterThan |
12 | 13 | from django.utils.translation import gettext_lazy as _ |
13 | 14 | from opaque_keys import InvalidKeyError |
14 | 15 | from opaque_keys.edx.django.models import CourseKeyField |
@@ -222,11 +223,12 @@ class Meta: |
222 | 223 | models.CheckConstraint( |
223 | 224 | condition=models.Q(display_name__length__gt=0), name="oex_catalog_courserun_display_name_not_blank" |
224 | 225 | ), |
225 | | - # Enforce that the course ID must end with "+run" where "run" is an exact match for the "run" field. |
226 | | - # This check may be removed or changed in the future if our course ID format ever changes |
| 226 | + # Enforce at the DB level that the "run" field value appears in the course ID: |
227 | 227 | models.CheckConstraint( |
228 | | - # Note: EndsWith() on SQLite is always case-insensitive, so we code the constraint like this: |
229 | | - condition=Exact(Right("course_id", Length("run") + 1), Concat(models.Value("+"), "run")), |
| 228 | + condition=GreaterThan(StrIndex("course_id", F("run")), 0), |
| 229 | + # The following check condition (ends with "+run") is even stronger, but doesn't work with CCX keys |
| 230 | + # like "ccx-v1:org+code+run+ccx@1" which we also need to support. |
| 231 | + # condition=Exact(Right("course_id", Length("run") + 1), Concat(models.Value("+"), "run")), |
230 | 232 | name="oex_catalog_courserun_courseid_run_match_exactly", |
231 | 233 | violation_error_message=_("The CourseRun 'run' field should match the run in the course_id key."), |
232 | 234 | ), |
|
0 commit comments