def __setattr__(cls, key, value): if '__mapper__' in cls.__dict__: if isinstance(value, Column): _undefer_column_name(key, value) cls.__table__.append_column(value) cls.__mapper__.add_property(key, value) elif isinstance(value, ColumnProperty): for col in value.columns: if isinstance(col, Column) and col.table is None: _undefer_column_name(key, col) cls.__table__.append_column(col) cls.__mapper__.add_property(key, value) elif isinstance(value, MapperProperty): cls.__mapper__.add_property( key, _deferred_relationship(cls, value) ) else: type.__setattr__(cls, key, value) else: type.__setattr__(cls, key, value)
def _as_declarative(cls, classname, dict_): cls._decl_class_registry[classname] = cls # this sets up our_stuff which reads in the attributes and converts # them to SA columns, etc... our_stuff = util.OrderedDict() # just here to handle SA declarative, not needed for Django for k in dict_: value = dict_[k] if (isinstance(value, tuple) and len(value) == 1 and isinstance(value[0], (Column, MapperProperty))): util.warn("Ignoring declarative-like tuple value of attribute " "%s: possibly a copy-and-paste error with a comma " "left at the end of the line?" % k) continue if not isinstance(value, (Column, MapperProperty)): continue prop = _deferred_relation(cls, value) our_stuff[k] = prop # Django will *always* have set the pk before we get here. Check if # it is a Django AutoField so we can override it with our own. This # will allow for a custom primary key to just work. if isinstance(cls._meta.pk, AutoField): # we need to add in the django-sqlalchemy version of the AutoField # because the one that Django adds will not work for our purposes. auto_field = DSAutoField(verbose_name='ID', primary_key=True, auto_created=True) # this might seem redundant but without it the name is not set # for SA auto_field.name = "id" # Call set_attributes_from_name as it normally only gets called # during Django's metaclass. auto_field.set_attributes_from_name(auto_field.name) # HACK: we need to force the use of our AutoField over Django's # AutoField. cls._meta.pk = auto_field for i, field in enumerate(cls._meta.fields): if isinstance(field, AutoField): cls._meta.fields[i] = auto_field for field in cls._meta.fields + cls._meta.many_to_many: sa_field = field.create_column() # A ManyToManyField will return None for the column as it does # not need a column. if sa_field is not None: # this allows us to build up more complex structures if isinstance(sa_field, dict): our_stuff.update(sa_field) else: our_stuff[sa_field.name] = sa_field # set up attributes in the order they were created our_stuff.sort(lambda x, y: cmp(our_stuff[x]._creation_order, our_stuff[y]._creation_order)) table = None tablename = cls._meta.db_table # this is to support SA's declarative to support declaring a Table if '__table__' not in cls.__dict__: # this is just to support SA's declarative of allowing the # specification of the table name using this syntax if '__tablename__' in cls.__dict__: tablename = cls.__tablename__ # SA supports autoloading the model from database, but that will # not work for Django. We're leaving this here just for future # consideration. autoload = cls.__dict__.get('__autoload__') if autoload: table_kw = {'autoload': True} else: table_kw = {} # this allows us to pick up only the Column types for our table # definition. cols = [] for key, c in our_stuff.iteritems(): if isinstance(c, ColumnProperty): for col in c.columns: if isinstance(col, Column) and col.table is None: _undefer_column_name(key, col) cols.append(col) elif isinstance(c, Column): _undefer_column_name(key, c) cols.append(c) cls.__table__ = table = Table(tablename, cls.metadata, *cols, **table_kw) else: table = cls.__table__ mapper_args = getattr(cls, '__mapper_args__', {}) if 'inherits' not in mapper_args: inherits = cls.__mro__[1] inherits = cls._decl_class_registry.get(inherits.__name__, None) if inherits: mapper_args['inherits'] = inherits if not mapper_args.get('concrete', False) and table: # figure out the inherit condition with relaxed rules # about nonexistent tables, to allow for ForeignKeys to # not-yet-defined tables (since we know for sure that our # parent table is defined within the same MetaData) mapper_args['inherit_condition'] = sql_util.join_condition( inherits.__table__, table, ignore_nonexistent_tables=True) # declarative allows you to specify a mapper as well if hasattr(cls, '__mapper_cls__'): mapper_cls = util.unbound_method_to_callable(cls.__mapper_cls__) else: mapper_cls = mapper cls.__mapper__ = mapper_cls(cls, table, properties=our_stuff, **mapper_args) cls.query = session.query_property()