seeking clarification: custom manipulator foreign key / many-to-many

4 views
Skip to first unread message

va:patrick.kranzlmueller

unread,
Sep 20, 2006, 11:47:45 AM9/20/06
to django...@googlegroups.com
for the last couple of hours, I´ve read all entries about custom
manipulators but I´m still not able to get my stuff working.
I probably just don´t see what´s wrong anymore:

this is part of my MODEL:

class UserProfile(models.Model):
music = models.ManyToManyField(Music, blank=True, null=True,
related_name="music")
....


this is part of my CUSTOM MANIPULATOR:

class UserprofileManipulator(forms.Manipulator):
def __init__(self):
MUSIC_CHOICES = [(str(c.id), str(c)) for c in
Music.objects.all()]
self.fields = (
forms.CheckboxSelectMultipleField(field_name="music",
choices=MUSIC_CHOICES),
...
)
def save(self, data):
temp = UserProfile(
...
)
temp.set_gadgets(data['gadgets'])
temp.save()
#temp.gadgets = Gadgets.objects.filter(id__in=data.getlist('gadgets'))


in the VIEW:

manipulator = UserprofileManipulator()
user_profile_manipulator = UserProfile.ChangeManipulator
(request.user.id)
user_profile = user_profile_manipulator.original_object
if request.POST:
new_data = request.POST.copy()
errors = manipulator.get_validation_errors(new_data)
if not errors:
manipulator.do_html2python(new_data)
manipulator.save(new_data)
else:
errors = {}
new_data = user_profile_manipulator.flatten_data()
...


PROBLEMS:
1. the m2m-relationship doesn´t get saved.
2. in the template i have to write {{ form.gadgets_id }} to output
the checkboxes ... instead of {{ form.gadgets }}

thanks,
patrick


Ivan Sagalaev

unread,
Sep 20, 2006, 2:17:11 PM9/20/06
to django...@googlegroups.com
va:patrick.kranzlmueller wrote:
> self.fields = (
> forms.CheckboxSelectMultipleField(field_name="music",
> choices=MUSIC_CHOICES),
> ...
> )

I guess I know what is it... CheckboxSelectMultipleField
worksinexplicably different from SelectMultipleField in that it doesn't
use a field's name for checkboxes but instead counts them (music1,
music2, ...)

But it is fixable:

> manipulator = UserprofileManipulator()
> user_profile_manipulator = UserProfile.ChangeManipulator
> (request.user.id)
> user_profile = user_profile_manipulator.original_object
> if request.POST:
> new_data = request.POST.copy()

After this line add:

manipulator.prepare(new_data)

This will convert counted names back to normal.

patrickk

unread,
Sep 20, 2006, 2:57:39 PM9/20/06
to django...@googlegroups.com
thanks. the data is sent now, but
- how do I save the data in my custom manipulator, referring to:
temp.set_music(data['music'])

- how do I display the data (already in the database) on my site,
ref. to:
new_data = user_profile_manipulator.flatten_data()

additionally: I don´t understand why I have to write
{{ form.music_id }} instead of {{ form.music }} - it´s the same with
foreign keys.

thanks,
patrick

Ivan Sagalaev

unread,
Sep 20, 2006, 3:40:41 PM9/20/06
to django...@googlegroups.com
patrickk wrote:
> thanks. the data is sent now, but
> - how do I save the data in my custom manipulator, referring to:
> temp.set_music(data['music'])

It looks like 0.91 syntax. If you're using contemporary Django it should
look like this:

temp.music = Music.objects.filter(id__id=data['music'])

> - how do I display the data (already in the database) on my site,
> ref. to:
> new_data = user_profile_manipulator.flatten_data()
>

> additionally: I don愒 understand why I have to write
> {{ form.music_id }} instead of {{ form.music }} - it愀 the same with
> foreign keys.

In fact {{ form.music }} should work...

patrickk

unread,
Sep 20, 2006, 3:50:24 PM9/20/06
to django...@googlegroups.com

Am 20.09.2006 um 21:40 schrieb Ivan Sagalaev:

