Merge pull request #13671 from edx/jeskew/move_xmodule_django_to_openedx_core

Move xmodule_django app to openedx.core.djangoapps
This commit is contained in:
John Eskew
2016-10-06 16:53:25 -04:00
committed by GitHub
65 changed files with 144 additions and 139 deletions

View File

@@ -4,7 +4,7 @@ from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
from django.conf import settings
import xmodule_django.models
from openedx.core.djangoapps.xmodule_django.models import CourseKeyField
class Migration(migrations.Migration):
@@ -20,12 +20,12 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('created_time', models.DateTimeField(auto_now_add=True)),
('updated_time', models.DateTimeField(auto_now=True)),
('course_key', xmodule_django.models.CourseKeyField(max_length=255, db_index=True)),
('course_key', CourseKeyField(max_length=255, db_index=True)),
('action', models.CharField(max_length=100, db_index=True)),
('state', models.CharField(max_length=50)),
('should_display', models.BooleanField(default=False)),
('message', models.CharField(max_length=1000)),
('source_course_key', xmodule_django.models.CourseKeyField(max_length=255, db_index=True)),
('source_course_key', CourseKeyField(max_length=255, db_index=True)),
('display_name', models.CharField(default=b'', max_length=255, blank=True)),
('created_user', models.ForeignKey(related_name='created_by_user+', on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, null=True)),
('updated_user', models.ForeignKey(related_name='updated_by_user+', on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, null=True)),

View File

