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
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.
- 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
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 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.
>
> >
Good luck!
Aidas Bendoraitis [aka Archatas]
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...
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
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?
i just reinstalled the whole project, generated all the tables and
refilled them. nothing changed.
patrick
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?
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
>
> >
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.
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
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...
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
Indeed. But you should never underestimate value of reading code in
Python :-). Docs are good but they never cover everything...
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