>
> patrickk wrote:
>> thanks. the data is sent now, but
>> - how do I save the data in my custom manipulator, referring to:
>> temp.set_music(data['music'])
>
> It looks like 0.91 syntax. If you're using contemporary Django it
> should
> look like this:
>
> temp.music = Music.objects.filter(id__id=data['music'])

doesn´t work.
I also tried:
temp.music = Music.objects.filter(id__id=data.getlist('music'))

>
>> - how do I display the data (already in the database) on my site,
>> ref. to:
>> new_data = user_profile_manipulator.flatten_data()
>>

>> additionally: I don´t understand why I have to write
>> {{ form.music_id }} instead of {{ form.music }} - it´s the same with


>> foreign keys.
>
> In fact {{ form.music }} should work...

doesn´t work either - when using {{ form.music }} I get nothing, with
{{ form.music_id }} the output looks ok.

>
> >

Aidas Bendoraitis

unread,
Sep 21, 2006, 10:08:29 AM9/21/06
to django...@googlegroups.com
Has your Music model a __str__ method? Maybe you get nothing using {{
form.music }} because it is represented in no way. Have you tried {{
form.music.title }} or similar? As far as I know, instance.music_id
refers to the id of the related object whereas instance.music refers
to the object itself.

Good luck!
Aidas Bendoraitis [aka Archatas]

Ivan Sagalaev

unread,
Sep 21, 2006, 10:52:55 AM9/21/06
to django...@googlegroups.com
Aidas Bendoraitis wrote:
> Has your Music model a __str__ method? Maybe you get nothing using {{
> form.music }} because it is represented in no way.

In fact {{ form.music }} has nothing to do with the model itself. It's a
manipulator's field and should be represented as a group of
checkboxes. I have no idea why it's not working...

patrickk

unread,
Sep 21, 2006, 1:20:38 PM9/21/06
to django...@googlegroups.com
thanks for your help (especially ivan).

are there any workarounds?
I´m still not able to save and retrieve the m2m-data. and since I
have to meet a deadline I´m getting kind of nervous.

thanks,
patrick

Ivan Sagalaev

unread,
Sep 21, 2006, 4:02:20 PM9/21/06
to django...@googlegroups.com
patrickk wrote:
> are there any workarounds?
> I´m still not able to save and retrieve the m2m-data. and since I
> have to meet a deadline I´m getting kind of nervous.

In your view code you use flatten_data() but I can't see it defined in
your custom manipulator. This must raise an exception but since you say
that it kinda works (just not right) I suspect you have omitted it from
you mail. Can you post it?

patrickk

unread,
Sep 21, 2006, 4:28:32 PM9/21/06
to django...@googlegroups.com
flatten_data() doesn´t relate to the custom manipulator but to model
resp. the changemanipulator.
btw, the table we´re talking about is extending the user model, it´s
a one-to-one relation - but I guess that shouldn´t be the problem.

i just reinstalled the whole project, generated all the tables and
refilled them. nothing changed.

patrick

Ivan Sagalaev

unread,
Sep 21, 2006, 4:47:56 PM9/21/06
to django...@googlegroups.com
patrickk wrote:
> flatten_data() doesn´t relate to the custom manipulator but to model
> resp. the changemanipulator.

I see now... And if I'm guessing correctly you're creating a FormWrapper
from user_profile_manipulator that just doesn't have that checkbox field.

Anyway making two manipulators is unnecessary and I can't even imagine
how is this supposed to work :-).

Now, if I understand your task you want a form for your user profile but
with multiple checkboxes for 'music' field. Right? Then you can
inherit you manipulator from automatic UserProfile.ChangeManipulator and
replace this field with what you need:

class UserProfileManipulator(UserProfile.Manipulator):
def __init__(self, id):
UserProfile.Manipulator.__init__(self, id)

# Finding and removing standard field
for field in self.fields:
if field.field_name == 'music':
self.fields.remove(field)
break

# Adding custom field


MUSIC_CHOICES = [(str(c.id), str(c))
for c in Music.objects.all()]

self.fields.append(forms.CheckboxSelectMultipleField(
'music',
choices=MUSIC_CHOICES))

Does it make sense?

patrickk

