MySQL doesn't like you subquerying on the same table you are trying to update in one query. https://dev.mysql.com/doc/refman/8.0/en/subquery-restrictions.html PROD-1366
73 lines
2.7 KiB
Python
73 lines
2.7 KiB
Python
|
|
|
|
import datetime
|
|
import logging
|
|
|
|
import pytz
|
|
from django.db.models import F, Subquery
|
|
from django.db.models.functions import Greatest
|
|
|
|
from openedx.core.djangoapps.schedules.models import Schedule
|
|
from student.models import CourseEnrollment
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
# TODO: consider using a LoggerAdapter instead of this mixin:
|
|
# https://docs.python.org/2/library/logging.html#logging.LoggerAdapter
|
|
class PrefixedDebugLoggerMixin(object):
|
|
log_prefix = None
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super(PrefixedDebugLoggerMixin, self).__init__(*args, **kwargs)
|
|
if self.log_prefix is None:
|
|
self.log_prefix = self.__class__.__name__
|
|
|
|
def log_debug(self, message, *args, **kwargs):
|
|
"""
|
|
Wrapper around LOG.debug that prefixes the message.
|
|
"""
|
|
LOG.debug(self.log_prefix + ': ' + message, *args, **kwargs)
|
|
|
|
def log_info(self, message, *args, **kwargs):
|
|
"""
|
|
Wrapper around LOG.info that prefixes the message.
|
|
"""
|
|
LOG.info(self.log_prefix + ': ' + message, *args, **kwargs)
|
|
|
|
|
|
def reset_self_paced_schedule(user, course_key, use_availability_date=False):
|
|
"""
|
|
Reset the user's schedule if self-paced.
|
|
|
|
It does not create a new schedule, just resets an existing one.
|
|
This is used, for example, when a user requests it or when an enrollment mode changes.
|
|
|
|
Arguments:
|
|
user (User)
|
|
course_key (CourseKey or str)
|
|
use_availability_date (bool): if False, reset to now, else reset to when user got access to course material
|
|
"""
|
|
schedule = Schedule.objects.filter(
|
|
enrollment__user=user,
|
|
enrollment__course__id=course_key,
|
|
enrollment__course__self_paced=True,
|
|
)
|
|
|
|
if use_availability_date:
|
|
# Query enrollments to find availability date -- very similar to query above, but we can't reuse that query
|
|
# object because mysql doesn't like a subquery of an update to reference the same table being updated.
|
|
# Be careful attempting to remove this logic because you can't reproduce a problem locally -- in my own testing,
|
|
# I could not reproduce in devstack, but it was happening on prod databases. So implementations vary.
|
|
# See https://dev.mysql.com/doc/refman/8.0/en/subquery-restrictions.html
|
|
enrollments = CourseEnrollment.objects.filter(
|
|
user=user,
|
|
course__id=course_key,
|
|
course__self_paced=True,
|
|
).annotate(
|
|
availability=Greatest(F('created'), F('course__start')),
|
|
)
|
|
schedule.update(start_date=Subquery(enrollments.values('availability')[:1]))
|
|
else:
|
|
schedule.update(start_date=datetime.datetime.now(pytz.utc))
|