[django-modeltranslation] r149 committed - Added a new management command sync_database_fields to sync the databa...

6 views
Skip to first unread message

django-mode...@googlecode.com

unread,
Jul 11, 2012, 8:57:55 AM7/11/12
to django-modeltra...@googlegroups.com
Revision: 149
Author: eschler
Date: Wed Jul 11 05:57:37 2012
Log: Added a new management command sync_database_fields to sync the
database after a new model has been registered or a new language has been
added. Resolves issue 62 (thanks to Sébastien Fievet and the authors of
django-transmeta).
http://code.google.com/p/django-modeltranslation/source/detail?r=149

Added:
/trunk/modeltranslation/management/commands/sync_translation_fields.py
Modified:
/trunk/AUTHORS.txt
/trunk/CHANGELOG.txt

=======================================
--- /dev/null
+++ /trunk/modeltranslation/management/commands/sync_translation_fields.py
Wed Jul 11 05:57:37 2012
@@ -0,0 +1,137 @@
+# -*- coding: utf-8 -*-
+"""
+Detect new translatable fields in all models and sync database structure.
+
+You will need to execute this command in two cases:
+
+ 1. When you add new languages to settings.LANGUAGES.
+ 2. When you add new translatable fields to your models.
+
+Credits: Heavily inspired by django-transmeta's sync_transmeta_db command.
+"""
+from django.conf import settings
+from django.core.management.base import BaseCommand
+from django.core.management.color import no_style
+from django.db import connection, transaction
+from django.db.models import get_models
+
+from modeltranslation.translator import translator, NotRegistered
+from modeltranslation.utils import build_localized_fieldname
+
+
+def ask_for_confirmation(sql_sentences, model_full_name):
+ print '\nSQL to synchronize "%s" schema:' % model_full_name
+ for sentence in sql_sentences:
+ print ' %s' % sentence
+ while True:
+ prompt = ('\nAre you sure that you want to execute the previous
SQL: '
+ '(y/n) [n]: ')
+ answer = raw_input(prompt).strip()
+ if answer == '':
+ return False
+ elif answer not in ('y', 'n', 'yes', 'no'):
+ print 'Please answer yes or no'
+ elif answer == 'y' or answer == 'yes':
+ return True
+ else:
+ return False
+
+
+def print_missing_langs(missing_langs, field_name, model_name):
+ print 'Missing languages in "%s" field from "%s" model: %s' % (
+ field_name, model_name, ", ".join(missing_langs))
+
+
+class Command(BaseCommand):
+ help = ('Detect new translatable fields or new available languages
and '
+ 'sync database structure')
+
+ def handle(self, *args, **options):
+ """
+ Command execution.
+ """
+ self.cursor = connection.cursor()
+ self.introspection = connection.introspection
+
+ all_models = get_models()
+ found_missing_fields = False
+ for model in all_models:
+ try:
+ options = translator.get_options_for_model(model)
+ # options returns full-wide spectrum of localized fields
but
+ # we only to synchronize the local fields attached to the
model.
+ local_field_names = [field.name for field
+ in model._meta.local_fields]
+ translatable_fields = [field for field
+ in options.localized_fieldnames
+ if field in local_field_names]
+ model_full_name = '%s.%s' % (model._meta.app_label,
+ model._meta.module_name)
+ db_table = model._meta.db_table
+ for field_name in translatable_fields:
+ missing_langs = list(
+ self.get_missing_languages(field_name, db_table))
+ if missing_langs:
+ found_missing_fields = True
+ print_missing_langs(
+ missing_langs, field_name, model_full_name)
+ sql_sentences = self.get_sync_sql(
+ field_name, missing_langs, model)
+ execute_sql = ask_for_confirmation(
+ sql_sentences, model_full_name)
+ if execute_sql:
+ print 'Executing SQL...',
+ for sentence in sql_sentences:
+ self.cursor.execute(sentence)
+ print 'Done'
+ else:
+ print 'SQL not executed'
+ except NotRegistered:
+ pass
+
+ transaction.commit_unless_managed()
+
+ if not found_missing_fields:
+ print 'No new translatable fields detected'
+
+ def get_table_fields(self, db_table):
+ """
+ Gets table fields from schema.
+ """
+ db_table_desc = self.introspection.get_table_description(
+ self.cursor, db_table)
+ return [t[0] for t in db_table_desc]
+
+ def get_missing_languages(self, field_name, db_table):
+ """
+ Gets only missings fields.
+ """
+ db_table_fields = self.get_table_fields(db_table)
+ for lang_code, lang_name in settings.LANGUAGES:
+ if build_localized_fieldname(
+ field_name, lang_code) not in db_table_fields:
+ yield lang_code
+
+ def get_sync_sql(self, field_name, missing_langs, model):
+ """
+ Returns SQL needed for sync schema for a new translatable field.
+ """
+ qn = connection.ops.quote_name
+ style = no_style()
+ sql_output = []
+ db_table = model._meta.db_table
+ for lang in missing_langs:
+ new_field = build_localized_fieldname(field_name, lang)
+ f = model._meta.get_field(new_field)
+ col_type = f.db_type(connection)
+ field_sql = [style.SQL_FIELD(qn(f.column)),
+ style.SQL_COLTYPE(col_type)]
+ # column creation
+ sql_output.append(
+ "ALTER TABLE %s ADD COLUMN %s;" % (
+ qn(db_table), ' '.join(field_sql)))
+ if not f.null and lang == settings.LANGUAGE_CODE:
+ sql_output.append("ALTER TABLE %s MODIFY
COLUMN %s %s %s;" % \
+ (qn(db_table), qn(f.column), col_type,
+ style.SQL_KEYWORD('NOT NULL')))
+ return sql_output
=======================================
--- /trunk/AUTHORS.txt Tue Oct 26 13:28:20 2010
+++ /trunk/AUTHORS.txt Wed Jul 11 05:57:37 2012
@@ -8,3 +8,4 @@
Carl J. Meyer
Jaap Roes
Bojan Mihelac
+Sébastien Fievet
=======================================
--- /trunk/CHANGELOG.txt Wed Jul 11 05:28:30 2012
+++ /trunk/CHANGELOG.txt Wed Jul 11 05:57:37 2012
@@ -1,14 +1,18 @@
v0.4.0-alpha1
=============

