mirror of
https://github.com/django/django.git
synced 2025-11-19 11:15:44 +00:00
Fixed #27380 -- Added "raw" argument to m2m_changed signals.
This commit is contained in:
parent
5e6ba7368c
commit
47f8206609
7 changed files with 166 additions and 16 deletions
|
|
@ -262,11 +262,11 @@ class DeserializedObject:
|
|||
def save(self, save_m2m=True, using=None, **kwargs):
|
||||
# Call save on the Model baseclass directly. This bypasses any
|
||||
# model-defined save. The save is also forced to be raw.
|
||||
# raw=True is passed to any pre/post_save signals.
|
||||
# raw=True is passed to any pre/post_save and m2m_changed signals.
|
||||
models.Model.save_base(self.object, using=using, raw=True, **kwargs)
|
||||
if self.m2m_data and save_m2m:
|
||||
for accessor_name, object_list in self.m2m_data.items():
|
||||
getattr(self.object, accessor_name).set(object_list)
|
||||
getattr(self.object, accessor_name).set_base(object_list, raw=True)
|
||||
|
||||
# prevent a second (possibly accidental) call to save() from saving
|
||||
# the m2m data twice.
|
||||
|
|
|
|||
|
|
@ -1262,7 +1262,7 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
|
|||
else:
|
||||
return super().count()
|
||||
|
||||
def _add_base(self, *objs, through_defaults=None, using=None):
|
||||
def _add_base(self, *objs, through_defaults=None, using=None, raw=False):
|
||||
db = using or router.db_for_write(self.through, instance=self.instance)
|
||||
with transaction.atomic(using=db, savepoint=False):
|
||||
self._add_items(
|
||||
|
|
@ -1271,6 +1271,7 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
|
|||
*objs,
|
||||
through_defaults=through_defaults,
|
||||
using=db,
|
||||
raw=raw,
|
||||
)
|
||||
# If this is a symmetrical m2m relation to self, add the mirror
|
||||
# entry in the m2m table.
|
||||
|
|
@ -1281,6 +1282,7 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
|
|||
*objs,
|
||||
through_defaults=through_defaults,
|
||||
using=db,
|
||||
raw=raw,
|
||||
)
|
||||
|
||||
def add(self, *objs, through_defaults=None):
|
||||
|
|
@ -1297,10 +1299,10 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
|
|||
|
||||
aadd.alters_data = True
|
||||
|
||||
def _remove_base(self, *objs, using=None):
|
||||
def _remove_base(self, *objs, using=None, raw=False):
|
||||
db = using or router.db_for_write(self.through, instance=self.instance)
|
||||
self._remove_items(
|
||||
self.source_field_name, self.target_field_name, *objs, using=db
|
||||
self.source_field_name, self.target_field_name, *objs, using=db, raw=raw
|
||||
)
|
||||
|
||||
def remove(self, *objs):
|
||||
|
|
@ -1315,7 +1317,7 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
|
|||
|
||||
aremove.alters_data = True
|
||||
|
||||
def _clear_base(self, using=None):
|
||||
def _clear_base(self, using=None, raw=False):
|
||||
db = using or router.db_for_write(self.through, instance=self.instance)
|
||||
with transaction.atomic(using=db, savepoint=False):
|
||||
signals.m2m_changed.send(
|
||||
|
|
@ -1326,6 +1328,7 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
|
|||
model=self.model,
|
||||
pk_set=None,
|
||||
using=db,
|
||||
raw=raw,
|
||||
)
|
||||
filters = self._build_remove_filters(super().get_queryset().using(db))
|
||||
self.through._default_manager.using(db).filter(filters).delete()
|
||||
|
|
@ -1338,6 +1341,7 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
|
|||
model=self.model,
|
||||
pk_set=None,
|
||||
using=db,
|
||||
raw=raw,
|
||||
)
|
||||
|
||||
def clear(self):
|
||||
|
|
@ -1352,7 +1356,7 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
|
|||
|
||||
aclear.alters_data = True
|
||||
|
||||
def set_base(self, objs, *, clear=False, through_defaults=None):
|
||||
def set_base(self, objs, *, clear=False, through_defaults=None, raw=False):
|
||||
# Force evaluation of `objs` in case it's a queryset whose value
|
||||
# could be affected by `manager.clear()`. Refs #19816.
|
||||
objs = tuple(objs)
|
||||
|
|
@ -1361,8 +1365,10 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
|
|||
with transaction.atomic(using=db, savepoint=False):
|
||||
self._remove_prefetched_objects()
|
||||
if clear:
|
||||
self._clear_base(using=db)
|
||||
self._add_base(*objs, through_defaults=through_defaults, using=db)
|
||||
self._clear_base(using=db, raw=raw)
|
||||
self._add_base(
|
||||
*objs, through_defaults=through_defaults, using=db, raw=raw
|
||||
)
|
||||
else:
|
||||
old_ids = set(
|
||||
self.using(db).values_list(
|
||||
|
|
@ -1382,9 +1388,9 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
|
|||
else:
|
||||
new_objs.append(obj)
|
||||
|
||||
self._remove_base(*old_ids, using=db)
|
||||
self._remove_base(*old_ids, using=db, raw=raw)
|
||||
self._add_base(
|
||||
*new_objs, through_defaults=through_defaults, using=db
|
||||
*new_objs, through_defaults=through_defaults, using=db, raw=raw
|
||||
)
|
||||
|
||||
def set(self, objs, *, clear=False, through_defaults=None):
|
||||
|
|
@ -1545,6 +1551,7 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
|
|||
*objs,
|
||||
through_defaults=None,
|
||||
using=None,
|
||||
raw=False,
|
||||
):
|
||||
# source_field_name: the PK fieldname in join table for the source
|
||||
# object target_field_name: the PK fieldname in join table for the
|
||||
|
|
@ -1587,6 +1594,7 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
|
|||
model=self.model,
|
||||
pk_set=missing_target_ids,
|
||||
using=db,
|
||||
raw=raw,
|
||||
)
|
||||
# Add the ones that aren't there already.
|
||||
self.through._default_manager.using(db).bulk_create(
|
||||
|
|
@ -1612,10 +1620,11 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
|
|||
model=self.model,
|
||||
pk_set=missing_target_ids,
|
||||
using=db,
|
||||
raw=raw,
|
||||
)
|
||||
|
||||
def _remove_items(
|
||||
self, source_field_name, target_field_name, *objs, using=None
|
||||
self, source_field_name, target_field_name, *objs, using=None, raw=False
|
||||
):
|
||||
# source_field_name: the PK colname in join table for the source
|
||||
# object target_field_name: the PK colname in join table for the
|
||||
|
|
@ -1644,6 +1653,7 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
|
|||
model=self.model,
|
||||
pk_set=old_ids,
|
||||
using=db,
|
||||
raw=raw,
|
||||
)
|
||||
target_model_qs = super().get_queryset()
|
||||
if target_model_qs._has_filters():
|
||||
|
|
@ -1663,6 +1673,7 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
|
|||
model=self.model,
|
||||
pk_set=old_ids,
|
||||
using=db,
|
||||
raw=raw,
|
||||
)
|
||||
|
||||
return ManyRelatedManager
|
||||
|
|
|
|||
|
|
@ -303,6 +303,15 @@ Arguments sent with this signal:
|
|||
``using``
|
||||
The database alias being used.
|
||||
|
||||
``raw``
|
||||
|
||||
.. versionadded:: 6.1
|
||||
|
||||
A boolean; ``True`` if the model is saved exactly as presented
|
||||
(i.e. when loading a :ref:`fixture <fixtures-explanation>`). One should not
|
||||
query/modify other records in the database as the database might not be in
|
||||
a consistent state yet.
|
||||
|
||||
For example, if a ``Pizza`` can have multiple ``Topping`` objects, modeled
|
||||
like this::
|
||||
|
||||
|
|
|
|||
|
|
@ -225,7 +225,9 @@ Logging
|
|||
Management Commands
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* ...
|
||||
* The :djadmin:`loaddata` command now calls
|
||||
:data:`~django.db.models.signals.m2m_changed` signals with ``raw=True`` when
|
||||
loading fixtures.
|
||||
|
||||
Migrations
|
||||
~~~~~~~~~~
|
||||
|
|
|
|||
|
|
@ -118,8 +118,9 @@ How fixtures are saved to the database
|
|||
|
||||
When fixture files are processed, the data is saved to the database as is.
|
||||
Model defined :meth:`~django.db.models.Model.save` methods are not called, and
|
||||
any :data:`~django.db.models.signals.pre_save` or
|
||||
:data:`~django.db.models.signals.post_save` signals will be called with
|
||||
any :data:`~django.db.models.signals.pre_save`,
|
||||
:data:`~django.db.models.signals.post_save`, or
|
||||
:data:`~django.db.models.signals.m2m_changed` signals will be called with
|
||||
``raw=True`` since the instance only contains attributes that are local to the
|
||||
model. You may, for example, want to disable handlers that access
|
||||
related fields that aren't present during fixture loading and would otherwise
|
||||
|
|
@ -163,6 +164,10 @@ You could also write a decorator to encapsulate this logic::
|
|||
Just be aware that this logic will disable the signals whenever fixtures are
|
||||
deserialized, not just during :djadmin:`loaddata`.
|
||||
|
||||
.. versionchanged:: 6.1
|
||||
|
||||
The ``raw`` argument was added to ``m2m_changed`` signals.
|
||||
|
||||
Compressed fixtures
|
||||
===================
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": kwargs["action"],
|
||||
"reverse": kwargs["reverse"],
|
||||
"model": kwargs["model"],
|
||||
"raw": kwargs["raw"],
|
||||
}
|
||||
if kwargs["pk_set"]:
|
||||
message["objects"] = list(
|
||||
|
|
@ -114,6 +115,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "pre_add",
|
||||
"reverse": False,
|
||||
"model": Part,
|
||||
"raw": False,
|
||||
"objects": [self.doors, self.engine, self.wheelset],
|
||||
}
|
||||
)
|
||||
|
|
@ -123,6 +125,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "post_add",
|
||||
"reverse": False,
|
||||
"model": Part,
|
||||
"raw": False,
|
||||
"objects": [self.doors, self.engine, self.wheelset],
|
||||
}
|
||||
)
|
||||
|
|
@ -136,6 +139,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "pre_add",
|
||||
"reverse": True,
|
||||
"model": Car,
|
||||
"raw": False,
|
||||
"objects": [self.bmw, self.toyota],
|
||||
}
|
||||
)
|
||||
|
|
@ -145,6 +149,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "post_add",
|
||||
"reverse": True,
|
||||
"model": Car,
|
||||
"raw": False,
|
||||
"objects": [self.bmw, self.toyota],
|
||||
}
|
||||
)
|
||||
|
|
@ -163,6 +168,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "pre_remove",
|
||||
"reverse": False,
|
||||
"model": Part,
|
||||
"raw": False,
|
||||
"objects": [self.airbag, self.engine],
|
||||
},
|
||||
{
|
||||
|
|
@ -170,6 +176,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "post_remove",
|
||||
"reverse": False,
|
||||
"model": Part,
|
||||
"raw": False,
|
||||
"objects": [self.airbag, self.engine],
|
||||
},
|
||||
],
|
||||
|
|
@ -188,6 +195,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "pre_add",
|
||||
"reverse": False,
|
||||
"model": Part,
|
||||
"raw": False,
|
||||
"objects": [self.airbag, self.sunroof],
|
||||
}
|
||||
)
|
||||
|
|
@ -197,6 +205,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "post_add",
|
||||
"reverse": False,
|
||||
"model": Part,
|
||||
"raw": False,
|
||||
"objects": [self.airbag, self.sunroof],
|
||||
}
|
||||
)
|
||||
|
|
@ -210,6 +219,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "pre_add",
|
||||
"reverse": True,
|
||||
"model": Car,
|
||||
"raw": False,
|
||||
"objects": [self.bmw, self.toyota],
|
||||
}
|
||||
)
|
||||
|
|
@ -219,6 +229,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "post_add",
|
||||
"reverse": True,
|
||||
"model": Car,
|
||||
"raw": False,
|
||||
"objects": [self.bmw, self.toyota],
|
||||
}
|
||||
)
|
||||
|
|
@ -237,6 +248,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "pre_remove",
|
||||
"reverse": True,
|
||||
"model": Car,
|
||||
"raw": False,
|
||||
"objects": [self.vw],
|
||||
},
|
||||
{
|
||||
|
|
@ -244,6 +256,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "post_remove",
|
||||
"reverse": True,
|
||||
"model": Car,
|
||||
"raw": False,
|
||||
"objects": [self.vw],
|
||||
},
|
||||
],
|
||||
|
|
@ -261,12 +274,14 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "pre_clear",
|
||||
"reverse": False,
|
||||
"model": Part,
|
||||
"raw": False,
|
||||
},
|
||||
{
|
||||
"instance": self.vw,
|
||||
"action": "post_clear",
|
||||
"reverse": False,
|
||||
"model": Part,
|
||||
"raw": False,
|
||||
},
|
||||
],
|
||||
)
|
||||
|
|
@ -283,12 +298,14 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "pre_clear",
|
||||
"reverse": True,
|
||||
"model": Car,
|
||||
"raw": False,
|
||||
},
|
||||
{
|
||||
"instance": self.doors,
|
||||
"action": "post_clear",
|
||||
"reverse": True,
|
||||
"model": Car,
|
||||
"raw": False,
|
||||
},
|
||||
],
|
||||
)
|
||||
|
|
@ -306,12 +323,14 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "pre_clear",
|
||||
"reverse": True,
|
||||
"model": Car,
|
||||
"raw": False,
|
||||
},
|
||||
{
|
||||
"instance": self.airbag,
|
||||
"action": "post_clear",
|
||||
"reverse": True,
|
||||
"model": Car,
|
||||
"raw": False,
|
||||
},
|
||||
],
|
||||
)
|
||||
|
|
@ -330,6 +349,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "pre_add",
|
||||
"reverse": False,
|
||||
"model": Part,
|
||||
"raw": False,
|
||||
"objects": [p6],
|
||||
}
|
||||
)
|
||||
|
|
@ -339,6 +359,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "post_add",
|
||||
"reverse": False,
|
||||
"model": Part,
|
||||
"raw": False,
|
||||
"objects": [p6],
|
||||
}
|
||||
)
|
||||
|
|
@ -352,6 +373,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "pre_remove",
|
||||
"reverse": False,
|
||||
"model": Part,
|
||||
"raw": False,
|
||||
"objects": [p6],
|
||||
}
|
||||
)
|
||||
|
|
@ -361,6 +383,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "post_remove",
|
||||
"reverse": False,
|
||||
"model": Part,
|
||||
"raw": False,
|
||||
"objects": [p6],
|
||||
}
|
||||
)
|
||||
|
|
@ -370,6 +393,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "pre_add",
|
||||
"reverse": False,
|
||||
"model": Part,
|
||||
"raw": False,
|
||||
"objects": [self.doors, self.engine, self.wheelset],
|
||||
}
|
||||
)
|
||||
|
|
@ -379,6 +403,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "post_add",
|
||||
"reverse": False,
|
||||
"model": Part,
|
||||
"raw": False,
|
||||
"objects": [self.doors, self.engine, self.wheelset],
|
||||
}
|
||||
)
|
||||
|
|
@ -397,6 +422,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "pre_clear",
|
||||
"reverse": False,
|
||||
"model": Part,
|
||||
"raw": False,
|
||||
}
|
||||
)
|
||||
expected_messages.append(
|
||||
|
|
@ -405,6 +431,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "post_clear",
|
||||
"reverse": False,
|
||||
"model": Part,
|
||||
"raw": False,
|
||||
}
|
||||
)
|
||||
expected_messages.append(
|
||||
|
|
@ -413,6 +440,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "pre_add",
|
||||
"reverse": False,
|
||||
"model": Part,
|
||||
"raw": False,
|
||||
"objects": [self.doors, self.engine, self.wheelset],
|
||||
}
|
||||
)
|
||||
|
|
@ -422,6 +450,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "post_add",
|
||||
"reverse": False,
|
||||
"model": Part,
|
||||
"raw": False,
|
||||
"objects": [self.doors, self.engine, self.wheelset],
|
||||
}
|
||||
)
|
||||
|
|
@ -435,6 +464,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "pre_remove",
|
||||
"reverse": False,
|
||||
"model": Part,
|
||||
"raw": False,
|
||||
"objects": [self.engine],
|
||||
}
|
||||
)
|
||||
|
|
@ -444,6 +474,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "post_remove",
|
||||
"reverse": False,
|
||||
"model": Part,
|
||||
"raw": False,
|
||||
"objects": [self.engine],
|
||||
}
|
||||
)
|
||||
|
|
@ -464,6 +495,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "pre_add",
|
||||
"reverse": False,
|
||||
"model": Part,
|
||||
"raw": False,
|
||||
"objects": [self.doors],
|
||||
}
|
||||
)
|
||||
|
|
@ -473,6 +505,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "post_add",
|
||||
"reverse": False,
|
||||
"model": Part,
|
||||
"raw": False,
|
||||
"objects": [self.doors],
|
||||
}
|
||||
)
|
||||
|
|
@ -485,6 +518,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "pre_add",
|
||||
"reverse": True,
|
||||
"model": Car,
|
||||
"raw": False,
|
||||
"objects": [c4b],
|
||||
}
|
||||
)
|
||||
|
|
@ -494,6 +528,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "post_add",
|
||||
"reverse": True,
|
||||
"model": Car,
|
||||
"raw": False,
|
||||
"objects": [c4b],
|
||||
}
|
||||
)
|
||||
|
|
@ -519,6 +554,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "pre_add",
|
||||
"reverse": False,
|
||||
"model": Person,
|
||||
"raw": False,
|
||||
"objects": [self.bob, self.chuck],
|
||||
},
|
||||
{
|
||||
|
|
@ -526,6 +562,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "post_add",
|
||||
"reverse": False,
|
||||
"model": Person,
|
||||
"raw": False,
|
||||
"objects": [self.bob, self.chuck],
|
||||
},
|
||||
],
|
||||
|
|
@ -542,6 +579,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "pre_add",
|
||||
"reverse": False,
|
||||
"model": Person,
|
||||
"raw": False,
|
||||
"objects": [self.daisy],
|
||||
},
|
||||
{
|
||||
|
|
@ -549,6 +587,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "post_add",
|
||||
"reverse": False,
|
||||
"model": Person,
|
||||
"raw": False,
|
||||
"objects": [self.daisy],
|
||||
},
|
||||
],
|
||||
|
|
@ -565,6 +604,7 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "pre_add",
|
||||
"reverse": True,
|
||||
"model": Person,
|
||||
"raw": False,
|
||||
"objects": [self.alice, self.bob],
|
||||
},
|
||||
{
|
||||
|
|
@ -572,6 +612,89 @@ class ManyToManySignalsTest(TestCase):
|
|||
"action": "post_add",
|
||||
"reverse": True,
|
||||
"model": Person,
|
||||
"raw": False,
|
||||
"objects": [self.alice, self.bob],
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
def test_m2m_relations_set_base_raw(self):
|
||||
self.chuck.idols.add(self.daisy)
|
||||
self._initialize_signal_person()
|
||||
self.chuck.idols.set_base([self.alice, self.bob], raw=True)
|
||||
self.assertEqual(
|
||||
self.m2m_changed_messages,
|
||||
[
|
||||
{
|
||||
"instance": self.chuck,
|
||||
"action": "pre_remove",
|
||||
"reverse": True,
|
||||
"model": Person,
|
||||
"raw": True,
|
||||
"objects": [self.daisy],
|
||||
},
|
||||
{
|
||||
"instance": self.chuck,
|
||||
"action": "post_remove",
|
||||
"reverse": True,
|
||||
"model": Person,
|
||||
"raw": True,
|
||||
"objects": [self.daisy],
|
||||
},
|
||||
{
|
||||
"instance": self.chuck,
|
||||
"action": "pre_add",
|
||||
"reverse": True,
|
||||
"model": Person,
|
||||
"raw": True,
|
||||
"objects": [self.alice, self.bob],
|
||||
},
|
||||
{
|
||||
"instance": self.chuck,
|
||||
"action": "post_add",
|
||||
"reverse": True,
|
||||
"model": Person,
|
||||
"raw": True,
|
||||
"objects": [self.alice, self.bob],
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
def test_m2m_relations_set_base_raw_clear(self):
|
||||
self.chuck.idols.set([self.daisy, self.bob])
|
||||
self._initialize_signal_person()
|
||||
self.chuck.idols.set_base([self.alice, self.bob], clear=True, raw=True)
|
||||
self.assertEqual(
|
||||
self.m2m_changed_messages,
|
||||
[
|
||||
{
|
||||
"instance": self.chuck,
|
||||
"action": "pre_clear",
|
||||
"reverse": True,
|
||||
"model": Person,
|
||||
"raw": True,
|
||||
},
|
||||
{
|
||||
"instance": self.chuck,
|
||||
"action": "post_clear",
|
||||
"reverse": True,
|
||||
"model": Person,
|
||||
"raw": True,
|
||||
},
|
||||
{
|
||||
"instance": self.chuck,
|
||||
"action": "pre_add",
|
||||
"reverse": True,
|
||||
"model": Person,
|
||||
"raw": True,
|
||||
"objects": [self.alice, self.bob],
|
||||
},
|
||||
{
|
||||
"instance": self.chuck,
|
||||
"action": "post_add",
|
||||
"reverse": True,
|
||||
"model": Person,
|
||||
"raw": True,
|
||||
"objects": [self.alice, self.bob],
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ def fk_create(pk, klass, data):
|
|||
def m2m_create(pk, klass, data):
|
||||
instance = klass(id=pk)
|
||||
models.Model.save_base(instance, raw=True)
|
||||
instance.data.set(data)
|
||||
instance.data.set_base(data, raw=True)
|
||||
return [instance]
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue