Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion baph/core/management/commands/killcache.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from sqlalchemy import *
from sqlalchemy.exc import ResourceClosedError
from sqlalchemy.orm import lazyload, contains_eager, class_mapper
from sqlalchemy.orm.util import identity_key
from sqlalchemy.sql import compiler

from baph.core.management.base import BaseCommand #NoArgsCommand
Expand Down
5 changes: 2 additions & 3 deletions baph/core/management/commands/loaddata.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@
from django.utils.functional import cached_property, memoize
from sqlalchemy.orm.attributes import instance_dict
from sqlalchemy.orm.session import Session
from sqlalchemy.orm.util import identity_key

from baph.core.management.new_base import BaseCommand
from baph.db import DEFAULT_DB_ALIAS
from baph.db.models import get_app_paths
from baph.db.models.utils import identity_key
from baph.db.orm import ORM
from baph.utils.glob import glob_escape

Expand Down Expand Up @@ -228,8 +228,7 @@ def load_label(self, fixture_label):
if True: #router.allow_syncdb(self.using, obj.object.__class__):
loaded_objects_in_fixture += 1
self.models.add(type(obj))
ident = identity_key(instance=obj)
(cls, key) = ident[:2]
(cls, key) = identity_key(instance=obj)
if any(part is None for part in key):
# we can't generate an explicit key with this info
session.add(obj)
Expand Down
2 changes: 1 addition & 1 deletion baph/core/serializers/python.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from django.utils.encoding import smart_text, is_protected_type
from sqlalchemy.orm.util import identity_key

from baph.core.serializers import base
from baph.db import DEFAULT_DB_ALIAS
from baph.db.models import get_apps
from baph.db.models.utils import identity_key
from baph.db.orm import Base


Expand Down
8 changes: 3 additions & 5 deletions baph/db/models/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@
from sqlalchemy.orm.interfaces import MANYTOONE
from sqlalchemy.orm.properties import ColumnProperty, RelationshipProperty
from sqlalchemy.orm.session import Session
from sqlalchemy.orm.util import has_identity, identity_key
from sqlalchemy.orm.util import has_identity
from sqlalchemy.schema import ForeignKeyConstraint

from baph.db import ORM
from baph.db.models import signals
from baph.db.models.loading import get_model, register_models
from baph.db.models.mixins import CacheMixin, GlobalMixin, ModelPermissionMixin
from baph.db.models.options import Options
from baph.db.models.utils import key_to_value
from baph.db.models.utils import key_to_value, identity_key
from baph.utils.functional import cachedclassproperty
from baph.utils.importing import remove_class
from baph.utils.module_loading import import_string
Expand Down Expand Up @@ -150,9 +150,7 @@ def before_flush_attrs(cls):
def pk_as_query_filters(self, force=False):
" returns a filter expression for the primary key of the instance "
" suitable for use with Query.filter() "
ident = identity_key(instance=self)
(cls, pk_values) = ident[:2]

(cls, pk_values) = identity_key(instance=self)
if None in pk_values and not force:
return None
items = zip(self.pk_attrs, pk_values)
Expand Down
24 changes: 15 additions & 9 deletions baph/db/models/cloning.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import copy

from sqlalchemy import inspect
from sqlalchemy import inspect, Column
from sqlalchemy.orm import class_mapper
from sqlalchemy.orm.attributes import instance_dict
from sqlalchemy.orm.collections import MappedCollection
from sqlalchemy.orm.properties import ColumnProperty, RelationshipProperty
from sqlalchemy.orm.session import object_session
from sqlalchemy.orm.util import identity_key

from baph.db.models.utils import identity_key
from baph.db.orm import ORM
from baph.utils.collections import duck_type_collection

