Ticket #6148: generic-db_schema-r8319.diff

File generic-db_schema-r8319.diff, 9.5 KB (added by crippledcanary@…, 7 years ago)

remade some stuff and added testing and doc. Tested with mysql and sqlite so far

  • django/core/management/commands/syncdb.py

     
    6161            app_name = app.__name__.split('.')[-2]
    6262            model_list = models.get_models(app)
    6363            for model in model_list:
     64                # Add model defined schema tables if anny
     65                if model._meta.db_schema:
     66                    tables += connection.introspection.schema_table_names(model._meta.db_schema)
    6467                # Create the model's database table, if it doesn't already exist.
    6568                if verbosity >= 2:
    6669                    print "Processing %s.%s model" % (app_name, model._meta.object_name)
  • django/core/management/sql.py

     
    8484    references_to_delete = {}
    8585    app_models = models.get_models(app)
    8686    for model in app_models:
     87        # Find aditional tables in model defined schemas
     88        if model._meta.db_schema:
     89            table_names += connection.introspection.get_schema_table_list(cursor, model._meta.db_schema)
    8790        if cursor and connection.introspection.table_name_converter(model._meta.db_table) in table_names:
    8891            # The table exists, so it needs to be dropped
    8992            opts = model._meta
  • django/db/backends/__init__.py

     
    225225        """
    226226        raise NotImplementedError()
    227227
     228    def prep_db_table(self, db_schema, db_table):
     229        """
     230        Prepares and formats the table name if neccesary.
     231        Just returns the db_table if not supported
     232        """
     233        return db_table
     234
    228235    def random_function_sql(self):
    229236        """
    230237        Returns a SQL expression that returns a random value.
     
    381388        "Returns a list of names of all tables that exist in the database."
    382389        cursor = self.connection.cursor()
    383390        return self.get_table_list(cursor)
     391   
     392    def get_schema_table_list(self, cursor, schema):
     393        return []
     394   
     395    def schema_table_names(self, schema):
     396        "Returns a list of names of all tables that exist in the database schema."
     397        cursor = self.connection.cursor()
     398        return self.get_schema_table_list(cursor, schema)
    384399
    385400    def django_table_names(self, only_existing=False):
    386401        """
  • django/db/backends/creation.py

     
    243243                    tablespace_sql = ''
    244244            else:
    245245                tablespace_sql = ''
     246            # Use original db_table in index name if schema is provided
     247            if model._meta.db_schema:
     248                index_table_name = model._meta._db_table
     249            else:
     250                index_table_name = model._meta.db_table
     251               
    246252            output = [style.SQL_KEYWORD('CREATE INDEX') + ' ' +
    247                 style.SQL_TABLE(qn('%s_%s' % (model._meta.db_table, f.column))) + ' ' +
     253                style.SQL_TABLE(qn('%s_%s' % (index_table_name, f.column))) + ' ' +
    248254                style.SQL_KEYWORD('ON') + ' ' +
    249255                style.SQL_TABLE(qn(model._meta.db_table)) + ' ' +
    250256                "(%s)" % style.SQL_FIELD(qn(f.column)) +
  • django/db/backends/mysql/base.py

     
    106106    def quote_name(self, name):
    107107        if name.startswith("`") and name.endswith("`"):
    108108            return name # Quoting once is enough.
    109         return "`%s`" % name
     109        # add support for tablenames passed that also have their schema in their name
     110        return "`%s`" % name.replace('.','`.`')
    110111
     112    def prep_db_table(self, db_schema, db_table):
     113        return "%s.%s" % (db_schema, db_table)
     114
    111115    def random_function_sql(self):
    112116        return 'RAND()'
    113117
  • django/db/backends/mysql/introspection.py

     
    3232        cursor.execute("SHOW TABLES")
    3333        return [row[0] for row in cursor.fetchall()]
    3434
     35    def get_schema_table_list(self, cursor, schema):
     36        cursor.execute("SHOW TABLES FROM %s" % self.connection.ops.quote_name(schema))
     37        return [schema + "." + row[0] for row in cursor.fetchall()]
     38   
    3539    def get_table_description(self, cursor, table_name):
    3640        "Returns a description of the table, with the DB-API cursor.description interface."
    3741        cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name))
  • django/db/models/options.py

     
    2121DEFAULT_NAMES = ('verbose_name', 'db_table', 'ordering',
    2222                 'unique_together', 'permissions', 'get_latest_by',
    2323                 'order_with_respect_to', 'app_label', 'db_tablespace',
    24                  'abstract')
     24                 'abstract', 'db_schema')
    2525
    2626class Options(object):
    2727    def __init__(self, meta, app_label=None):
     
    2929        self.module_name, self.verbose_name = None, None
    3030        self.verbose_name_plural = None
    3131        self.db_table = ''
     32        self.db_schema = ''
    3233        self.ordering = []
    3334        self.unique_together =  []
    3435        self.permissions =  []
     
    9596            self.db_table = "%s_%s" % (self.app_label, self.module_name)
    9697            self.db_table = truncate_name(self.db_table, connection.ops.max_name_length())
    9798
     99        # Patch db_table with the schema if provided and allowed
     100        if self.db_schema:
     101            # Store original db_table in a save place first
     102            self._db_table = self.db_table
     103            self.db_table = connection.ops.prep_db_table(self.db_schema, self.db_table)
     104            # If no changes were done then backend don't support schemas
     105            if self._db_table == self.db_table:
     106                self.db_schema = ''
    98107
    99108    def _prepare(self, model):
    100109        if self.order_with_respect_to:
  • docs/model-api.txt

     
    12071207that aren't allowed in Python variable names -- notably, the hyphen --
    12081208that's OK. Django quotes column and table names behind the scenes.
    12091209
     1210``db_schema``
     1211-----------------
     1212
     1213**New in Django development version**
     1214
     1215The name of the database schema to use for the model. If the backend
     1216doesn't support multiple schemas, this options is ignored.
     1217
     1218If this is used Django will prefix any table names with the schema name.
     1219For MySQL Django would use ``db_schema + '.' + db_table``.
     1220
     1221
    12101222``db_tablespace``
    12111223-----------------
    12121224
  • tests/modeltests/schemas/models.py

     
     1# coding: utf-8
     2
     3from django.db import models
     4
     5
     6class Blog(models.Model):
     7    "Model in default schema"
     8    name = models.CharField(max_length=50)
     9
     10   
     11class Entry(models.Model):
     12    "Model in custom schema that reference the default"
     13    blog = models.ForeignKey(Blog)   
     14    title = models.CharField(max_length=50)
     15   
     16    class Meta:
     17        "using custom db_table as well"
     18        db_table='schema_blog_entries'
     19        db_schema = 'test_django'
     20       
     21
     22class Comment(models.Model):
     23    "Model in the default schema that references the custom"
     24    entry = models.ForeignKey(Entry)
     25    text = models.CharField(max_length=50)
     26
     27__test__ = {'API_TESTS': """
     28# Nothing in there yet
     29>>> Blog.objects.all()
     30[]
     31
     32# Create a blog
     33>>> b = Blog(name='Test')
     34>>> b.save()
     35
     36# Verify that we got an ID
     37>>> b.id
     381
     39
     40# Create entry
     41>>> e = Entry(blog=b, title='Test entry')
     42>>> e.save()
     43>>> e.id
     441
     45
     46# Create Comments
     47>>> c1 = Comment(entry=e, text='nice entry')
     48>>> c1.save()
     49>>> c2 = Comment(entry=e, text='really like it')
     50>>> c2.save()
     51
     52
     53>>> from django.conf import settings
     54>>> from django.db import connection, models
     55
     56# Test if we support schemas and can find the table if so
     57>>> if e._meta.db_schema:
     58...     tables = connection.introspection.schema_table_names(e._meta.db_schema)
     59... else:
     60...     tables = connection.introspection.table_names()
     61>>> if connection.introspection.table_name_converter(e._meta.db_table) in tables:
     62...     print "ok"
     63... else:
     64...     print "schema=" + e._meta.db_schema
     65ok
     66
     67# Test that mysql backend doesn't drop the schema
     68>>> if settings.DATABASE_ENGINE == 'mysql':
     69...     if e._meta.db_schema != 'test_django':
     70...         print "shouldn't drop or modify schema"
     71
     72#Done
     73"""
     74}
Back to Top