unread,
Sep 21, 2006, 5:04:54 PM9/21/06
to django...@googlegroups.com
well, now I´m totally confused.
I though that´s exactly what custom manipulators are here for:
"You can easily create your own custom manipulators for handling
custom forms." (django documentation).

more below ...

Am 21.09.2006 um 22:47 schrieb Ivan Sagalaev:

>
> patrickk wrote:
>> flatten_data() doesn´t relate to the custom manipulator but to model
>> resp. the changemanipulator.
>
> I see now... And if I'm guessing correctly you're creating a
> FormWrapper
> from user_profile_manipulator that just doesn't have that checkbox
> field.

that´s right. user_profile_manipulator doesn´t have that checkbox field.
in the model, the relation is defined as:


music = models.ManyToManyField(Music, blank=True, null=True,
related_name='music')

at this point, there is nothing defined about *how* to display that
relation (e.g. using checkboxes).

>
> Anyway making two manipulators is unnecessary and I can't even imagine
> how is this supposed to work :-).

as mentioned above, I thought that´s the primary use-case for custom
manipulators:
the custom manipulator handles the custom form
the changemanipulator handles the data

is that wrong?

>
> Now, if I understand your task you want a form for your user
> profile but
> with multiple checkboxes for 'music' field. Right? Then you can
> inherit you manipulator from automatic
> UserProfile.ChangeManipulator and
> replace this field with what you need:
>
> class UserProfileManipulator(UserProfile.Manipulator):
> def __init__(self, id):
> UserProfile.Manipulator.__init__(self, id)
>
> # Finding and removing standard field
> for field in self.fields:
> if field.field_name == 'music':
> self.fields.remove(field)
> break
>
> # Adding custom field
> MUSIC_CHOICES = [(str(c.id), str(c))
> for c in Music.objects.all()]
> self.fields.append(forms.CheckboxSelectMultipleField(
> 'music',
> choices=MUSIC_CHOICES))
>
> Does it make sense?

some thoughts on that:
1. if I do it that way, I´m having checkboxes in the admin-interface,
right?
2. is that the standard way to do it? it seems really complicated
(ref. to finding and removing fields)?
3. instead of "finding and removing a field" - why not write a custom
manipulator, add specific validation etc.?

your suggestion might work, but (to me) it doesn´t seem like the
"django way" to do that.

thanks a lot for your help.
gotta get some sleep,
patrick


>
> >

Ivan Sagalaev

unread,
Sep 21, 2006, 5:27:08 PM9/21/06
to django...@googlegroups.com
patrickk wrote:
> well, now I´m totally confused.
> I though that´s exactly what custom manipulators are here for:
> "You can easily create your own custom manipulators for handling
> custom forms." (django documentation).

All manipulators handle forms:
- prepare initial data
- validate data
- save data or redisplay the form with errors

Automatic manipulators just know how to construct their fields based on
model's fields.

> that´s right. user_profile_manipulator doesn´t have that checkbox field.
> in the model, the relation is defined as:
> music = models.ManyToManyField(Music, blank=True, null=True,
> related_name='music')
>
> at this point, there is nothing defined about *how* to display that
> relation (e.g. using checkboxes).

In fact there is a default representation for every Django data field.
For ManyToManyField it is SelectMultipleField.

> as mentioned above, I thought that´s the primary use-case for custom
> manipulators:
> the custom manipulator handles the custom form
> the changemanipulator handles the data
>
> is that wrong?

Yes. One manipulator is intended to handle one form entirely. You need a
custom manipulator only if an automatic one doesn't work as you want it.

> some thoughts on that:
> 1. if I do it that way, I´m having checkboxes in the admin-interface,
> right?

No. Admin code won't know anything about your manipulator and will use
automatic ChangeManipulator (with SelectMultiple for your 'music').

For completeness: to make it work in admin you could create a new
_model_ field as a subclass of ManyToManyField and make
CheckboxMultipleField its default manipulaator field class.

> 2. is that the standard way to do it? it seems really complicated
> (ref. to finding and removing fields)?

I wouldn't call it "standard" but for me it seems pretty
straightforward. I use it often and have convenience function for
removing fields by name.

> 3. instead of "finding and removing a field" - why not write a custom
> manipulator, add specific validation etc.?

