|
@@ -67,9 +67,19 @@ class ModelBase(type):
|
|
|
if not hasattr(meta, 'get_latest_by'):
|
|
|
new_class._meta.get_latest_by = base_meta.get_latest_by
|
|
|
|
|
|
+ is_proxy = new_class._meta.proxy
|
|
|
+
|
|
|
if getattr(new_class, '_default_manager', None):
|
|
|
- new_class._default_manager = None
|
|
|
- new_class._base_manager = None
|
|
|
+ if not is_proxy:
|
|
|
+
|
|
|
+
|
|
|
+ new_class._default_manager = None
|
|
|
+ new_class._base_manager = None
|
|
|
+ else:
|
|
|
+
|
|
|
+
|
|
|
+ new_class._default_manager = new_class._default_manager._copy_to_model(new_class)
|
|
|
+ new_class._base_manager = new_class._base_manager._copy_to_model(new_class)
|
|
|
|
|
|
|
|
|
m = get_model(new_class._meta.app_label, name, False)
|
|
@@ -80,21 +90,43 @@ class ModelBase(type):
|
|
|
for obj_name, obj in attrs.items():
|
|
|
new_class.add_to_class(obj_name, obj)
|
|
|
|
|
|
+
|
|
|
+ new_fields = new_class._meta.local_fields + \
|
|
|
+ new_class._meta.local_many_to_many + \
|
|
|
+ new_class._meta.virtual_fields
|
|
|
+ field_names = set([f.name for f in new_fields])
|
|
|
+
|
|
|
+
|
|
|
+ if is_proxy:
|
|
|
+ base = None
|
|
|
+ for parent in [cls for cls in parents if hasattr(cls, '_meta')]:
|
|
|
+ if parent._meta.abstract:
|
|
|
+ if parent._meta.fields:
|
|
|
+ raise TypeError("Abstract base class containing model fields not permitted for proxy model '%s'." % name)
|
|
|
+ else:
|
|
|
+ continue
|
|
|
+ if base is not None:
|
|
|
+ raise TypeError("Proxy model '%s' has more than one non-abstract model base class." % name)
|
|
|
+ else:
|
|
|
+ base = parent
|
|
|
+ if base is None:
|
|
|
+ raise TypeError("Proxy model '%s' has no non-abstract model base class." % name)
|
|
|
+ if (new_class._meta.local_fields or
|
|
|
+ new_class._meta.local_many_to_many):
|
|
|
+ raise FieldError("Proxy model '%s' contains model fields."
|
|
|
+ % name)
|
|
|
+ new_class._meta.setup_proxy(base)
|
|
|
+
|
|
|
|
|
|
o2o_map = dict([(f.rel.to, f) for f in new_class._meta.local_fields
|
|
|
if isinstance(f, OneToOneField)])
|
|
|
+
|
|
|
for base in parents:
|
|
|
if not hasattr(base, '_meta'):
|
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
|
-
|
|
|
- new_fields = new_class._meta.local_fields + \
|
|
|
- new_class._meta.local_many_to_many + \
|
|
|
- new_class._meta.virtual_fields
|
|
|
- field_names = set([f.name for f in new_fields])
|
|
|
-
|
|
|
parent_fields = base._meta.local_fields + base._meta.local_many_to_many
|
|
|
|
|
|
|
|
@@ -107,15 +139,19 @@ class ModelBase(type):
|
|
|
(field.name, name, base.__name__))
|
|
|
if not base._meta.abstract:
|
|
|
|
|
|
+ while base._meta.proxy:
|
|
|
+
|
|
|
+ base = base._meta.proxy_for_model
|
|
|
if base in o2o_map:
|
|
|
field = o2o_map[base]
|
|
|
- else:
|
|
|
+ elif not is_proxy:
|
|
|
attr_name = '%s_ptr' % base._meta.module_name
|
|
|
field = OneToOneField(base, name=attr_name,
|
|
|
auto_created=True, parent_link=True)
|
|
|
new_class.add_to_class(attr_name, field)
|
|
|
+ else:
|
|
|
+ field = None
|
|
|
new_class._meta.parents[base] = field
|
|
|
-
|
|
|
else:
|
|
|
|
|
|
for field in parent_fields:
|
|
@@ -125,13 +161,12 @@ class ModelBase(type):
|
|
|
new_class._meta.parents.update(base._meta.parents)
|
|
|
|
|
|
|
|
|
- base_managers = base._meta.abstract_managers
|
|
|
- base_managers.sort()
|
|
|
- for _, mgr_name, manager in base_managers:
|
|
|
- val = getattr(new_class, mgr_name, None)
|
|
|
- if not val or val is manager:
|
|
|
- new_manager = manager._copy_to_model(new_class)
|
|
|
- new_class.add_to_class(mgr_name, new_manager)
|
|
|
+ new_class.copy_managers(base._meta.abstract_managers)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if is_proxy:
|
|
|
+ new_class.copy_managers(base._meta.concrete_managers)
|
|
|
|
|
|
|
|
|
|
|
@@ -160,6 +195,15 @@ class ModelBase(type):
|
|
|
|
|
|
return get_model(new_class._meta.app_label, name, False)
|
|
|
|
|
|
+ def copy_managers(cls, base_managers):
|
|
|
+
|
|
|
+ base_managers.sort()
|
|
|
+ for _, mgr_name, manager in base_managers:
|
|
|
+ val = getattr(cls, mgr_name, None)
|
|
|
+ if not val or val is manager:
|
|
|
+ new_manager = manager._copy_to_model(cls)
|
|
|
+ cls.add_to_class(mgr_name, new_manager)
|
|
|
+
|
|
|
def add_to_class(cls, name, value):
|
|
|
if hasattr(value, 'contribute_to_class'):
|
|
|
value.contribute_to_class(cls, name)
|
|
@@ -358,55 +402,59 @@ class Model(object):
|
|
|
|
|
|
|
|
|
|
|
|
- if getattr(self, parent._meta.pk.attname) is None and getattr(self, field.attname) is not None:
|
|
|
+ if field and getattr(self, parent._meta.pk.attname) is None and getattr(self, field.attname) is not None:
|
|
|
setattr(self, parent._meta.pk.attname, getattr(self, field.attname))
|
|
|
|
|
|
- self.save_base(raw, parent)
|
|
|
- setattr(self, field.attname, self._get_pk_val(parent._meta))
|
|
|
-
|
|
|
- non_pks = [f for f in meta.local_fields if not f.primary_key]
|
|
|
-
|
|
|
-
|
|
|
- pk_val = self._get_pk_val(meta)
|
|
|
- pk_set = pk_val is not None
|
|
|
- record_exists = True
|
|
|
- manager = cls._base_manager
|
|
|
- if pk_set:
|
|
|
-
|
|
|
- if (force_update or (not force_insert and
|
|
|
- manager.filter(pk=pk_val).extra(select={'a': 1}).values('a').order_by())):
|
|
|
-
|
|
|
- if force_update or non_pks:
|
|
|
- values = [(f, None, (raw and getattr(self, f.attname) or f.pre_save(self, False))) for f in non_pks]
|
|
|
- rows = manager.filter(pk=pk_val)._update(values)
|
|
|
- if force_update and not rows:
|
|
|
- raise DatabaseError("Forced update did not affect any rows.")
|
|
|
- else:
|
|
|
- record_exists = False
|
|
|
- if not pk_set or not record_exists:
|
|
|
- if not pk_set:
|
|
|
- if force_update:
|
|
|
- raise ValueError("Cannot force an update in save() with no primary key.")
|
|
|
- values = [(f, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True))) for f in meta.local_fields if not isinstance(f, AutoField)]
|
|
|
- else:
|
|
|
- values = [(f, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True))) for f in meta.local_fields]
|
|
|
+ self.save_base(cls=parent)
|
|
|
+ if field:
|
|
|
+ setattr(self, field.attname, self._get_pk_val(parent._meta))
|
|
|
+ if meta.proxy:
|
|
|
+ return
|
|
|
+
|
|
|
+ if not meta.proxy:
|
|
|
+ non_pks = [f for f in meta.local_fields if not f.primary_key]
|
|
|
+
|
|
|
+
|
|
|
+ pk_val = self._get_pk_val(meta)
|
|
|
+ pk_set = pk_val is not None
|
|
|
+ record_exists = True
|
|
|
+ manager = cls._base_manager
|
|
|
+ if pk_set:
|
|
|
+
|
|
|
+ if (force_update or (not force_insert and
|
|
|
+ manager.filter(pk=pk_val).extra(select={'a': 1}).values('a').order_by())):
|
|
|
+
|
|
|
+ if force_update or non_pks:
|
|
|
+ values = [(f, None, (raw and getattr(self, f.attname) or f.pre_save(self, False))) for f in non_pks]
|
|
|
+ rows = manager.filter(pk=pk_val)._update(values)
|
|
|
+ if force_update and not rows:
|
|
|
+ raise DatabaseError("Forced update did not affect any rows.")
|
|
|
+ else:
|
|
|
+ record_exists = False
|
|
|
+ if not pk_set or not record_exists:
|
|
|
+ if not pk_set:
|
|
|
+ if force_update:
|
|
|
+ raise ValueError("Cannot force an update in save() with no primary key.")
|
|
|
+ values = [(f, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True))) for f in meta.local_fields if not isinstance(f, AutoField)]
|
|
|
+ else:
|
|
|
+ values = [(f, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True))) for f in meta.local_fields]
|
|
|
|
|
|
- if meta.order_with_respect_to:
|
|
|
- field = meta.order_with_respect_to
|
|
|
- values.append((meta.get_field_by_name('_order')[0], manager.filter(**{field.name: getattr(self, field.attname)}).count()))
|
|
|
- record_exists = False
|
|
|
+ if meta.order_with_respect_to:
|
|
|
+ field = meta.order_with_respect_to
|
|
|
+ values.append((meta.get_field_by_name('_order')[0], manager.filter(**{field.name: getattr(self, field.attname)}).count()))
|
|
|
+ record_exists = False
|
|
|
|
|
|
- update_pk = bool(meta.has_auto_field and not pk_set)
|
|
|
- if values:
|
|
|
-
|
|
|
- result = manager._insert(values, return_id=update_pk)
|
|
|
- else:
|
|
|
-
|
|
|
- result = manager._insert([(meta.pk, connection.ops.pk_default_value())], return_id=update_pk, raw_values=True)
|
|
|
+ update_pk = bool(meta.has_auto_field and not pk_set)
|
|
|
+ if values:
|
|
|
+
|
|
|
+ result = manager._insert(values, return_id=update_pk)
|
|
|
+ else:
|
|
|
+
|
|
|
+ result = manager._insert([(meta.pk, connection.ops.pk_default_value())], return_id=update_pk, raw_values=True)
|
|
|
|
|
|
- if update_pk:
|
|
|
- setattr(self, meta.pk.attname, result)
|
|
|
- transaction.commit_unless_managed()
|
|
|
+ if update_pk:
|
|
|
+ setattr(self, meta.pk.attname, result)
|
|
|
+ transaction.commit_unless_managed()
|
|
|
|
|
|
if signal:
|
|
|
signals.post_save.send(sender=self.__class__, instance=self,
|