Example #1
0
 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)
Example #2
0
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()