-
Notifications
You must be signed in to change notification settings - Fork 21
feat: CourseKeyField can now be optionally case-sensitive, has default max_length [FC-0117] #426
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
b180195
ad2a7f3
de35180
293058a
1721be1
b7937f7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,7 +9,7 @@ | |
|
|
||
| try: | ||
| from django.core.exceptions import ValidationError | ||
| from django.db.models import CharField | ||
| from django.db.models import CharField, Field | ||
| from django.db.models.lookups import IsNull | ||
| except ImportError: # pragma: no cover | ||
| # Django is unavailable, none of the classes below will work, | ||
|
|
@@ -96,8 +96,9 @@ class OpaqueKeyField(CreatorMixin, CharField): | |
|
|
||
| def __init__(self, *args, **kwargs): | ||
| if self.KEY_CLASS is None: | ||
| raise ValueError('Must specify KEY_CLASS in OpaqueKeyField subclasses') | ||
|
|
||
| raise ValueError('Must specify KEY_CLASS in OpaqueKeyField subclasses') # pragma: no cover | ||
| kwargs.setdefault("max_length", 255) # Default max length for all opaque key fields | ||
| self.case_sensitive = kwargs.pop("case_sensitive", False) # see self.db_parameters() for details | ||
| super().__init__(*args, **kwargs) | ||
|
|
||
| def to_python(self, value): # pylint: disable=missing-function-docstring | ||
|
|
@@ -164,6 +165,38 @@ def run_validators(self, value): | |
|
|
||
| return super().run_validators(value) | ||
|
|
||
| def db_parameters(self, connection): | ||
| """ | ||
| Return database parameters for this field. This adds collation info, to | ||
| make the key field case-sensitive (optionally). | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I keep seeing PRs about adding/fixing postgres support to the platform, so I wonder if it's worth making the case-insensitivity work on postgres too. At the very least, could you add your postgres note from the PR description here?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From my research, getting case-insensitivity to work on PostgreSQL is not possible without a migration to create a case-insensitive collation (once, for the whole database), which we could then use. Since this library has no migrations, I don't think we should do that. I can definitely add the note here though. |
||
| Previously, these fields were case-sensitive on SQLite and | ||
| case-insensitive on MySQL, which was not ideal. Now they are generally | ||
| case-insensitive by default (for backwards compatibility), and | ||
| case-sensitive if case_sensitive=True is specified (recommended!). | ||
| """ | ||
| db_params = Field.db_parameters(self, connection) | ||
|
|
||
| if connection.vendor == "sqlite": | ||
| db_params["collation"] = "BINARY" if self.case_sensitive else "NOCASE" | ||
| elif connection.vendor == "mysql": # pragma: no cover | ||
| db_params["collation"] = "utf8mb4_bin" if self.case_sensitive else "utf8mb4_unicode_ci" | ||
| # We're using utf8mb4_unicode_ci to keep MariaDB compatibility, since their collation support diverges after | ||
| # this. MySQL is now on utf8mb4_0900_ai_ci based on Unicode 9, while MariaDB has uca1400_ai_ci (Unicode 14). | ||
|
|
||
| return db_params | ||
|
|
||
| def deconstruct(self): | ||
| """ | ||
| How to serialize our Field for the migration file. | ||
|
|
||
| Just add our custom "case_sensitive" field if needed. | ||
| """ | ||
| name, path, args, kwargs = super().deconstruct() | ||
| if self.case_sensitive: | ||
| kwargs["case_sensitive"] = True | ||
| return name, path, args, kwargs | ||
|
|
||
|
|
||
| class OpaqueKeyFieldEmptyLookupIsNull(IsNull): | ||
| """ | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.