Created separate from infi MigrationHistory in order to:

1) inherit it from this library models
2) Use some extra functionality
This commit is contained in:
M1ha 2018-12-18 18:28:23 +05:00
parent 0268cc230a
commit d830b74bcb
4 changed files with 65 additions and 23 deletions

View File

@ -20,6 +20,7 @@ DEFAULTS = {
'DATABASE_ROUTER': 'django_clickhouse.routers.DefaultRouter', 'DATABASE_ROUTER': 'django_clickhouse.routers.DefaultRouter',
'STATSD_PREFIX': 'clickhouse', 'STATSD_PREFIX': 'clickhouse',
'MIGRATIONS_PACKAGE': 'clickhouse_migrations', 'MIGRATIONS_PACKAGE': 'clickhouse_migrations',
'MIGRATION_HISTORY_MODEL': 'django_clickhouse.migrations.MigrationHistory',
'MIGRATE_WITH_DEFAULT_DB': True, 'MIGRATE_WITH_DEFAULT_DB': True,
'CELERY_QUEUE': 'celery', 'CELERY_QUEUE': 'celery',
'DEFAULT_DB_ALIAS': 'default' 'DEFAULT_DB_ALIAS': 'default'

View File

@ -24,19 +24,7 @@ class Database(InfiDatabase):
' Use django_clickhouse.migrations module instead.') ' Use django_clickhouse.migrations module instead.')
def _get_applied_migrations(self, migrations_package_name): def _get_applied_migrations(self, migrations_package_name):
# I don't want to create any tables here, so I changed method to work in without table raise NotImplementedError("This method is not supported by django_clickhouse.")
if not self.db_exists:
return []
query = "SELECT module_name from $table WHERE package_name = '%s'" % migrations_package_name
query = self._substitute(query, MigrationHistory)
try:
return set(obj.module_name for obj in self.select(query))
except ServerError as ex:
# Database doesn't exist or table doesn't exist
if ex.code in {81, 60}:
return set()
raise ex
class ConnectionProxy: class ConnectionProxy:

View File

@ -2,11 +2,14 @@
Migrating database Migrating database
""" """
import datetime import datetime
from typing import Optional from typing import Optional, Set
from django.db import DEFAULT_DB_ALIAS as DJANGO_DEFAULT_DB_ALIAS from django.db import DEFAULT_DB_ALIAS as DJANGO_DEFAULT_DB_ALIAS
from django.db.models.signals import post_migrate from django.db.models.signals import post_migrate
from django.dispatch import receiver from django.dispatch import receiver
from infi.clickhouse_orm.database import ServerError
from django_clickhouse.clickhouse_models import ClickHouseModel
from infi.clickhouse_orm.migrations import * from infi.clickhouse_orm.migrations import *
from infi.clickhouse_orm.utils import import_submodules from infi.clickhouse_orm.utils import import_submodules
@ -29,13 +32,13 @@ class Migration:
:return: None :return: None
""" """
db_router = lazy_class_import(config.DATABASE_ROUTER)() db_router = lazy_class_import(config.DATABASE_ROUTER)()
database = database or connections[db_alias]
for op in self.operations: for op in self.operations:
model_class = getattr(op, 'model_class', None) model_class = getattr(op, 'model_class', None)
hints = getattr(op, 'hints', {}) hints = getattr(op, 'hints', {})
if db_router.allow_migrate(db_alias, self.__module__, op, model=model_class, **hints): if db_router.allow_migrate(db_alias, self.__module__, op, model=model_class, **hints):
database = database or connections[db_alias]
op.apply(database) op.apply(database)
@ -62,20 +65,17 @@ def migrate_app(app_label, db_alias, up_to=9999, database=None):
if module_exists(migrations_package): if module_exists(migrations_package):
database = database or connections[db_alias] database = database or connections[db_alias]
applied_migrations = database._get_applied_migrations(migrations_package) applied_migrations = MigrationHistory.get_applied_migrations(db_alias, migrations_package)
modules = import_submodules(migrations_package) modules = import_submodules(migrations_package)
unapplied_migrations = set(modules.keys()) - set(applied_migrations) unapplied_migrations = set(modules.keys()) - applied_migrations
for name in sorted(unapplied_migrations): for name in sorted(unapplied_migrations):
print('Applying ClickHouse migration %s for app %s in database %s' % (name, app_label, db_alias)) print('Applying ClickHouse migration %s for app %s in database %s' % (name, app_label, db_alias))
migration = modules[name].Migration() migration = modules[name].Migration()
migration.apply(db_alias, database=database) migration.apply(db_alias, database=database)
# Ensure that table for migration storing is created migration_history_model = lazy_class_import(config.MIGRATION_HISTORY_MODEL)
database.create_table(MigrationHistory) migration_history_model.set_migration_applied(db_alias, migrations_package, name)
database.insert([
MigrationHistory(package_name=migrations_package, module_name=name, applied=datetime.date.today())
])
if int(name[:4]) >= up_to: if int(name[:4]) >= up_to:
break break
@ -95,3 +95,56 @@ def clickhouse_migrate(sender, **kwargs):
for db_alias in config.DATABASES: for db_alias in config.DATABASES:
migrate_app(app_name, db_alias) migrate_app(app_name, db_alias)
class MigrationHistory(ClickHouseModel):
"""
A model for storing which migrations were already applied to database.
This
"""
db_alias = StringField()
package_name = StringField()
module_name = StringField()
applied = DateField()
engine = MergeTree('applied', ('db_alias', 'package_name', 'module_name'))
@classmethod
def set_migration_applied(cls, db_alias, migrations_package, name): # type: (str, str, str) -> None
"""
Sets migration apply status
:param db_alias: Database alias migration is applied to
:param migrations_package: Package migration is stored in
:param name: Migration name
:return: None
"""
db = cls.get_database(for_write=True)
# Ensure that table for migration storing is created
db.create_table(MigrationHistory)
db.insert([
MigrationHistory(db_alias=db_alias, package_name=migrations_package, module_name=name,
applied=datetime.date.today())
])
@classmethod
def get_applied_migrations(cls, db_alias, migrations_package): # type: (str, str) -> Set[str]
"""
Returns applied migrations names
:param db_alias: Database alias, to check
:param migrations_package: Package name to check
:return: Set of migration names
"""
qs = MigrationHistory.objects.filter(package_name=migrations_package, db_alias=db_alias).only('module_name')
try:
return set(obj.module_name for obj in qs)
except ServerError as ex:
# Database doesn't exist or table doesn't exist
if ex.code in {81, 60}:
return set()
raise ex
@classmethod
def table_name(cls):
return 'django_clickhouse_migrations'

View File

@ -1,5 +1,5 @@
from django.test import TestCase, override_settings from django.test import TestCase, override_settings
from infi.clickhouse_orm.migrations import MigrationHistory from django_clickhouse.migrations import MigrationHistory
from django_clickhouse.database import connections from django_clickhouse.database import connections
from django_clickhouse.migrations import migrate_app from django_clickhouse.migrations import migrate_app