@@ -11,7 +11,7 @@ file and check it in at the same time as your model changes. To do that,
"""
from django.contrib.auth.models import User
from django.db import models
from xmodule_django.models import CourseKeyField
from openedx.core.djangoapps.xmodule_django.models import CourseKeyField
from course_action_state.managers import CourseActionStateManager, CourseRerunUIStateManager

View File

@@ -2,7 +2,7 @@
from __future__ import unicode_literals
from django.db import migrations, models
import xmodule_django.models
from openedx.core.djangoapps.xmodule_django.models import CourseKeyField
class Migration(migrations.Migration):
@@ -15,7 +15,7 @@ class Migration(migrations.Migration):
name='CourseMode',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('course_id', xmodule_django.models.CourseKeyField(max_length=255, verbose_name='Course', db_index=True)),
('course_id', CourseKeyField(max_length=255, verbose_name='Course', db_index=True)),
('mode_slug', models.CharField(max_length=100, verbose_name='Mode')),
('mode_display_name', models.CharField(max_length=255, verbose_name='Display Name')),
('min_price', models.IntegerField(default=0, verbose_name='Price')),
@@ -31,7 +31,7 @@ class Migration(migrations.Migration):
name='CourseModesArchive',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('course_id', xmodule_django.models.CourseKeyField(max_length=255, db_index=True)),
('course_id', CourseKeyField(max_length=255, db_index=True)),
('mode_slug', models.CharField(max_length=100)),
('mode_display_name', models.CharField(max_length=255)),
('min_price', models.IntegerField(default=0)),

View File

@@ -10,7 +10,7 @@ from django.core.exceptions import ValidationError
from django.db import models
from django.db.models import Q
from django.utils.translation import ugettext_lazy as _
from xmodule_django.models import CourseKeyField
from openedx.core.djangoapps.xmodule_django.models import CourseKeyField
Mode = namedtuple('Mode',
[

View File

@@ -3,7 +3,7 @@ from __future__ import unicode_literals
from django.db import migrations, models
from django.conf import settings
import xmodule_django.models
from openedx.core.djangoapps.xmodule_django.models import CourseKeyField
class Migration(migrations.Migration):
@@ -27,7 +27,7 @@ class Migration(migrations.Migration):
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=30)),
('course_id', xmodule_django.models.CourseKeyField(db_index=True, max_length=255, blank=True)),
('course_id', CourseKeyField(db_index=True, max_length=255, blank=True)),
('users', models.ManyToManyField(related_name='roles', to=settings.AUTH_USER_MODEL)),
],
options={

View File

@@ -12,7 +12,7 @@ from student.models import CourseEnrollment
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.exceptions import ItemNotFoundError
from xmodule_django.models import CourseKeyField, NoneToEmptyManager
from openedx.core.djangoapps.xmodule_django.models import CourseKeyField, NoneToEmptyManager
FORUM_ROLE_ADMINISTRATOR = ugettext_noop('Administrator')
FORUM_ROLE_MODERATOR = ugettext_noop('Moderator')

View File

@@ -5,7 +5,7 @@ from django.db import migrations, models
import django_countries.fields
import django.db.models.deletion
from django.conf import settings
import xmodule_django.models
from openedx.core.djangoapps.xmodule_django.models import CourseKeyField
class Migration(migrations.Migration):
@@ -38,7 +38,7 @@ class Migration(migrations.Migration):
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('timestamp', models.DateTimeField(auto_now_add=True, db_index=True)),
('course_key', xmodule_django.models.CourseKeyField(max_length=255, db_index=True)),
('course_key', CourseKeyField(max_length=255, db_index=True)),
('snapshot', models.TextField(null=True, blank=True)),
],
options={
@@ -49,7 +49,7 @@ class Migration(migrations.Migration):
name='EmbargoedCourse',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('course_id', xmodule_django.models.CourseKeyField(unique=True, max_length=255, db_index=True)),
('course_id', CourseKeyField(unique=True, max_length=255, db_index=True)),
('embargoed', models.BooleanField(default=False)),
],
),
@@ -86,7 +86,7 @@ class Migration(migrations.Migration):
name='RestrictedCourse',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('course_key', xmodule_django.models.CourseKeyField(help_text='The course key for the restricted course.', unique=True, max_length=255, db_index=True)),
('course_key', CourseKeyField(help_text='The course key for the restricted course.', unique=True, max_length=255, db_index=True)),
('enroll_msg_key', models.CharField(default=b'default', help_text='The message to show when a user is blocked from enrollment.', max_length=255, choices=[(b'default', b'Default'), (b'embargo', b'Embargo')])),
('access_msg_key', models.CharField(default=b'default', help_text='The message to show when a user is blocked from accessing a course.', max_length=255, choices=[(b'default', b'Default'), (b'embargo', b'Embargo')])),
('disable_access_check', models.BooleanField(default=False, help_text='Allow users who enrolled in an allowed country to access restricted courses from excluded countries.')),

View File

@@ -25,7 +25,7 @@ from django_countries.fields import CountryField
from django_countries import countries
from config_models.models import ConfigurationModel
from xmodule_django.models import CourseKeyField, NoneToEmptyManager
from openedx.core.djangoapps.xmodule_django.models import CourseKeyField, NoneToEmptyManager
from embargo.exceptions import InvalidAccessPoint
from embargo.messages import ENROLL_MESSAGES, COURSEWARE_MESSAGES

View File

@@ -4,7 +4,7 @@ from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
from django.conf import settings
import xmodule_django.models
from openedx.core.djangoapps.xmodule_django.models import CourseKeyField
class Migration(migrations.Migration):
@@ -18,7 +18,7 @@ class Migration(migrations.Migration):
name='CourseMessage',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('course_key', xmodule_django.models.CourseKeyField(db_index=True, max_length=255, blank=True)),
('course_key', CourseKeyField(db_index=True, max_length=255, blank=True)),
('message', models.TextField(null=True, blank=True)),
],
),

View File

@@ -6,7 +6,7 @@ from django.db import models
from django.contrib import admin
from django.core.cache import cache
from xmodule_django.models import CourseKeyField
from openedx.core.djangoapps.xmodule_django.models import CourseKeyField
from config_models.models import ConfigurationModel
from config_models.admin import ConfigurationModelAdmin

View File

@@ -6,7 +6,7 @@ import django.utils.timezone
import django_countries.fields
import django.db.models.deletion
from django.conf import settings
import xmodule_django.models
from openedx.core.djangoapps.xmodule_django.models import CourseKeyField
class Migration(migrations.Migration):
@@ -21,7 +21,7 @@ class Migration(migrations.Migration):
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('anonymous_user_id', models.CharField(unique=True, max_length=32)),
('course_id', xmodule_django.models.CourseKeyField(db_index=True, max_length=255, blank=True)),
('course_id', CourseKeyField(db_index=True, max_length=255, blank=True)),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
],
),
@@ -30,7 +30,7 @@ class Migration(migrations.Migration):
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('org', models.CharField(db_index=True, max_length=64, blank=True)),
('course_id', xmodule_django.models.CourseKeyField(db_index=True, max_length=255, blank=True)),
('course_id', CourseKeyField(db_index=True, max_length=255, blank=True)),
('role', models.CharField(max_length=64, db_index=True)),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
],
@@ -39,7 +39,7 @@ class Migration(migrations.Migration):
name='CourseEnrollment',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('course_id', xmodule_django.models.CourseKeyField(max_length=255, db_index=True)),
('course_id', CourseKeyField(max_length=255, db_index=True)),
('created', models.DateTimeField(db_index=True, auto_now_add=True, null=True)),
('is_active', models.BooleanField(default=True)),
('mode', models.CharField(default=b'honor', max_length=100)),
@@ -54,7 +54,7 @@ class Migration(migrations.Migration):
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('email', models.CharField(max_length=255, db_index=True)),
('course_id', xmodule_django.models.CourseKeyField(max_length=255, db_index=True)),
('course_id', CourseKeyField(max_length=255, db_index=True)),
('auto_enroll', models.BooleanField(default=0)),
('created', models.DateTimeField(db_index=True, auto_now_add=True, null=True)),
],
@@ -101,7 +101,7 @@ class Migration(migrations.Migration):
name='EntranceExamConfiguration',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('course_id', xmodule_django.models.CourseKeyField(max_length=255, db_index=True)),
('course_id', CourseKeyField(max_length=255, db_index=True)),
('created', models.DateTimeField(db_index=True, auto_now_add=True, null=True)),
('updated', models.DateTimeField(auto_now=True, db_index=True)),
('skip_entrance_exam', models.BooleanField(default=True)),
@@ -112,7 +112,7 @@ class Migration(migrations.Migration):
name='HistoricalCourseEnrollment',
fields=[
('id', models.IntegerField(verbose_name='ID', db_index=True, auto_created=True, blank=True)),
('course_id', xmodule_django.models.CourseKeyField(max_length=255, db_index=True)),
('course_id', CourseKeyField(max_length=255, db_index=True)),
('created', models.DateTimeField(db_index=True, null=True, editable=False, blank=True)),
('is_active', models.BooleanField(default=True)),
('mode', models.CharField(default=b'honor', max_length=100)),

View File

@@ -45,7 +45,7 @@ from opaque_keys.edx.keys import CourseKey
from opaque_keys.edx.locations import SlashSeparatedCourseKey
from simple_history.models import HistoricalRecords
from track import contexts
from xmodule_django.models import CourseKeyField, NoneToEmptyManager
from openedx.core.djangoapps.xmodule_django.models import CourseKeyField, NoneToEmptyManager
from lms.djangoapps.badges.utils import badges_enabled
from certificates.models import GeneratedCertificate

View File

@@ -9,7 +9,7 @@ from django.contrib.auth.models import User
import logging
from student.models import CourseAccessRole
from xmodule_django.models import CourseKeyField
from openedx.core.djangoapps.xmodule_django.models import CourseKeyField
log = logging.getLogger(__name__)

View File

@@ -1,197 +0,0 @@
"""
Useful django models for implementing XBlock infrastructure in django.
"""
import warnings
import logging
from django.db import models
from django.core.exceptions import ValidationError
from opaque_keys.edx.keys import CourseKey, UsageKey, BlockTypeKey
log = logging.getLogger(__name__)
class NoneToEmptyManager(models.Manager):
"""
A :class:`django.db.models.Manager` that has a :class:`NoneToEmptyQuerySet`
as its `QuerySet`, initialized with a set of specified `field_names`.
"""
def __init__(self):
"""
Args:
field_names: The list of field names to initialize the :class:`NoneToEmptyQuerySet` with.
"""
super(NoneToEmptyManager, self).__init__()
def get_queryset(self):
"""
Returns the result of NoneToEmptyQuerySet instead of a regular QuerySet.
"""
return NoneToEmptyQuerySet(self.model, using=self._db)
class NoneToEmptyQuerySet(models.query.QuerySet):
"""
A :class:`django.db.query.QuerySet` that replaces `None` values passed to `filter` and `exclude`
with the corresponding `Empty` value for all fields with an `Empty` attribute.
This is to work around Django automatically converting `exact` queries for `None` into
`isnull` queries before the field has a chance to convert them to queries for it's own
empty value.
"""
def _filter_or_exclude(self, *args, **kwargs):
for name in self.model._meta.get_all_field_names():
field_object, _model, direct, _m2m = self.model._meta.get_field_by_name(name)
if direct and hasattr(field_object, 'Empty'):
for suffix in ('', '_exact'):
key = '{}{}'.format(name, suffix)
if key in kwargs and kwargs[key] is None:
kwargs[key] = field_object.Empty
return super(NoneToEmptyQuerySet, self)._filter_or_exclude(*args, **kwargs)
def _strip_object(key):
"""
Strips branch and version info if the given key supports those attributes.
"""
if hasattr(key, 'version_agnostic') and hasattr(key, 'for_branch'):
return key.for_branch(None).version_agnostic()
else:
return key
def _strip_value(value, lookup='exact'):
"""
Helper function to remove the branch and version information from the given value,
which could be a single object or a list.
"""
if lookup == 'in':
stripped_value = [_strip_object(el) for el in value]
else:
stripped_value = _strip_object(value)
return stripped_value
class OpaqueKeyField(models.CharField):
"""
A django field for storing OpaqueKeys.
The baseclass will return the value from the database as a string, rather than an instance
of an OpaqueKey, leaving the application to determine which key subtype to parse the string
as.
Subclasses must specify a KEY_CLASS attribute, in which case the field will use :meth:`from_string`
to parse the key string, and will return an instance of KEY_CLASS.
"""
description = "An OpaqueKey object, saved to the DB in the form of a string."
__metaclass__ = models.SubfieldBase
Empty = object()
KEY_CLASS = None
def __init__(self, *args, **kwargs):
if self.KEY_CLASS is None:
raise ValueError('Must specify KEY_CLASS in OpaqueKeyField subclasses')
super(OpaqueKeyField, self).__init__(*args, **kwargs)
def to_python(self, value):
if value is self.Empty or value is None:
return None
assert isinstance(value, (basestring, self.KEY_CLASS)), \
"%s is not an instance of basestring or %s" % (value, self.KEY_CLASS)
if value == '':
# handle empty string for models being created w/o fields populated
return None
if isinstance(value, basestring):
if value.endswith('\n'):
# An opaque key with a trailing newline has leaked into the DB.
# Log and strip the value.
log.warning(u'{}:{}:{}:to_python: Invalid key: {}. Removing trailing newline.'.format(
self.model._meta.db_table, # pylint: disable=protected-access
self.name,
self.KEY_CLASS.__name__,
repr(value)
))
value = value.rstrip()
return self.KEY_CLASS.from_string(value)
else:
return value
def get_prep_lookup(self, lookup, value):
if lookup == 'isnull':
raise TypeError('Use {0}.Empty rather than None to query for a missing {0}'.format(self.__class__.__name__))
return super(OpaqueKeyField, self).get_prep_lookup(
lookup,
# strip key before comparing
_strip_value(value, lookup)
)
def get_prep_value(self, value):
if value is self.Empty or value is None:
return '' # CharFields should use '' as their empty value, rather than None
assert isinstance(value, self.KEY_CLASS), "%s is not an instance of %s" % (value, self.KEY_CLASS)
serialized_key = unicode(_strip_value(value))
if serialized_key.endswith('\n'):
# An opaque key object serialized to a string with a trailing newline.
# Log the value - but do not modify it.
log.warning(u'{}:{}:{}:get_prep_value: Invalid key: {}.'.format(
self.model._meta.db_table, # pylint: disable=protected-access
self.name,
self.KEY_CLASS.__name__,
repr(serialized_key)
))
return serialized_key
def validate(self, value, model_instance):
"""Validate Empty values, otherwise defer to the parent"""
# raise validation error if the use of this field says it can't be blank but it is
if not self.blank and value is self.Empty:
raise ValidationError(self.error_messages['blank'])
else:
return super(OpaqueKeyField, self).validate(value, model_instance)
def run_validators(self, value):
"""Validate Empty values, otherwise defer to the parent"""
if value is self.Empty:
return
return super(OpaqueKeyField, self).run_validators(value)
class CourseKeyField(OpaqueKeyField):
"""
A django Field that stores a CourseKey object as a string.
"""
description = "A CourseKey object, saved to the DB in the form of a string"
KEY_CLASS = CourseKey
class UsageKeyField(OpaqueKeyField):
"""
A django Field that stores a UsageKey object as a string.
"""
description = "A Location object, saved to the DB in the form of a string"
KEY_CLASS = UsageKey
class LocationKeyField(UsageKeyField):
"""
A django Field that stores a UsageKey object as a string.
"""
def __init__(self, *args, **kwargs):
warnings.warn("LocationKeyField is deprecated. Please use UsageKeyField instead.", stacklevel=2)
super(LocationKeyField, self).__init__(*args, **kwargs)
class BlockTypeKeyField(OpaqueKeyField):
"""
A django Field that stores a BlockTypeKey object as a string.
"""
description = "A BlockTypeKey object, saved to the DB in the form of a string."
KEY_CLASS = BlockTypeKey