2009/11/4 Georg Göttlich <m...@dvine.de>:
>
> Hi everybody,
>
> I have a problem with denormalizing a m2m field. For several reasons I
> want to save a CSV string of all the authors of a text. The authors
> are manage in an m2m field to auth.user. The changes are made with the
> admin.
>
> First I tried to override the save() method of the model. This didn't
> work. Even with first calling save on the parent and doing a fresh
> query within the save() function I always get the state of the authors
> before the change. After the save operation I have the correct list of
> authors in the m2m field but an incorrect serialization in the
> denormalized charfield. If I then save again (via the admin interface)
> without changing anything it obviously works.
>
> Next I tried using the post_save signal. Same results.
>
> Then someone in the channel suggested to override an admin function
> and I tried overriding save_model. Same results here as well.
>
> I don't really know what to do next and I simply don't understand
> what's going on. When are these m2m relations updated? Is there
> perhaps a seperate signal. Do I somehow need to resync due to internal
> caching or something weird like that?
> I would be very glad for any suggestions in the toppic! Thanks a lot
> in advance.
The problem you are experiencing is caused by a misunderstanding about
the handling of m2m fields: m2m saving and model saving are
independent processes. The call to set:

book.authors = [a,b,c,d]

doesn't have any interaction on the Book model itself - it only
interacts with the m2m table. As a result, it doesn't invoke the
save() method on Book, or issue the pre/post_save signal. When you
assign a value to an m2m field, the m2m field is updated
*immediately*, without any need to call save() on the parent model. An
example:

book = Book.objects.filter(...) # retrieve a book from the db
book.name = 'asdf' # Set the name - no db activity
book.pagecount = 42 # Set the pagecount - no db activity
book.authors = [a,b,c,d] # Write the m2m data to the database
book.save() # Write the name and pagecount to the database

A related issue here is that when you create a new book instance, you
can't assign to an m2m field until *after* the instance has been saved
for the first time - until the book has been saved, it doesn't have a
primary key, so the m2m table has nothing to link to.

In your case, ticket #5390 is the fix to your problem. This ticket
proposes to introduce a signal on m2m saving. You could then connect
your denormalization method to this signal. This ticket has been on
the todo list for a while - it narrowly missed inclusion in v1.1. I
hope to be able to get this into trunk for v1.2.

In the meantime, you will need to use a workaround. The easiest
workaround I can think of is to introduce an intermediate model [1].
Django allows you to manually define the model to use to store m2m
relations. This was originally intended to allow you to store extra
data on the m2m relationship, but there is no requirement that you do
this - you can define an intermediate m2m table that just stores the
m2m data.

By defining your own m2m intermediate table, you get a standalone
class, which means you can override the save method on the m2m table.
Put your denormalization in that save method, and you're done.

The unfortunate side effect of this approach is that you won't be able
to do direct assignment of m2m relations (i.e., you won't be able to
say book.authors = [a,b,c]). Instead, you will need to manually create
instances of the intermediate relation.

[1] 
http://docs.djangoproject.com/en/dev/topics/db/models/#extra-fields-on-many-to-many-relationships

Yours,
Russ Magee %-)

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-users@googlegroups.com
To unsubscribe from this group, send email to 
django-users+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to