In django 1.4, my model save() gets called for ManyToManyField "through"
models for loaddata on that model:
class Entity(models.Model):
related_entities = models.ManyToManyField('self',
through='EntityRelationship', symmetrical=False, related_name='related_to+')
class EntityRelationship(models.Model):
from_entity = models.ForeignKey(Entity,
related_name='from_entities')
to_entity = models.ForeignKey(Entity,
related_name='to_entities')
def save(self, *args, **kwargs):
print >>sys.stderr, EntityRelationship.objects.all()
super(EntityRelationship, self).save(*args, **kwargs)
print >>sys.stderr, EntityRelationship.objects.all()
assert False
class Meta:
db_table = u'EntityRelationship'
ordering = ["to_entity"]
unique_together = (('from_entity','to_entity'))
def __unicode__(self):
return '%s -> %s'%(self.from_entity.pk,self.to_entity.pk)
Interestingly, `save()` is not called for the forward relationship, the one
explicity specified in the json fixture. loaddata must do a "raw" insert
for this one. But is called as part of validation of the relationship when
inserting a record for the reciprocal relationship:
>>> manage.py loaddata fixtures/EntityRelationship.json
[<EntityRelationship: 1 -> 2>]
[<EntityRelationship: 1 -> 2>, <EntityRelationship: 2 -> 1>]
I wouldn't expect loaddata should insert a receiprocal relationship record
not specified in the fixture. And doing so without calling save() for both
inserts makes it very difficult to deal with fixtures that contain a random
network of connected entities. You eventually get an IntegrityError during
the loaddata because duplicate records (relationships) have already been
entered. And it prevents the user from loading a fixture of asymmetrical
(not necessarily a reciprocal relationship for every edge of the graph)
relationships. At least I'm having trouble doing so.
Perhaps the '+' in the related name ('related_to+') is causing me grief, or
some other subtlety of self-referential relationships in Django that I
don't understand.
On Tuesday, March 29, 2011 11:21:43 PM UTC-7, George Karpenkov wrote:
>
> If we'll look into core/management/commands/loaddata we'll see the
> line
> "obj.save(using=using)" which saves the data.
>
> *however* consider the case when application has some custom database-
> altering logic in .save method. The common thing that comes to mind is
> timestamp, or something similar. What would happen is that instead of
> loading data the data from the fixture will be partly changed, which
> is really not what you want.
>
> That's not the worst case though - I've just spent 40 minutes loading
> the database from a fixture which contained data in django-tagging,
> which inserts it's own "INSERT" SQL statements into save. So loaddata
> was consistently crashing with "column blah is not unique" while the
> data from the dump was perfectly fine. It made me quite sad.
>
> so coming to think of it i can't really think of a use case where
> you'd want the custom logic in .save() to be executed. All the data is
> already there, and we *know* that it is valid data - so what else we
> might possibly want to do with it? (unless our application
> communicates over network with different services and it uses .save()
> to maintain integrity with them, but I haven't seen a single django
> website like that)
> So I think that some lower-level logic should be called instead.
>
> Any comments on why loaddata was implemented this way in the first
> place?
--
You received this message because you are subscribed to the Google Groups
"Django developers" group.
To view this discussion on the web visit
https://groups.google.com/d/msg/django-developers/-/Z3iq0-j3B9sJ.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/django-developers?hl=en.