Expand All @@ -19,7 +19,7 @@ def reload_object(instance):
"""
Reloads an instance with the correct polymorphic subclass
"""
cls, pk_vals = identity_key(instance=instance)
(cls, pk_vals) = identity_key(instance=instance)
mapper = inspect(cls)
pk_cols = [col.key for col in mapper.primary_key]
pk = dict(zip(pk_cols, pk_vals))
Expand All @@ -38,7 +38,7 @@ def get_polymorphic_subclass(instance):
the polymorphic map of the base class. for non-polymorphic classes, it
returns the class
"""
cls, pk = identity_key(instance=instance)
(cls, pk) = identity_key(instance=instance)
base_mapper = inspect(cls)
if base_mapper.polymorphic_on is None:
# this is not a polymorphic class
Expand All @@ -65,11 +65,18 @@ def get_cloning_rules(cls):

def get_default_excludes(cls):
"""
By default, exclude pks and fks
By default, exclude pks, fks, and query_expressions
"""
mapper = inspect(cls)
exclude_props = set()
exclude_cols = set()

for attr in mapper.column_attrs:
# exclude column properties which do not refer to actual columns
# ie query_expressions
if not any(isinstance(col, Column) for col in attr.columns):
exclude_props.add(attr.key)

if mapper.polymorphic_on is not None:
# do not copy the polymorphic discriminator. it will be set automatically
# via the polymorphic class, and we don't want to generate flush warnings
Expand All @@ -86,7 +93,7 @@ def get_default_excludes(cls):

props = map(mapper.get_property_by_column, exclude_cols)
keys = set(prop.key for prop in props)
return keys
return exclude_props | keys

def get_default_columns(cls):
"""
Expand Down Expand Up @@ -148,7 +155,7 @@ def get_rules(rules, rule_keys):
def user_id(self):
if not self.user:
return None
cls, pk = identity_key(instance=self.user)
(cls, pk) = identity_key(instance=self.user)
if len(pk) > 1:
raise Exception('chown cannot used for multi-column user pks. To '
'specify ownership for a user with a multi-column pk, add the '
Expand Down Expand Up @@ -218,8 +225,7 @@ def clone_collection(self, value, **kwargs):

def clone_obj(self, instance, ruleset=None, rule_keys=None, cast_to=None):
is_root = self.root is None

base_cls, pk = identity_key(instance=instance)
(base_cls, pk) = identity_key(instance=instance)
if (base_cls, pk) in self.registry:
# we already cloned this
return self.registry[(base_cls, pk)]
Expand Down
6 changes: 3 additions & 3 deletions baph/db/models/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@
from sqlalchemy.orm import class_mapper, object_session
from sqlalchemy.orm.attributes import get_history, instance_dict
from sqlalchemy.orm.properties import ColumnProperty, RelationshipProperty
from sqlalchemy.orm.util import has_identity, identity_key
from sqlalchemy.orm.util import has_identity

from baph.db import ORM
from baph.db.models.utils import identity_key
from .utils import column_to_attr, class_resolver


Expand Down Expand Up @@ -611,8 +612,7 @@ def get_cache_keys(self, child_updated=False, force_expire_pointers=False,
# the fields which trigger this pointer were not changed
continue
cache_key = raw_key % data
ident_key = identity_key(instance=self)
_, ident = ident_key[:2]
(_, ident) = identity_key(instance=self)
if len(ident) > 1:
ident = ','.join(map(str, ident))
else:
Expand Down
5 changes: 5 additions & 0 deletions baph/db/models/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@

from sqlalchemy import inspect
from sqlalchemy.ext.declarative.clsregistry import _class_resolver
from sqlalchemy.orm.util import identity_key as new_identity_key


def identity_key(*args, **kwargs):
""" returns a 2-tuple identity key, not the 3-tuple in newer SQLA """
return new_identity_key(*args, **kwargs)[:2]

def has_inherited_table(cls):
# TODO: a fix in sqla 0.9 should make this unnecessary, check it
"""
Expand Down
67 changes: 35 additions & 32 deletions baph/forms/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,17 +77,17 @@ def model_to_dict(instance, fields=None, exclude=None):
data = {}
unloaded_attrs = inspect(instance).unloaded
for f in opts.fields:
if f.name in unloaded_attrs:
if issubclass(f.data_type, orm.Base):
# skip relations that haven't been loaded yet
continue
if not getattr(f, 'editable', False):
continue
if fields and not f.name in fields:
continue
if exclude and f.name in exclude:
continue
data[f.name] = getattr(instance, f.name)
if f.name in unloaded_attrs:
if issubclass(f.data_type, orm.Base):
# skip relations that haven't been loaded yet
continue
if not getattr(f, 'editable', False):
continue
if fields and not f.name in fields:
continue
if exclude and f.name in exclude:
continue
data[f.name] = getattr(instance, f.name)
return data

def fields_for_model(model, fields=None, exclude=None, widgets=None,
Expand All @@ -109,13 +109,13 @@ def fields_for_model(model, fields=None, exclude=None, widgets=None,
continue

if issubclass(f.data_type, Base):
# TODO: Auto-generate fields, control via 'fields' param
if fields is not None and f.name in fields:
# manually included field
pass
else:
# skip relations unless manually requested
continue
# TODO: Auto-generate fields, control via 'fields' param
if fields is not None and f.name in fields:
# manually included field
pass
else:
# skip relations unless manually requested
continue

kwargs = {}
if widgets and f.name in widgets:
Expand Down Expand Up @@ -200,13 +200,15 @@ def __new__(cls, name, bases, attrs):
except NameError:
parents = None
declared_fields = forms.forms.get_declared_fields(bases, attrs, False)

new_class = super(SQLAModelFormMetaclass, cls) \
.__new__(cls, name, bases, attrs)
if not parents:
return new_class

if 'media' not in attrs:
new_class.media = forms.widgets.media_property(new_class)

opts = new_class._meta = SQLAModelFormOptions(getattr(new_class, 'Meta', None))
if opts.model:
# If a model is defined, extract form fields from it.
Expand All @@ -227,30 +229,31 @@ def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
opts = self._meta
exclude = list(opts.exclude)
if opts.model is None:
raise ValueError('ModelForm has no model class specified.')
raise ValueError('ModelForm has no model class specified.')
self.nested = nested
if self.nested:
exclude.extend(opts.exclude_on_nested)
exclude.extend(opts.exclude_on_nested)
if instance is None:
exclude.extend(opts.exclude_on_create)
self.instance = opts.model()
object_data = {}
exclude.extend(opts.exclude_on_create)
self.instance = opts.model()
object_data = {}
else:
self.instance = instance
object_data = model_to_dict(instance, opts.fields, exclude)
if has_identity(instance):
exclude.extend(opts.exclude_on_update)
else:
exclude.extend(opts.exclude_on_create)
self.instance = instance
object_data = model_to_dict(instance, opts.fields, exclude)
if has_identity(instance):
exclude.extend(opts.exclude_on_update)
else:
exclude.extend(opts.exclude_on_create)

if initial is not None:
object_data.update(initial)
object_data.update(initial)
object_data.update(data)

super(BaseSQLAModelForm, self).__init__(object_data, files, auto_id, prefix)

for k in exclude:
if k in self.fields:
del self.fields[k]
if k in self.fields:
del self.fields[k]

def save(self, commit=False):
"""
Expand Down
2 changes: 1 addition & 1 deletion baph/test/cloning.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
from sqlalchemy import inspect
from sqlalchemy.ext.associationproxy import ASSOCIATION_PROXY
from sqlalchemy.ext.orderinglist import OrderingList
from sqlalchemy.orm.util import identity_key

from baph.db.models.cloning import *
from baph.db.models.utils import identity_key
from baph.utils.collections import duck_type_collection


Expand Down