- FIXED: Dynamic TranslationOptions model name.
+ ADDED: New management command sync_database_fields to sync the database
after
+ a new model has been registered or a new language has been added.
+ (thanks to Sébastien Fievet and the authors of django-transmeta,
+ resolves issue 62)
+
CHANGED: Use app-level translation files in favour of a single
project-level
one. Adds an autoregister feature similiar to the one provided by
Django's admin. A new setting MODELTRANSLATION_TRANSLATION_FILES
keeps
backwards compatibility with older versions. See documentation for
details. This is basically a merge from both
django-modeltranslation-wrapper and hyperweek's branch at github.
- (thanks to Jacek Tomaszewski, hyperweek and haineault)
+ (thanks to Jacek Tomaszewski, Sébastien Fievet and Maxime
Haineault,
resolves issues 19, 58 and 71)
CHANGED: Moved tests to separate folder and added tests for
TranslationAdmin.
To run the tests the settings provided in
model.tests.modeltranslation
@@ -20,6 +24,8 @@
and get_fieldsets. This should resolve several problems with the
exclude and fieldsets options and properly support options in
inlines.
(resolves issue 72)
+
+ FIXED: Dynamic TranslationOptions model name.
FIXED: Widgets for translated fields are not properly copied from
original
fields.
(thanks to boris-chervenkov, resolves issue 74)
@@ -35,6 +41,7 @@
CHANGED: jQuery search path in tabbed_translation_fields.js. This allows
use of
a version of jQuery other than the one provided by Django. Users
who
want to force the use of Django's jQuery can include
force_jquery.js.
+
FIXED: Another attempt to include static files during installation.
(resolves reopened issue 61)

Reply all
Reply to author
Forward
0 new messages