You could. This is truly depend on the amount of differences between
automatic behavior and what you want.

If you want a form that is mostly similar to an automatic one but with
some small bits changed then it makes sense to change automatic
behavior. Because if you create a custom manipulator you will need to
repeat all the definitions for all the fields that automatic
manipulators do based on model. And keep updating manipulator when you
change a model.

But if your form is more custom and consists mostly of fields that don't
belong to one model then it is more convenient to create a custom
manipulator from scratch.

patrickk

unread,
Sep 21, 2006, 8:56:45 PM9/21/06
to django...@googlegroups.com
I don´t want to stress your help, but do you know where to find an
example on using a custom manipulator for *updating* data.

question is, where does the custom manipulator gets the data (stored
in the database) from.
the way I did it so far:
1. using a changmanipulator to get and display the data
2. using a custom manipulator to handle the form, do validation and
save the data

when you´re saying that I should only use *one* manipulator, there
has to be a possibility to get the data with the custom manipulator.
something like: manipulator = UserProfile.MyCustomManipulator(user_id)

sorry for being slow off the mark here, but that really contradicts
my reading of the documentation.

thanks again,
patrick

Ivan Sagalaev

unread,
Sep 22, 2006, 2:42:30 AM9/22/06
to django...@googlegroups.com
patrickk wrote:
> I don´t want to stress your help, but do you know where to find an
> example on using a custom manipulator for *updating* data.
>
> question is, where does the custom manipulator gets the data (stored
> in the database) from.
> the way I did it so far:
> 1. using a changmanipulator to get and display the data
> 2. using a custom manipulator to handle the form, do validation and
> save the data
>
> when you´re saying that I should only use *one* manipulator, there
> has to be a possibility to get the data with the custom manipulator.
> something like: manipulator = UserProfile.MyCustomManipulator(user_id)

Since it's custom manipulator it's all up to you how to retrieve data.
The most straightforward way is to copy the common behavior: implement
flatten_data:

class MyCustomManipulator(forms.Manipulator):
def __init__(self, id):
self.original_object = Model.objects.get(pk=id)
self.fields= [
...
]

def flatten_data():
return dict([(field.name, getattr(t, field.attname)) for field
in self.original_object._meta.fields])

This is a very simple implementation of flatten_data. It doesn't handle
ManyToManyField for example. But the idea is that you have to return a
dict with keys corresponding to your manipulator field names.

> sorry for being slow off the mark here, but that really contradicts
> my reading of the documentation.

Why that? Docs never say that you should use different manipulators for
giving away and accepting data. However it really lacks more advanced
examples of using custom manipulators...

patrickk

unread,
Sep 22, 2006, 4:26:32 AM9/22/06
to django...@googlegroups.com
thanks, I think I´ve got it now.

the documentation of custom manipulators really lacks advanced examples.
I don´t know how one should find out what you explained in the last
few mails by reading the documentation.
e.g., I´m quite sure that there´s no explanation of "_meta" in the
documentation

anyway, thanks a lot.
patrick

Ivan Sagalaev

unread,
Sep 23, 2006, 6:45:07 AM9/23/06
to django...@googlegroups.com
patrickk wrote:
> thanks, I think I扉e got it now.

>
> the documentation of custom manipulators really lacks advanced examples.
> I don愒 know how one should find out what you explained in the last
> few mails by reading the documentation.
> e.g., I惴 quite sure that there愀 no explanation of "_meta" in the
> documentation

Indeed. But you should never underestimate value of reading code in
Python :-). Docs are good but they never cover everything...

patrickk

unread,
Sep 23, 2006, 7:00:01 AM9/23/06
to django...@googlegroups.com
still learning ...
btw, it works fine now.

thanks,
patrick

Am 23.09.2006 um 12:45 schrieb Ivan Sagalaev:

>
> patrickk wrote:
>> thanks, I think I´ve got it now.


>>
>> the documentation of custom manipulators really lacks advanced
>> examples.

>> I don´t know how one should find out what you explained in the last


>> few mails by reading the documentation.

>> e.g., I´m quite sure that there´s no explanation of "_meta" in the

Reply all
Reply to author
Forward
0 new messages