I have the following models (simplified example):
class Book(models.Model):
users = models.ManyToManyField(User, through=Permission)
class Permission(models.Model):
user = models.ForeignKey(User)
role = models.ForeignKey(Group)
active = models.BooleanField()
book = models.ForeignKey(Book)
What I need is that for a Book instance there cannot be more than one User of with the same Role and Active. So this is allowed:
Alice, Admin, False (not active), BookA
Dick, Admin, True (active), BookA
Chris, Editor, False (not active), BookA
Matt, Editor, False (not active), BookA
But this is not allowed:
Alice, Admin, True (active), BookA
Dick, Admin, True (active), BookA
Now this cannot be done with unique_together, because it only counts when active is True. I've tried to write a custom clean method (like how I have done here). But it seems that when you save a Book and it runs the validation on each Permission, the already validated Permission instances aren't saved until they've all been validated. This makes sense, because you don't want them to be saved in case something doesn't validate.
Could anyone tell me if there is a way to perform the validation described above?
P.S. I could imagine using the savepoint feature (http://docs.djangoproject.com/en/1.2/topics/db/transactions/), but I only really want to consider that as a last resort.
Maybe you can do something like: unique_together = [[book, role, active=1],]
?
Edit Sep. 23, 2010 14:00 Response to Manoj Govindan:
My admin.py (simplified version for clarity):
class BookAdmin(admin.ModelAdmin):
inlines = (PermissionInline,)
class PermissionInline(admin.TabularInline):
model = Permission
In the shell your validation would work. Because you first have to create the book instance and then you create all the Permission instances one by one: http://docs.djangoproject.com/en/1.2/topics/db/models/#extra-fields-on-many-to-many-relationships. So in the shell if you add 2 Permission instances the 1st Permission instance has been saved by the time 2nd is being validated, and so the validation works.
However when you use the Admin interface and you add all the book.users instances at the same time via the book users inline, I believe it does all the validation on all the book.users instances first, before it saves them. When I tried it, the validation didn't work, it just succeeded without an error when there should have been a ValidationError.