Admin Model Validation on ManyToMany Field

453 views
Skip to first unread message

Heleen

unread,
Jul 13, 2010, 8:45:43 AM7/13/10
to Django users
Hello,

I have the following classes:
class Application(models.Model):
users = models.ManyToManyField(User, through='Permission')
folder = models.ForeignKey(Folder)

class Folder(models.Model):
company = models.ManyToManyField(Compnay)

class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile')
company = models.ManyToManyField(Company)

Now when I save application, I would like to check if the users do not
belong to the application's folder's companies.
I have posed this question before and someone came up with the
following sollution:
forms.py:
class ApplicationForm(ModelForm):
class Meta:
model = Application

def clean(self):
cleaned_data = self.cleaned_data
users = cleaned_data['users']
folder = cleaned_data['folder']
if
users.filter(profile__company__in=folder.company.all()).count() > 0:
raise forms.ValidationError('One of the users of this
Application works in one of the Folder companies!')
return cleaned_data

admin.py
class ApplicationAdmin(ModelAdmin):
form = ApplicationForm

This seems like right the way to go about this. The problem is that
neither the users nor folder fields are in the cleaned_data and I get
a keyerror when it hits the users = cleaned_data['users'] line.

I was hoping that someone here could explain to me why these
manytomany fields don't show up in cleaned_data and that someone could
possibly give me a sollution to my problem.

Thanks!
Heleen

Nuno Maltez

unread,
Jul 14, 2010, 8:02:08 AM7/14/10
to django...@googlegroups.com
Hi,

Just a guess: have you actually selected a user and a folder when
submitting the form? I think only valid field are present on the
cleaned_data dict, and your users and folder fields are not optional
(blank=True, null=True).

hth,
nuno

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

Heleen

unread,
Jul 14, 2010, 9:32:58 AM7/14/10
to Django users
Thank you for your reply.

Yes I have selected a user and folder.
I believe ManyToMany fields are always optional (hence many to many).
So my users and company fields are optional, but my folder field
isn't.
When I add a new Application in the Admin I do specify a folder and
users (if I don't I would at least get a 'Required field' error for
the folder field).
I've tested the method above (clean function) with another model that
has a manytomany field, and it does exactly the same thing, even when
I really do fill in the data. In fact, if I delibirately throw an
error and look in the debug info I can see the ManyToMany field data
being present in the POST data, just like I can when I do the same
thing with the above models.

Btw, I just noticed a typo in my Folder model description above,
that's not the issue as it's correct in my original model.

On Jul 14, 2:02 pm, Nuno Maltez <nuno.li...@gmail.com> wrote:
> Hi,
>
> Just a guess: have you actually selected a user and a folder when
> submitting the form? I think only valid field are present on the
> cleaned_data dict, and your users and folder fields are not optional
> (blank=True, null=True).
>
> hth,
> nuno
>

Nuno Maltez

unread,
Jul 14, 2010, 10:50:58 AM7/14/10
to django...@googlegroups.com
Sorry, I can't reproduce your error with django 1.2.

I copied your models (just removed the intermediaty "Permission"
because I don't know your User model) into a new app and I have 2
scenarios Adding an Application in the admin:

a) if I select a User and Folder, the validation runs just fine
b) if I do not select an User, then the "clean" method is still
accessed, but since 'users' is not present in the cleaned_data dict it
throws an exception - which is the scenario you give, hence my
original guess :)

Nuno

jaymzcd

unread,
Jul 14, 2010, 11:16:07 AM7/14/10
to Django users
Hi Heleen,

I think this is because your running the users through an intermediate
model. That changes the way you need to work with the M2M data. You
should be working on the Permission model/objects instead. If you
check out the M2M docs for models via an intermediate:

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

You'll see the example is pretty much what you have only with Group
instead of Application.

"The only way to create this type of relationship is to create
instances of the intermediate model. Unlike normal many-to-many
fields, you can't use add, create, or assignment (i.e.,
beatles.members = [...]) to create relationships:"

jaymz

Nuno Maltez

unread,
Jul 14, 2010, 10:54:29 AM7/14/10
to django...@googlegroups.com
On Wed, Jul 14, 2010 at 3:50 PM, Nuno Maltez <nuno....@gmail.com> wrote:
> Sorry, I can't reproduce your error with django 1.2.
>
> I copied your models (just removed the intermediaty "Permission"
> because I don't know your User model) into a new app and I have 2

Oops, forgot to add i made the ManyToMany a relation to django's User model.

Nuno

Heleen

unread,
Jul 15, 2010, 3:53:37 AM7/15/10
to Django users
Thanks very much for your reply!
I got it working now. At first I couldn't get my head around how it
would work using the clean of the intermediary model. But after a
night's sleep it made sense to me.
In the Admin my Permission model (the users field) is an inline of
Application and when I put the validation on Permission it also
automatically works in the Application Admin.

So now I have:

admin.py
class PermissionInline(admin.TabularInline):
form = PermissionForm
model = Permission
extra = 3

forms.py
class PermissionForm(forms.ModelForm):
class Meta:
model = Permission

def clean(self):
cleaned_data = self.cleaned_data
user = cleaned_data['user']
role = cleaned_data['role']
if role.id != 1:
folder = cleaned_data['application'].folder
if len(filter(lambda x:x in
user.profile.company.all(),folder.company.all())) > 0: # this is an
intersection
raise forms.ValidationError("One of the users of this
Application works for one of the Repository's organisations!")
return cleaned_data

And this works!

On Jul 14, 5:16 pm, jaymzcd <jaym...@googlemail.com> wrote:
> Hi Heleen,
>
> I think this is because your running the users through an intermediate
> model. That changes the way you need to work with the M2M data. You
> should be working on the Permission model/objects instead. If you
> check out the M2M docs for models via an intermediate:
>
> http://docs.djangoproject.com/en/dev/topics/db/models/#extra-fields-o...
Reply all
Reply to author
Forward
0 new messages