Django

Code

MultipleDatabaseSupport: p5.diff

File p5.diff, 52.8 kB (added by jpellerin@gmail.com, 2 years ago)

Updated patch including transaction support

  • django/db/models/base.py

    old new  
    77from django.db.models.related import RelatedObject 
    88from django.db.models.query import orderlist2sql, delete_objects 
    99from django.db.models.options import Options, AdminOptions 
    10 from django.db import connection, backend, transaction 
     10from django.db import transaction 
    1111from django.db.models import signals 
    1212from django.db.models.loading import register_models 
    1313from django.dispatch import dispatcher 
     
    3838                new_class._meta.parents.extend(base._meta.parents) 
    3939 
    4040        model_module = sys.modules[new_class.__module__] 
    41  
     41         
    4242        if getattr(new_class._meta, 'app_label', None) is None: 
    4343            # Figure out the app_label by looking one level up. 
    4444            # For 'django.contrib.sites.models', this would be 'sites'. 
     
    154154    def save(self): 
    155155        dispatcher.send(signal=signals.pre_save, sender=self.__class__, instance=self) 
    156156 
     157        info = self._meta.connection_info 
     158        connection = info.connection 
     159        backend = info.backend 
    157160        non_pks = [f for f in self._meta.fields if not f.primary_key] 
    158161        cursor = connection.cursor() 
    159162 
     
    201204                     backend.get_pk_default_value())) 
    202205            if self._meta.has_auto_field and not pk_set: 
    203206                setattr(self, self._meta.pk.attname, backend.get_last_insert_id(cursor, self._meta.db_table, self._meta.pk.column)) 
    204         transaction.commit_unless_managed(
     207        transaction.commit_unless_managed([connection]
    205208 
    206209        # Run any post-save hooks. 
    207210        dispatcher.send(signal=signals.post_save, sender=self.__class__, instance=self) 
     
    272275        return dict(field.choices).get(value, value) 
    273276 
    274277    def _get_next_or_previous_by_FIELD(self, field, is_next, **kwargs): 
     278        backend = self._meta.connection_info.backend 
    275279        op = is_next and '>' or '<' 
    276280        where = '(%s %s %%s OR (%s = %%s AND %s.%s %s %%s))' % \ 
    277281            (backend.quote_name(field.column), op, backend.quote_name(field.column), 
     
    286290            raise self.DoesNotExist, "%s matching query does not exist." % self.__class__._meta.object_name 
    287291 
    288292    def _get_next_or_previous_in_order(self, is_next): 
     293        backend = self._meta.connection_info.backend 
    289294        cachename = "__%s_order_cache" % is_next 
    290295        if not hasattr(self, cachename): 
    291296            op = is_next and '>' or '<' 
     
    374379        rel = rel_field.rel.to 
    375380        m2m_table = rel_field.m2m_db_table() 
    376381        this_id = self._get_pk_val() 
     382        info = self._meta.connection_info 
     383        connection = info.connection 
     384        backend = info.backend 
    377385        cursor = connection.cursor() 
    378386        cursor.execute("DELETE FROM %s WHERE %s = %%s" % \ 
    379387            (backend.quote_name(m2m_table), 
     
    383391            backend.quote_name(rel_field.m2m_column_name()), 
    384392            backend.quote_name(rel_field.m2m_reverse_name())) 
    385393        cursor.executemany(sql, [(this_id, i) for i in id_list]) 
    386         transaction.commit_unless_managed(
     394        transaction.commit_unless_managed([connection]
    387395 
    388396############################################ 
    389397# HELPER FUNCTIONS (CURRIED MODEL METHODS) # 
     
    392400# ORDERING METHODS ######################### 
    393401 
    394402def method_set_order(ordered_obj, self, id_list): 
     403    connection_info = ordered_obj.connection_info 
     404    connection = info.connection 
     405    backend = info.backend 
     406     
    395407    cursor = connection.cursor() 
    396408    # Example: "UPDATE poll_choices SET _order = %s WHERE poll_id = %s AND id = %s" 
    397409    sql = "UPDATE %s SET %s = %%s WHERE %s = %%s AND %s = %%s" % \ 
     
    400412        backend.quote_name(ordered_obj.pk.column)) 
    401413    rel_val = getattr(self, ordered_obj.order_with_respect_to.rel.field_name) 
    402414    cursor.executemany(sql, [(i, rel_val, j) for i, j in enumerate(id_list)]) 
    403     transaction.commit_unless_managed(
     415    transaction.commit_unless_managed([connection]
    404416 
    405417def method_get_order(ordered_obj, self): 
     418    connection_info = ordered_obj.connection_info 
     419    connection = info.connection 
     420    backend = info.backend 
    406421    cursor = connection.cursor() 
    407422    # Example: "SELECT id FROM poll_choices WHERE poll_id = %s ORDER BY _order" 
    408423    sql = "SELECT %s FROM %s WHERE %s = %%s ORDER BY %s" % \ 
  • django/db/models/manager.py

    old new  
    9999    def values(self, *args, **kwargs): 
    100100        return self.get_query_set().values(*args, **kwargs) 
    101101 
     102    ####################### 
     103    # SCHEMA MANIPULATION # 
     104    ####################### 
     105 
     106    def install(self, initial_data=False): 
     107        """Install my model's table, indexes and (if requested) initial data. 
     108 
     109        Returns a 2-tuple of the lists of statements executed and 
     110        statements pending. Pending statements are those that could 
     111        not yet be executed, such as foreign key constraints for 
     112        tables that don't exist at install time. 
     113        """ 
     114        creator = self.model._meta.connection_info.get_creation_module() 
     115        run, pending = creator.get_create_table(self.model) 
     116        run += creator.get_create_indexes(self.model) 
     117        pending += creator.get_create_many_to_many(self.model) 
     118        if initial_data: 
     119            run += creator.get_initialdata(self.model) 
     120 
     121        executed = [] 
     122        for statement in run: 
     123            statement.execute() 
     124            executed.append(statement) 
     125        return (executed, pending) 
     126 
     127    def load_initial_data(self): 
     128        """Load initial data for my model into the database.""" 
     129        pass 
     130 
     131    def drop(self): 
     132        """Drop my model's table.""" 
     133        pass 
     134 
     135    # Future... 
     136     
     137    def add_column(self, column): 
     138        """Add a column to my model's table""" 
     139        pass 
     140 
     141    def drop_column(self, column): 
     142        """Drop a column from my model's table""" 
     143        pass 
     144         
     145 
    102146class ManagerDescriptor(object): 
    103147    # This class ensures managers aren't accessible via model instances. 
    104148    # For example, Poll.objects works, but poll_obj.objects raises AttributeError. 
  • django/db/models/options.py

    old new  
    11from django.conf import settings 
     2from django.db import connection_info, connections 
    23from django.db.models.related import RelatedObject 
    34from django.db.models.fields.related import ManyToManyRel 
    45from django.db.models.fields import AutoField, FieldDoesNotExist 
     
    1112# Calculate the verbose_name by converting from InitialCaps to "lowercase with spaces". 
    1213get_verbose_name = lambda class_name: re.sub('(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))', ' \\1', class_name).lower().strip() 
    1314 
    14 DEFAULT_NAMES = ('verbose_name', 'db_table', 'ordering', 
     15DEFAULT_NAMES = ('verbose_name', 'db_connection', 'db_table', 'ordering', 
    1516                 'unique_together', 'permissions', 'get_latest_by', 
    1617                 'order_with_respect_to', 'app_label') 
    1718 
     
    2021        self.fields, self.many_to_many = [], [] 
    2122        self.module_name, self.verbose_name = None, None 
    2223        self.verbose_name_plural = None 
     24        self.db_connection = None 
    2325        self.db_table = '' 
    2426        self.ordering = [] 
    2527        self.unique_together =  [] 
     
    5658                raise TypeError, "'class Meta' got invalid attribute(s): %s" % ','.join(meta_attrs.keys()) 
    5759        else: 
    5860            self.verbose_name_plural = self.verbose_name + 's' 
     61        #  
    5962        del self.meta 
    6063 
    6164    def _prepare(self, model): 
     
    8891    def __repr__(self): 
    8992        return '<Options for %s>' % self.object_name 
    9093 
     94    def get_connection_info(self): 
     95        if self.db_connection: 
     96            return connections[self.db_connection] 
     97        return connection_info 
     98    connection_info = property(get_connection_info) 
     99             
     100    def get_connection(self): 
     101        """Get the database connection for this object's model""" 
     102        return self.get_connection_info().connection 
     103    connection = property(get_connection) 
     104     
    91105    def get_field(self, name, many_to_many=True): 
    92106        "Returns the requested field by name. Raises FieldDoesNotExist on error." 
    93107        to_search = many_to_many and (self.fields + self.many_to_many) or self.fields 
  • django/db/models/loading.py

    old new  
    88_app_list = None # Cache of installed apps. 
    99_app_models = {} # Dictionary of models against app label 
    1010                 # Each value is a dictionary of model name: model class 
    11  
     11_app_model_order = {} # Dictionary of models against app label 
     12                      # Each value is a list of model names, in the order in 
     13                      # which the models were created 
    1214def get_apps(): 
    1315    "Returns a list of all installed modules that contain models." 
    1416    global _app_list 
     
    3537            return __import__(app_name, '', '', ['models']).models 
    3638    raise ImproperlyConfigured, "App with label %s could not be found" % app_label 
    3739 
    38 def get_models(app_mod=None): 
     40def get_models(app_mod=None, creation_order=False): 
    3941    """ 
    4042    Given a module containing models, returns a list of the models. Otherwise 
    41     returns a list of all installed models. 
     43    returns a list of all installed models. In either case, if creation_order 
     44    is true, return the models sorted into the same order in which they 
     45    were created. 
    4246    """ 
    4347    app_list = get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish. 
    4448    if app_mod: 
    45         return _app_models.get(app_mod.__name__.split('.')[-2], {}).values() 
     49        app_label = app_mod.__name__.split('.')[-2] 
     50        app_models = _app_models.get(app_label, {}) 
     51        if creation_order: 
     52            return [ app_models[name] 
     53                     for name in _app_model_order.get(app_label, []) ] 
     54        return app_models.values() 
    4655    else: 
    4756        model_list = [] 
    4857        for app_mod in app_list: 
     
    7584        model_name = model._meta.object_name.lower() 
    7685        model_dict = _app_models.setdefault(app_label, {}) 
    7786        model_dict[model_name] = model 
     87        model_list = _app_model_order.setdefault(app_label, []) 
     88        model_list.append(model_name) 
  • django/db/models/query.py

    old new  
    1 from django.db import backend, connection, transaction 
     1from django.db import backend, connection, connections, transaction 
    22from django.db.models.fields import DateField, FieldDoesNotExist 
    33from django.db.models import signals 
    44from django.dispatch import dispatcher 
     
    158158        # undefined, so we convert it to a list of tuples. 
    159159        extra_select = self._select.items() 
    160160 
    161         cursor = connection.cursor() 
     161        cursor = self.model._meta.connection.cursor() 
    162162        select, sql, params = self._get_sql_clause() 
    163163        cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params) 
    164164        fill_cache = self._select_related 
     
    178178 
    179179    def count(self): 
    180180        "Performs a SELECT COUNT() and returns the number of records as an integer." 
     181 
     182        info = self.model._meta.connection_info 
     183        backend = info.backend 
     184        connection = info.connection 
     185         
    181186        counter = self._clone() 
    182187        counter._order_by = () 
    183188        counter._offset = None 
     
    505510            columns = [f.column for f in self.model._meta.fields] 
    506511            field_names = [f.attname for f in self.model._meta.fields] 
    507512 
     513        info = self.model._meta.connection_info 
     514        backend = info.backend 
     515        connection = info.connection 
    508516        cursor = connection.cursor() 
    509517        select, sql, params = self._get_sql_clause() 
    510518        select = ['%s.%s' % (backend.quote_name(self.model._meta.db_table), backend.quote_name(c)) for c in columns] 
     
    524532class DateQuerySet(QuerySet): 
    525533    def iterator(self): 
    526534        from django.db.backends.util import typecast_timestamp 
     535 
     536        info = self.model._meta.connection_info 
     537        backend = info.backend 
     538        connection = info.connection 
     539         
    527540        self._order_by = () # Clear this because it'll mess things up otherwise. 
    528541        if self._field.null: 
    529542            self._where.append('%s.%s IS NOT NULL' % \ 
     
    616629        where2 = ['(NOT (%s))' % " AND ".join(where)] 
    617630        return tables, joins, where2, params 
    618631 
    619 def get_where_clause(lookup_type, table_prefix, field_name, value): 
     632def get_where_clause(opts, lookup_type, table_prefix, field_name, value): 
     633    backend = opts.connection_info.backend 
     634     
    620635    if table_prefix.endswith('.'): 
    621636        table_prefix = backend.quote_name(table_prefix[:-1])+'.' 
    622637    field_name = backend.quote_name(field_name) 
     
    745760    intermediate_table = None 
    746761    join_required = False 
    747762 
     763    info = current_opts.connection_info 
     764    backend = info.backend 
     765    connection = info.connection 
     766 
    748767    name = path.pop(0) 
    749768    # Has the primary key been requested? If so, expand it out 
    750769    # to be the name of the current class' primary key 
     
    872891        else: 
    873892            column = field.column 
    874893 
    875         where.append(get_where_clause(clause, current_table + '.', column, value)) 
     894        where.append(get_where_clause(current_opts, clause, current_table + '.', column, value)) 
    876895        params.extend(field.get_db_prep_lookup(clause, value)) 
    877896 
    878897    return tables, joins, where, params 
     
    882901    ordered_classes = seen_objs.keys() 
    883902    ordered_classes.reverse() 
    884903 
    885     cursor = connection.cursor() 
    886904 
    887905    for cls in ordered_classes: 
     906 
     907        info = cls._meta.connection_info 
     908        backend = info.backend 
     909        connection = info.connection 
     910        cursor = connection.cursor() 
     911         
    888912        seen_objs[cls] = seen_objs[cls].items() 
    889913        seen_objs[cls].sort() 
    890914 
     
    919943 
    920944    # Now delete the actual data 
    921945    for cls in ordered_classes: 
     946 
     947        info = cls._meta.connection_info 
     948        backend = info.backend 
     949        connection = info.connection 
     950        cursor = connection.cursor() 
     951 
    922952        seen_objs[cls].reverse() 
    923953        pk_list = [pk for pk,instance in seen_objs[cls]] 
    924954        for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE): 
  • django/db/__init__.py

    old new  
    1 from django.conf import settings 
     1from django.conf import settings, UserSettingsHolder 
    22from django.core import signals 
     3from django.core.exceptions import ImproperlyConfigured 
    34from django.dispatch import dispatcher 
    45 
    56__all__ = ('backend', 'connection', 'DatabaseError') 
     
    78if not settings.DATABASE_ENGINE: 
    89    settings.DATABASE_ENGINE = 'dummy' 
    910 
    10 try: 
    11     backend = __import__('django.db.backends.%s.base' % settings.DATABASE_ENGINE, '', '', ['']) 
    12 except ImportError, e: 
    13     # The database backend wasn't found. Display a helpful error message 
    14     # listing all possible database backends. 
    15     from django.core.exceptions import ImproperlyConfigured 
    16     import os 
    17     backend_dir = os.path.join(__path__[0], 'backends') 
    18     available_backends = [f for f in os.listdir(backend_dir) if not f.startswith('_') and not f.startswith('.') and not f.endswith('.py') and not f.endswith('.pyc')] 
    19     available_backends.sort() 
    20     if settings.DATABASE_ENGINE not in available_backends: 
    21         raise ImproperlyConfigured, "%r isn't an available database backend. vailable options are: %s" % \ 
    22             (settings.DATABASE_ENGINE, ", ".join(map(repr, available_backends))) 
    23     else: 
    24         raise # If there's some other error, this must be an error in Django itself. 
     11class ConnectionInfo(object): 
     12    """Encapsulates all information about a db connection: 
     13     - connection 
     14     - DatabaseError 
     15     - backend 
     16     - get_introspection_module 
     17     - get_creation_module 
     18     - runshell 
     19    """ 
     20    def __init__(self, connection, DatabaseError, backend,  
     21                 get_introspection_module, get_creation_module, runshell): 
     22        self.connection = connection 
     23        self.DatabaseError = DatabaseError 
     24        self.backend = backend 
     25        self.get_introspection_module = get_introspection_module 
     26        self.get_creation_module = get_creation_module 
     27        self.runshell = runshell 
    2528 
    26 get_introspection_module = lambda: __import__('django.db.backends.%s.introspection' % settings.DATABASE_ENGINE, '', '', ['']) 
    27 get_creation_module = lambda: __import__('django.db.backends.%s.creation' % settings.DATABASE_ENGINE, '', '', ['']) 
    28 runshell = lambda: __import__('django.db.backends.%s.client' % settings.DATABASE_ENGINE, '', '', ['']).runshell() 
     29    def __repr__(self): 
     30        return "Connection: %r (ENGINE=%s NAME=%s)" \ 
     31               % (self.connection, 
     32                  self.connection.settings.DATABASE_ENGINE, 
     33                  self.connection.settings.DATABASE_NAME) 
    2934 
    30 connection = backend.DatabaseWrapper() 
    31 DatabaseError = backend.DatabaseError 
     35def connect(settings=settings): 
     36    """Connect to the database specified in the given settings. 
     37    """ 
     38    try: 
     39        backend = __import__('django.db.backends.%s.base' % settings.DATABASE_ENGINE, '', '', ['']) 
     40    except ImportError, e: 
     41        # The database backend wasn't found. Display a helpful error message 
     42        # listing all possible database backends. 
     43        import os 
     44        backend_dir = os.path.join(__path__[0], 'backends') 
     45        available_backends = [f for f in os.listdir(backend_dir) if not f.startswith('_') and not f.startswith('.') and not f.endswith('.py') and not f.endswith('.pyc')] 
     46        available_backends.sort() 
     47        if settings.DATABASE_ENGINE not in available_backends: 
     48            raise ImproperlyConfigured, "%r isn't an available database backend. vailable options are: %s" % \ 
     49                (settings.DATABASE_ENGINE, ", ".join(map(repr, available_backends))) 
     50        else: 
     51            raise # If there's some other error, this must be an error in Django itself. 
    3252 
    33 # Register an event that closes the database connection 
    34 # when a Django request is finished. 
    35 dispatcher.connect(connection.close, signal=signals.request_finished) 
    3653 
     54    get_introspection_module = lambda: __import__('django.db.backends.%s.introspection' % settings.DATABASE_ENGINE, '', '', ['']) 
     55    get_creation_module = lambda: __import__('django.db.backends.%s.creation' % settings.DATABASE_ENGINE, '', '', ['']) 
     56    runshell = lambda: __import__('django.db.backends.%s.client' % settings.DATABASE_ENGINE, '', '', ['']).runshell() 
     57 
     58    connection = backend.DatabaseWrapper(settings) 
     59    DatabaseError = backend.DatabaseError 
     60 
     61    return ConnectionInfo(connection, DatabaseError, backend,  
     62                          get_introspection_module, get_creation_module, 
     63                          runshell) 
     64 
     65connection_info = connect(settings) 
     66 
     67# backwards compatibility 
     68(connection, DatabaseError, backend, get_introspection_module,  
     69 get_creation_module, runshell) = (connection_info.connection, 
     70                                   connection_info.DatabaseError, 
     71                                   connection_info.backend, 
     72                                   connection_info.get_introspection_module,  
     73                                   connection_info.get_creation_module, 
     74                                   connection_info.runshell) 
     75 
     76 
     77class LazyConnectionManager(object): 
     78    """Manages named connections lazily, instantiating them as 
     79    they are requested. 
     80    """ 
     81 
     82    def __init__(self): 
     83        self._connections = {} 
     84 
     85    def __iter__(self): 
     86        return self._connections.keys() 
     87 
     88    def __getattr__(self, attr): 
     89        return getattr(self._connections, attr) 
     90 
     91    def __getitem__(self, k): 
     92        try: 
     93            return self._connections[k] 
     94        except KeyError: 
     95            try: 
     96                self.connect(k) 
     97                return self._connections[k] 
     98            except KeyError: 
     99                raise ImproperlyConfigured, \ 
     100                      "No database connection '%s' has been configured" % k 
     101 
     102    def __setattr(self, attr, val): 
     103        setattr(self._connections, attr, val) 
     104             
     105    def connect(self, name): 
     106        from django.conf import settings 
     107        try: 
     108            database = settings.DATABASES[name] 
     109            try: 
     110                database.DATABASE_ENGINE 
     111            except AttributeError: 
     112                # assume its a dict and convert to settings instance 
     113                holder = UserSettingsHolder(settings) 
     114                for k, v in database.items(): 
     115                    setattr(holder, k, v) 
     116                    database = holder 
     117                settings.DATABASES[name] = database 
     118            self._connections[name] = connect(database) 
     119        except AttributeError: 
     120            # no named connections to set up 
     121            pass 
     122connections = LazyConnectionManager() 
     123 
    37124# Register an event that resets connection.queries 
    38125# when a Django request is started. 
    39 def reset_queries(): 
     126def reset_queries(connection=connection): 
    40127    connection.queries = [] 
    41128dispatcher.connect(reset_queries, signal=signals.request_started) 
    42129 
     
    46133    from django.db import transaction 
    47134    transaction.rollback_unless_managed() 
    48135dispatcher.connect(_rollback_on_exception, signal=signals.got_request_exception) 
     136 
     137# Register an event that closes the database connection 
     138# when a Django request is finished. 
     139dispatcher.connect(connection.close, signal=signals.request_finished) 
     140 
  • django/db/backends/ado_mssql/creation.py

    old new  
     1from django.db.backends.ansi.creation import SchemaBuilder 
     2 
    13DATA_TYPES = { 
    24    'AutoField':         'int IDENTITY (1, 1)', 
    35    'BooleanField':      'bit', 
     
    2426    'URLField':          'varchar(200)', 
    2527    'USStateField':      'varchar(2)', 
    2628} 
     29 
     30_builder = SchemaBuilder() 
     31get_create_table = _builder.get_create_table 
     32get_create_indexes = _builder.get_create_indexes 
     33get_create_many_to_many = _builder.get_create_many_to_many 
     34get_initialdata = _builder.get_initialdata 
  • django/db/backends/postgresql/base.py

    old new  
    2121    from django.utils._threading_local import local 
    2222 
    2323class DatabaseWrapper(local): 
    24     def __init__(self): 
     24    def __init__(self, settings): 
     25        self.settings = settings 
    2526        self.connection = None 
    2627        self.queries = [] 
    2728 
    2829    def cursor(self): 
    29         from django.conf import settings 
     30        settings = self.settings 
    3031        if self.connection is None: 
    3132            if settings.DATABASE_NAME == '': 
    3233                from django.core.exceptions import ImproperlyConfigured 
  • django/db/backends/postgresql/creation.py

    old new  
     1from django.db.backends.ansi.creation import SchemaBuilder 
     2 
    13# This dictionary maps Field objects to their associated PostgreSQL column 
    24# types, as strings. Column-type strings can contain format strings; they'll 
    35# be interpolated against the values of Field.__dict__ before being output. 
     
    2830    'URLField':          'varchar(200)', 
    2931    'USStateField':      'varchar(2)', 
    3032} 
     33 
     34_builder = SchemaBuilder() 
     35get_create_table = _builder.get_create_table 
     36get_create_indexes = _builder.get_create_indexes 
     37get_create_many_to_many = _builder.get_create_many_to_many 
     38get_initialdata = _builder.get_initialdata 
  • django/db/backends/sqlite3/base.py

    old new  
    3434    from django.utils._threading_local import local 
    3535 
    3636class DatabaseWrapper(local): 
    37     def __init__(self): 
     37    def __init__(self, settings): 
     38        self.settings = settings 
    3839        self.connection = None 
    3940        self.queries = [] 
    4041 
    4142    def cursor(self): 
    42         from django.conf import settings 
     43        settings = self.settings 
    4344        if self.connection is None: 
    4445            self.connection = Database.connect(settings.DATABASE_NAME, 
    4546                detect_types=Database.PARSE_DECLTYPES | Database.PARSE_COLNAMES) 
  • django/db/backends/sqlite3/creation.py

    old new  
     1from django.db.backends.ansi.creation import SchemaBuilder 
     2 
    13# SQLite doesn't actually support most of these types, but it "does the right 
    24# thing" given more verbose field definitions, so leave them as is so that 
    35# schema inspection is more useful. 
     
    2729    'URLField':                     'varchar(200)', 
    2830    'USStateField':                 'varchar(2)', 
    2931} 
     32 
     33_builder = SchemaBuilder() 
     34get_create_table = _builder.get_create_table 
     35get_create_indexes = _builder.get_create_indexes 
     36get_create_many_to_many = _builder.get_create_many_to_many 
     37get_initialdata = _builder.get_initialdata 
  • django/db/backends/mysql/creation.py

    old new  
     1from django.db.backends.ansi.creation import SchemaBuilder 
     2 
    13# This dictionary maps Field objects to their associated MySQL column 
    24# types, as strings. Column-type strings can contain format strings; they'll 
    35# be interpolated against the values of Field.__dict__ before being output. 
     
    2830    'URLField':          'varchar(200)', 
    2931    'USStateField':      'varchar(2)', 
    3032} 
     33 
     34_builder = SchemaBuilder() 
     35get_create_table = _builder.get_create_table 
     36get_create_indexes = _builder.get_create_indexes 
     37get_create_many_to_many = _builder.get_create_many_to_many 
     38get_initialdata = _builder.get_initialdata 
  • django/db/backends/oracle/creation.py

    old new  
     1from django.db.backends.ansi.creation import SchemaBuilder 
     2 
    13DATA_TYPES = { 
    24    'AutoField':         'number(38)', 
    35    'BooleanField':      'number(1)', 
     
    2426    'URLField':          'varchar(200)', 
    2527    'USStateField':      'varchar(2)', 
    2628} 
     29 
     30_builder = SchemaBuilder() 
     31get_create_table = _builder.get_create_table 
     32get_create_indexes = _builder.get_create_indexes 
     33get_create_many_to_many = _builder.get_create_many_to_many 
     34get_initialdata = _builder.get_initialdata 
  • django/db/backends/ansi/__init__.py

    old new  
  • django/db/backends/ansi/creation.py

    old new  
     1"""ANSISQL schema manipulation functions and classes 
     2""" 
     3from django.db import models 
     4 
     5# FIXME correct handling of styles, 
     6# allow style object to be passed in 
     7class dummy: 
     8    def __getattr__(self, attr): 
     9        return lambda x: x 
     10 
     11class BoundStatement(object): 
     12    """Represents an SQL statement that is to be executed, at some point in 
     13    the future, using a specific database connection. 
     14    """ 
     15    def __init__(self, sql, connection): 
     16        self.sql = sql 
     17        self.connection = connection 
     18 
     19    def execute(self): 
     20        cursor = self.connection.cursor() 
     21        cursor.execute(self.sql) 
     22 
     23    def __repr__(self): 
     24        return "BoundStatement(%r)" % self.sql 
     25 
     26    def __str__(self): 
     27        return self.sql 
     28 
     29    def __eq__(self, other): 
     30        return self.sql == other.sql and self.connection == other.connection 
     31 
     32class SchemaBuilder(object): 
     33    """Basic ANSI SQL schema element builder. Instances of this class may be 
     34    used to construct SQL expressions that create or drop schema elements such 
     35    as tables, indexes and (for those backends that support them) foreign key 
     36    or other constraints. 
     37    """ 
     38    def __init__(self): 
     39        self.models_already_seen = [] 
     40         
     41    def get_create_table(self, model, style=dummy()): 
     42        """Construct and return the SQL expression(s) needed to create the 
     43        table for the given model, and any constraints on that 
     44        table. The return value is a 2-tuple. The first element of the tuple 
     45        is a list of BoundStatements that may be executed immediately. The 
     46        second is a list of BoundStatements representing constraints that 
     47        can't be executed immediately because (for instance) the referent 
     48        table does not exist. 
     49        """ 
     50        if model in self.models_already_seen: 
     51            return (None, None, None) 
     52        self.models_already_seen.append(model) 
     53         
     54        opts = model._meta 
     55        info = opts.connection_info 
     56        backend = info.backend 
     57        quote_name = backend.quote_name 
     58        data_types = info.get_creation_module().DATA_TYPES 
     59        table_output = [] 
     60        pending_references = {}  
     61        pending = [] # actual pending statements to execute 
     62        for f in opts.fields: 
     63            if isinstance(f, models.ForeignKey): 
     64                rel_field = f.rel.get_related_field() 
     65                data_type = self.get_rel_data_type(rel_field) 
     66            else: 
     67                rel_field = f 
     68                data_type = f.get_internal_type() 
     69            col_type = data_types[data_type] 
     70            if col_type is not None: 
     71                # Make the definition (e.g. 'foo VARCHAR(30)') for this field. 
     72                field_output = [style.SQL_FIELD(quote_name(f.column)), 
     73                    style.SQL_COLTYPE(col_type % rel_field.__dict__)] 
     74                field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or ''))) 
     75                if f.unique: 
     76                    field_output.append(style.SQL_KEYWORD('UNIQUE')) 
     77                if f.primary_key: 
     78                    field_output.append(style.SQL_KEYWORD('PRIMARY KEY')) 
     79                if f.rel: 
     80                    if f.rel.to in self.models_already_seen: 
     81                        field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \ 
     82                            style.SQL_TABLE(quote_name(f.rel.to._meta.db_table)) + ' (' + \ 
     83                            style.SQL_FIELD(quote_name(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')' 
     84                        ) 
     85                    else: 
     86                        # We haven't yet created the table to which this field 
     87                        # is related, so save it for later. 
     88                        pr = pending_references.setdefault(f.rel.to, []).append(f) 
     89                table_output.append(' '.join(field_output)) 
     90        if opts.order_with_respect_to: 
     91            table_output.append(style.SQL_FIELD(quote_name('_order')) + ' ' + \ 
     92                style.SQL_COLTYPE(data_types['IntegerField']) + ' ' + \ 
     93                style.SQL_KEYWORD('NULL')) 
     94        for field_constraints in opts.unique_together: 
     95            table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \ 
     96                ", ".join([quote_name(style.SQL_FIELD(opts.get_field(f).column)) for f in field_constraints])) 
     97 
     98        full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(quote_name(opts.db_table)) + ' ('] 
     99        for i, line in enumerate(table_output): # Combine and add commas. 
     100            full_statement.append('    %s%s' % (line, i < len(table_output)-1 and ',' or '')) 
     101        full_statement.append(');') 
     102 
     103        create = [BoundStatement('\n'.join(full_statement), opts.connection)] 
     104 
     105        if (pending_references and 
     106            backend.supports_constraints): 
     107            for rel_class, cols in pending_references.items(): 
     108                for f in cols: 
     109                    rel_opts = rel_class._meta 
     110                    r_table = rel_opts.db_table 
     111                    r_col = f.column 
     112                    table = opts.db_table 
     113                    col = opts.get_field(f.rel.field_name).column 
     114                    sql = style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s);' % \ 
     115                        (quote_name(table), 
     116                        quote_name('%s_referencing_%s_%s' % (r_col, r_table, col)), 
     117                        quote_name(r_col), quote_name(r_table), quote_name(col)) 
     118                    pending.append(BoundStatement(sql, opts.connection)) 
     119        return (create, pending)     
     120 
     121    def get_create_indexes(self, model, style=dummy()): 
     122        """Construct and return SQL statements needed to create the indexes for 
     123        a model. Returns a list of BoundStatements. 
     124        """ 
     125        info = model._meta.connection_info 
     126        backend = info.backend 
     127        connection = info.connection 
     128        output = [] 
     129        for f in model._meta.fields: 
     130            if f.db_index: 
     131                unique = f.unique and 'UNIQUE ' or '' 
     132                output.append( 
     133                    BoundStatement( 
     134                        ' '.join( 
     135                            [style.SQL_KEYWORD('CREATE %sINDEX' % unique),  
     136                             style.SQL_TABLE('%s_%s' % 
     137                                             (model._meta.db_table, f.column)), 
     138                             style.SQL_KEYWORD('ON'),  
     139                             style.SQL_TABLE( 
     140                                    backend.quote_name(model._meta.db_table)), 
     141                             "(%s);" % style.SQL_FIELD( 
     142                                    backend.quote_name(f.column))]), 
     143                        connection) 
     144                    ) 
     145        return output 
     146 
     147    def get_create_many_to_many(self, model, style=dummy()): 
     148        """Construct and return SQL statements needed to create the 
     149        tables and relationships for all many-to-many relations 
     150        defined in the model. Returns a list of bound statments. Note 
     151        that these statements should only be execute after all models 
     152        for an app have been created. 
     153        """ 
     154        info = model._meta.connection_info 
     155        backend = info.backend 
     156        connection = info.connection         
     157        data_types = info.get_creation_module().DATA_TYPES 
     158        opts = model._meta 
     159        output = []         
     160        for f in opts.many_to_many: 
     161            if not isinstance(f.rel, models.GenericRel): 
     162                table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \ 
     163                    style.SQL_TABLE(backend.quote_name(f.m2m_db_table())) + ' ('] 
     164                table_output.append('    %s %s %s,' % \ 
     165                    (style.SQL_FIELD(backend.quote_name('id')), 
     166                    style.SQL_COLTYPE(data_types['AutoField']), 
     167                    style.SQL_KEYWORD('NOT NULL PRIMARY KEY'))) 
     168                table_output.append('    %s %s %s %s (%s),' % \ 
     169                    (style.SQL_FIELD(backend.quote_name(f.m2m_column_name())), 
     170                    style.SQL_COLTYPE(data_types[self.get_rel_data_type(opts.pk)] % opts.pk.__dict__), 
     171                    style.SQL_KEYWORD('NOT NULL REFERENCES'), 
     172                    style.SQL_TABLE(backend.quote_name(opts.db_table)), 
     173                    style.SQL_FIELD(backend.quote_name(opts.pk.column)))) 
     174                table_output.append('    %s %s %s %s (%s),' % \ 
     175                    (style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name())), 
     176                    style.SQL_COLTYPE(data_types[self.get_rel_data_type(f.rel.to._meta.pk)] % f.rel.to._meta.pk.__dict__), 
     177                    style.SQL_KEYWORD('NOT NULL REFERENCES'), 
     178                    style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)), 
     179                    style.SQL_FIELD(backend.quote_name(f.rel.to._meta.pk.column)))) 
     180                table_output.append('    %s (%s, %s)' % \ 
     181                    (style.SQL_KEYWORD('UNIQUE'), 
     182                    style.SQL_FIELD(backend.quote_name(f.m2m_column_name())), 
     183                    style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name())))) 
     184                table_output.append(');') 
     185                output.append(BoundStatement('\n'.join(table_output), 
     186                                             connection)) 
     187        return output 
     188 
     189     
     190    def get_initialdata(self, model, style=dummy()): 
     191        return [] # FIXME 
     192 
     193    def get_rel_data_type(self, f): 
     194        return (f.get_internal_type() in ('AutoField', 'PositiveIntegerField', 
     195                                          'PositiveSmallIntegerField')) \ 
     196                                          and 'IntegerField' \ 
     197                                          or f.get_internal_type() 
  • django/db/transaction.py

    old new  
    1616    import thread 
    1717except ImportError: 
    1818    import dummy_thread as thread 
    19 from django.db import connection 
     19from django import db 
    2020from django.conf import settings 
    2121 
    2222class TransactionManagementError(Exception): 
     
    116116    Puts the transaction manager into a manual state: managed transactions have 
    117117    to be committed explicitly by the user. If you switch off transaction 
    118118    management and there is a pending commit/rollback, the data will be 
    119     commited. 
     119    commited. Note that managed state applies across all connections. 
    120120    """ 
    121121    thread_ident = thread.get_ident() 
    122122    top = state.get(thread_ident, None) 
    123123    if top: 
    124124        top[-1] = flag 
    125125        if not flag and is_dirty(): 
    126             connection._commit() 
     126            for cx in all_connections(): 
     127                cx._commit() 
    127128            set_clean() 
    128129    else: 
    129130        raise TransactionManagementError("This code isn't under transaction management") 
    130131 
    131 def commit_unless_managed(): 
     132def commit_unless_managed(connections=None): 
    132133    """ 
    133134    Commits changes if the system is not in managed transaction mode. 
    134135    """ 
    135136    if not is_managed(): 
    136         connection._commit() 
     137        if connections is None: 
     138            connections = all_connections() 
     139        else: 
     140            connections = ensure_connections(connections) 
     141        for cx in connections: 
     142            cx._commit() 
    137143    else: 
    138144        set_dirty() 
    139145 
    140 def rollback_unless_managed(): 
     146def rollback_unless_managed(connections=None): 
    141147    """ 
    142148    Rolls back changes if the system is not in managed transaction mode. 
    143149    """ 
    144150    if not is_managed(): 
    145         connection._rollback() 
     151        if connections is None: 
     152            connections = all_connections() 
     153        for cx in connections: 
     154            cx._rollback() 
    146155    else: 
    147156        set_dirty() 
    148157 
    149 def commit(): 
     158def commit(connections=None): 
    150159    """ 
    151160    Does the commit itself and resets the dirty flag. 
    152161    """ 
    153     connection._commit() 
     162    if connections is None: 
     163        connections = all_connections() 
     164    else:&