Django

Code

Changeset 3320

Show
Ignore:
Timestamp:
07/10/06 22:16:28 (2 years ago)
Author:
jpellerin
Message:

[multi-db] Added preliminary drop-table generation to django.db.backends.ansi.sql.SchemaBuilder?.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/multiple-db-support/django/db/backends/ansi/sql.py

    r3315 r3320  
    4444    """ 
    4545    def __init__(self): 
     46        # models that I have created 
    4647        self.models_already_seen = set() 
    47  
     48        # model references, keyed by the referrent model 
     49        self.references = {} 
     50        # table cache; set to short-circuit table lookups 
     51        self.tables = None 
     52         
    4853    def get_create_table(self, model, style=None): 
    4954        """Construct and return the SQL expression(s) needed to create the 
     
    219224        """Construct and return the SQL statment(s) needed to drop a model's 
    220225        table. If cascade is true, then output additional statments to drop any 
    221         dependant man-many tables and drop any foreign keys that reference 
    222         this table. 
     226        many-to-many tables that this table created and any foreign keys that 
     227        reference this table. 
    223228        """ 
    224229        if style is None: 
     
    228233        db_table = opts.db_table 
    229234        backend = info.backend 
     235        qn = backend.quote_name 
    230236        output = [] 
    231237        output.append(BoundStatement( 
    232238                '%s %s;' % (style.SQL_KEYWORD('DROP TABLE'), 
    233                             style.SQL_TABLE(backend.quote_name(db_table))), 
     239                            style.SQL_TABLE(qn(db_table))), 
    234240                info.connection)) 
    235241 
    236242        if cascade: 
    237             # FIXME deal with my foreign keys, others that might have a foreign 
    238             # key TO me, and many-many 
    239             pass 
     243            # deal with others that might have a foreign key TO me: alter 
     244            # their tables to drop the constraint 
     245            if backend.supports_constraints: 
     246                references_to_delete = self.get_references() 
     247                if model in references_to_delete: 
     248                    for rel_class, f in references_to_delete[model]: 
     249                        table = rel_class._meta.db_table 
     250                        if not self.table_exists(info, table): 
     251                            continue 
     252                        col = f.column 
     253                        r_table = opts.db_table 
     254                        r_col = opts.get_field(f.rel.field_name).column 
     255                        output.append(BoundStatement( 
     256                            '%s %s %s %s;' %  
     257                            (style.SQL_KEYWORD('ALTER TABLE'), 
     258                             style.SQL_TABLE(qn(table)), 
     259                             style.SQL_KEYWORD( 
     260                                        backend.get_drop_foreignkey_sql()), 
     261                             style.SQL_FIELD(qn("%s_referencing_%s_%s" % 
     262                                                (col, r_table, r_col)))), 
     263                            info.connection)) 
     264                    del references_to_delete[model] 
     265            # many to many: drop any many-many tables that are my 
     266            # responsiblity 
     267            for f in opts.many_to_many: 
     268                if not isinstance(f.rel, models.GenericRel): 
     269                    output.append(BoundStatement( 
     270                            '%s %s;' % 
     271                            (style.SQL_KEYWORD('DROP TABLE'), 
     272                             style.SQL_TABLE(qn(f.m2m_db_table()))), 
     273                            info.connection)) 
    240274        # Reverse it, to deal with table dependencies.         
    241275        output.reverse() 
     
    274308        """Get the path from which to load sql initial data files for a model. 
    275309        """ 
    276         return os.path.normpath(os.path.join(os.path.dirname(models.get_app(model._meta.app_label).__file__), 'sql')) 
     310        return os.path.normpath(os.path.join(os.path.dirname( 
     311                    models.get_app(model._meta.app_label).__file__), 'sql')) 
    277312             
    278313    def get_rel_data_type(self, f): 
     
    281316                                          and 'IntegerField' \ 
    282317                                          or f.get_internal_type() 
    283          
     318     
     319    def get_references(self): 
     320        """Fill (if needed) and return the reference cache. 
     321        """ 
     322        if self.references: 
     323            return self.references 
     324        for klass in models.get_models(): 
     325            for f in klass._meta.fields: 
     326                if f.rel: 
     327                    self.references.setdefault(f.rel.to, []).append((klass, f)) 
     328        return self.references 
     329 
     330    def get_table_list(self, connection_info): 
     331        """Get list of tables accessible via the connection described by 
     332        connection_info. 
     333        """ 
     334        if self.tables is not None: 
     335            return self.tables 
     336        cursor = info.connection.cursor() 
     337        introspection = connection_info.get_introspection_module() 
     338        return introspection.get_table_list(cursor)         
     339     
     340    def table_exists(self, connection_info, table): 
     341        tables = self.get_table_list(connection_info) 
     342        return table in tables 
  • django/branches/multiple-db-support/django/db/models/manager.py

    r3291 r3320  
    160160        """ 
    161161        info = self.model._meta.connection_info 
    162         cursor = info.connection.cursor() 
    163         introspect = info.get_introspection_module() 
    164         return introspect.get_table_list(cursor) 
     162        builder = info.get_creation_module.builder() 
     163        return builder.get_table_list(info) 
    165164     
    166165class ManagerDescriptor(object): 
  • django/branches/multiple-db-support/tests/othertests/ansi_sql.py

    r3293 r3320  
    1 # For Python 2.3 
    2 if not hasattr(__builtins__, 'set'): 
    3     from sets import Set as set 
    4  
    51""" 
    6 >>> from django.db import models 
    72>>> from django.db.backends.ansi import sql 
    83 
    9 # test models 
    10 >>> class Car(models.Model): 
    11 ...     make = models.CharField(maxlength=32) 
    12 ...     model = models.CharField(maxlength=32) 
    13 ...     year = models.IntegerField() 
    14 ...     condition = models.CharField(maxlength=32) 
    15 ...      
    16 ...     class Meta: 
    17 ...         app_label = 'ansi_sql' 
    18  
    19 >>> class Collector(models.Model): 
    20 ...     name = models.CharField(maxlength=32) 
    21 ...     cars = models.ManyToManyField(Car) 
    22 ...      
    23 ...     class Meta: 
    24 ...         app_label = 'ansi_sql' 
    25  
    26 >>> class Mod(models.Model): 
    27 ...     car = models.ForeignKey(Car) 
    28 ...     part = models.CharField(maxlength=32, db_index=True) 
    29 ...     description = models.TextField() 
    30 ...      
    31 ...     class Meta: 
    32 ...         app_label = 'ansi_sql' 
     4# so we can test with a predicatable constraint setting 
     5>>> real_cnst = Mod._meta.connection_info.backend.supports_constraints 
     6>>> Mod._meta.connection_info.backend.supports_constraints = True 
    337     
    348# generate create sql 
    359>>> builder = sql.SchemaBuilder() 
    3610>>> builder.get_create_table(Car) 
    37 ([BoundStatement('CREATE TABLE "ansi_sql_car" (...);')], []
     11([BoundStatement('CREATE TABLE "ansi_sql_car" (...);')], {}
    3812>>> builder.models_already_seen 
    39 [<class 'othertests.ansi_sql.Car'>] 
     13Set([<class 'othertests.ansi_sql.Car'>]) 
    4014>>> builder.models_already_seen = set() 
    4115 
    4216# test that styles are used 
    4317>>> builder.get_create_table(Car, style=mockstyle()) 
    44 ([BoundStatement('SQL_KEYWORD(CREATE TABLE) SQL_TABLE("ansi_sql_car") (...SQL_FIELD("id")...);')], []
     18([BoundStatement('SQL_KEYWORD(CREATE TABLE) SQL_TABLE("ansi_sql_car") (...SQL_FIELD("id")...);')], {}
    4519 
    4620# test pending relationships 
    4721>>> builder.models_already_seen = set() 
    48 >>> real_cnst = Mod._meta.connection_info.backend.supports_constraints 
    49 >>> Mod._meta.connection_info.backend.supports_constraints = True 
    5022>>> builder.get_create_table(Mod) 
    5123([BoundStatement('CREATE TABLE "ansi_sql_mod" (..."car_id" integer NOT NULL,...);')], {<class 'othertests.ansi_sql.Car'>: [BoundStatement('ALTER TABLE "ansi_sql_mod" ADD CONSTRAINT ... FOREIGN KEY ("car_id") REFERENCES "ansi_sql_car" ("id");')]}) 
     
    5527>>> builder.get_create_table(Mod) 
    5628([BoundStatement('CREATE TABLE "ansi_sql_mod" (..."car_id" integer NOT NULL REFERENCES "ansi_sql_car" ("id"),...);')], {}) 
    57 >>> Mod._meta.connection_info.backend.supports_constraints = real_cnst 
    5829 
    5930# test many-many 
     
    7647>>> builder.get_initialdata(Car) 
    7748[BoundStatement('insert into ansi_sql_car (...)...values (...);')] 
     49 
     50# test drop 
     51>>> builder.get_drop_table(Mod) 
     52[BoundStatement('DROP TABLE "ansi_sql_mod";')] 
     53>>> builder.get_drop_table(Mod, cascade=True) 
     54[BoundStatement('DROP TABLE "ansi_sql_mod";')] 
     55>>> builder.get_drop_table(Car) 
     56[BoundStatement('DROP TABLE "ansi_sql_car";')] 
     57>>> builder.get_drop_table(Car, cascade=True) 
     58[BoundStatement('DROP TABLE "ansi_sql_car";')] 
     59 
     60>>> builder.tables = ['ansi_sql_car', 'ansi_sql_mod', 'ansi_sql_collector'] 
     61>>> Mod._meta.connection_info.backend.supports_constraints = False 
     62>>> builder.get_drop_table(Car, cascade=True) 
     63[BoundStatement('DROP TABLE "ansi_sql_car";')] 
     64>>> Mod._meta.connection_info.backend.supports_constraints = True 
     65>>> builder.get_drop_table(Car, cascade=True) 
     66[BoundStatement('ALTER TABLE "ansi_sql_mod" ...'), BoundStatement('DROP TABLE "ansi_sql_car";')] 
     67>>> builder.get_drop_table(Collector) 
     68[BoundStatement('DROP TABLE "ansi_sql_collector";')] 
     69>>> builder.get_drop_table(Collector, cascade=True) 
     70[BoundStatement('DROP TABLE "ansi_sql_collector_cars";'), BoundStatement('DROP TABLE "ansi_sql_collector";')] 
     71>>> Mod._meta.connection_info.backend.supports_constraints = real_cnst 
     72 
    7873""" 
    7974import os 
     75from django.db import models 
     76from django.core.management import install 
    8077 
    81 # mock style that wraps text in STYLE(text), for testing 
     78# For Python 2.3 
     79if not hasattr(__builtins__, 'set'): 
     80    from sets import Set as set 
     81 
     82 
     83# test models 
     84class Car(models.Model): 
     85    make = models.CharField(maxlength=32) 
     86    model = models.CharField(maxlength=32) 
     87    year = models.IntegerField() 
     88    condition = models.CharField(maxlength=32) 
     89     
     90    class Meta: 
     91        app_label = 'ansi_sql' 
     92 
     93         
     94class Collector(models.Model): 
     95    name = models.CharField(maxlength=32) 
     96    cars = models.ManyToManyField(Car) 
     97     
     98    class Meta: 
     99        app_label = 'ansi_sql' 
     100 
     101         
     102class Mod(models.Model): 
     103    car = models.ForeignKey(Car) 
     104    part = models.CharField(maxlength=32, db_index=True) 
     105    description = models.TextField() 
     106     
     107    class Meta: 
     108        app_label = 'ansi_sql' 
     109 
     110 
    82111class mockstyle: 
     112    """mock style that wraps text in STYLE(text), for testing""" 
    83113    def __getattr__(self, attr): 
    84114        if attr in ('ERROR', 'ERROR_OUTPUT', 'SQL_FIELD', 'SQL_COLTYPE', 
     
    86116            return lambda text: "%s(%s)" % (attr, text) 
    87117 
     118         
    88119def othertests_sql(mod): 
    89120    """Look in othertests/sql for sql initialdata""" 
    90121    return os.path.normpath(os.path.join(os.path.dirname(__file__), 'sql')) 
     122 
     123 
     124# install my stuff 
     125Car.objects.install() 
     126Collector.objects.install() 
     127Mod.objects.install()