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.

Reply via email to