From 25a56dff42246c16e0feba04919b5497233eb0d6 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Tue, 8 Dec 2020 13:05:58 +0100 Subject: [PATCH 1/2] Adds environment seting to select a custom database for devsite Uses django-environ to set a custom database connection for devsite For details, read the comments with the 'DATABASES' setting in devsite/settings.py This does not change `test_settings.py`, which uses SQLite for unit tests --- devsite/.env.example | 7 +++++++ devsite/devsite/settings.py | 25 +++++++++++++------------ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/devsite/.env.example b/devsite/.env.example index ea6154dd..9a381bfc 100644 --- a/devsite/.env.example +++ b/devsite/.env.example @@ -5,6 +5,13 @@ # Django development debug mode DEBUG=true +# Set a database to use with devsite +# The default database is SQLite and assigned in devsite/settings.py +# Use this specific string if you want to run Figures with MySQL Docker +# For more details, read the django-environ README +# https://github.com/joke2k/django-environ/blob/v0.4.5/README.rst +DATABASE_URL=mysql://figures_user:drowssap-ekaf@127.0.0.1:3306/figures-db + # Set which expected Open edX release mocks for devsite to use. # Valid options are: "GINKGO", "HAWTHORN", "JUNIPER" # diff --git a/devsite/devsite/settings.py b/devsite/devsite/settings.py index 08b538f8..1f0e7a43 100644 --- a/devsite/devsite/settings.py +++ b/devsite/devsite/settings.py @@ -160,20 +160,21 @@ WSGI_APPLICATION = 'devsite.wsgi.application' -# Database -# https://docs.djangoproject.com/en/1.8/ref/settings/#databases + +# Database setting +# To select a different database, such as MySQL, add the database url string to +# as 'DATABASE_URL=' in the devsite/.env file +# +# Refs: +# https://docs.djangoproject.com/en/1.8/ref/settings/#databases +# https://github.com/joke2k/django-environ/tree/v0.4.5 + +DEFAULT_SQLITE_DB_URL = os.path.join(DEVSITE_BASE_DIR, + 'figures-{release}-db.sqlite3'.format( + release=OPENEDX_RELEASE.lower())) DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': os.path.join(DEVSITE_BASE_DIR, - 'figures-{release}-db.sqlite3'.format( - release=OPENEDX_RELEASE.lower())), - 'USER': '', - 'PASSWORD': '', - 'HOST': '', - 'PORT': '', - } + 'default': env.db(default=DEFAULT_SQLITE_DB_URL) } LOCALE_PATHS = [ From 23fc12a131cf655ca85c6201d2c237a9423c1f7a Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Tue, 8 Dec 2020 10:57:57 +0100 Subject: [PATCH 2/2] Add db indexes to SiteDailyMetrics and CourseDailyMetrics This commit adds an index to the SiteDailyMetrics field: 'date_for' This commit adds indexes to the CourseDailyMetrics fields: 'course_id' and 'date_for' This commit adds a new migration, '0014' to perform non-atomic separate state and database migration actions. Included is compatibility functionality so that the migration works for both MySQL and SQLite. --- .../0014_add_indexes_to_daily_metrics.py | 76 +++++++++++++++++++ figures/models.py | 6 +- 2 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 figures/migrations/0014_add_indexes_to_daily_metrics.py diff --git a/figures/migrations/0014_add_indexes_to_daily_metrics.py b/figures/migrations/0014_add_indexes_to_daily_metrics.py new file mode 100644 index 00000000..3ffefd43 --- /dev/null +++ b/figures/migrations/0014_add_indexes_to_daily_metrics.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.29 on 2020-12-08 09:30 +""" +Hand edited to run separate database and state migrations to add indexes to +SiteDailyMetrics and CourseDailyMetrics +""" +from __future__ import unicode_literals + +from django.db import migrations, models +from django.db import connection + + +def compat_drop_index(index, table): + """Compatibility function to drop a database index + + Because MySQL requires the table name in the drop statement and SQLite + fails if the `ON table_name` is provided + """ + if connection.vendor == 'mysql': + return 'DROP INDEX {index} ON {table}'.format(index=index, table=table) + else: + return 'DROP INDEX {index}'.format(index=index) + + +class Migration(migrations.Migration): + + atomic = False + + dependencies = [ + ('figures', '0013_add_indexes_to_lcgm_date_for_and_course_id'), + ] + + operations = [ + + migrations.SeparateDatabaseAndState( + state_operations=[ + migrations.AlterField( + model_name='coursedailymetrics', + name='course_id', + field=models.CharField(db_index=True, max_length=255), + ), + migrations.AlterField( + model_name='coursedailymetrics', + name='date_for', + field=models.DateField(db_index=True), + ), + migrations.AlterField( + model_name='sitedailymetrics', + name='date_for', + field=models.DateField(db_index=True), + ), + ], + database_operations=[ + migrations.RunSQL(sql=""" + CREATE INDEX figures_coursedailymetrics_course_id_f7047b32 + ON figures_coursedailymetrics (course_id); + """, reverse_sql=compat_drop_index( + index='figures_coursedailymetrics_course_id_f7047b32', + table='figures_coursedailymetrics')), + migrations.RunSQL(sql=""" + CREATE INDEX figures_coursedailymetrics_date_for_481b5758 + ON figures_coursedailymetrics (date_for); + """, reverse_sql=compat_drop_index( + index='figures_coursedailymetrics_date_for_481b5758', + table='figures_coursedailymetrics')), + migrations.RunSQL(sql=""" + CREATE INDEX figures_sitedailymetrics_date_for_4d95be72 + ON figures_sitedailymetrics (date_for); + """, reverse_sql=compat_drop_index( + index='figures_sitedailymetrics_date_for_4d95be72', + table='figures_sitedailymetrics') + ) + ] + ) + + ] diff --git a/figures/models.py b/figures/models.py index cf39d076..1d874f4e 100644 --- a/figures/models.py +++ b/figures/models.py @@ -36,13 +36,13 @@ class CourseDailyMetrics(TimeStampedModel): """ # TODO: Review the most appropriate on_delete behaviour site = models.ForeignKey(Site, on_delete=models.CASCADE) - date_for = models.DateField() + date_for = models.DateField(db_index=True) # Leaving as a simple string for initial development # TODO: Follow on to decide if we want to make this an FK to # the CourseOverview model or have the course_id be a # CourseKeyField - course_id = models.CharField(max_length=255) + course_id = models.CharField(max_length=255, db_index=True) enrollment_count = models.IntegerField() active_learners_today = models.IntegerField() # Do we want cumulative average progress for the month? @@ -99,7 +99,7 @@ class SiteDailyMetrics(TimeStampedModel): # TODO: Review the most appropriate on_delete behaviour site = models.ForeignKey(Site, on_delete=models.CASCADE) # Date for which this record's data are collected - date_for = models.DateField() + date_for = models.DateField(db_index=True) # Under review for deletion cumulative_active_user_count = models.IntegerField(blank=True, null=True)