Ok, still slightly confused.  First - a high level description.  I
have a field that contains choices, but when I display the select, I
want to display some extra html below the select box, so I am creating
a custom widget that displays the standard select followed by my html.

Question: If want to use a special widget for a ChoiceField, is it
true that I need to instantiate the ChoiceField (or TypedChoiceField),
rather than just setting the .widget attribute on the one that is by
default created for me (due to it being a modelForm)?

I find that if I just do this:

            self.fields["status"].widget = StatusWidget(task=instance)

then my widget's select does not contain any choices.  My widget
doesn't do anything special to the select, it looks like this:

class StatusWidget(widgets.Select):
    def __init__(self, task, attrs={}):
        self.task = task
        super(StatusWidget, self).__init__(attrs)

    def render(self, name, value, attrs=None):
        rendered = super(StatusWidget, self).render(name, value,
attrs)
        rendered = rendered + .... add a bunch of stuff to the end
        return rendered

Because I seem unable to display the choices correctly in the select
box when I just set the field's widget attribute to my StatusWidget, I
am instantiating the field itself.  That now looks like this:

            self.fields["status"] = forms.TypedChoiceField
(choices=Task.STATUS_CHOICES, widget=StatusWidget(task=instance),
required=False, coerce=IntegerField.to_python)

However, I see when debugging that IntegerField.to_python is an
unbound method:

(Pdb) self.coerce
<unbound method IntegerField.to_python>

What is the right thing to set coerce to if I just want it to do
whatever it would "normally" do for the corresponding model field if I
wasn't trying to override the widget?  In my case I have verified that
if I set coerce=int that does work, but that doesn't seem very
general.  I'd much rather use whatever the standard coerce method
would have been if I hadn't overridden the widget.

Margie




On Aug 8, 12:11 am, Malcolm Tredinnick <malc...@pointy-stick.com>
wrote:
> Hi Margie,
>
>
>
> On Fri, 2009-08-07 at 23:17 -0700, Margie wrote:
>
> > Hmmm, ok, after digging around I realize that full_clean was not
> > setting cleaned_data for the status field to an integer value;
> > cleaned_data['status'] was just getting set to something like u'1'.
>
> > I am in fact using sqllite, and yes, my status fields are just
> > integers:
>
> > OPEN_STATUS = 1
> > CLOSED_STATUS = 2
> > STALLED_STATUS = 3
>
> > I think the problem has to do with the way I created the status field,
> > which is like this:
>
> >             self.fields["status"] = forms.ChoiceField
> > (choices=Task.STATUS_CHOICES, widget=StatusWidget(task=instance),
> > required=False)
>
> Right, that won't do what you want. ChoiceField normalizes to a unicode
> object.
>
>
>
> > I tried moving to TypedChoiceField(), but that didn't help.  I
> > debugged into it in the case where I used TypedChoiceField() and I can
> > see that when coerce is called it isn't doing anything, it is just
> > returning the unicode value.
>
> > I find that if I do this instead, that it does do the coerce
> > correctly:
>
> >             self.fields["status"].widget = StatusWidget(task=instance)
>
> > In looking at the doc it looks like the purpose of TypedChoiceField()
> > is to allow me to create my own coerce function, is that right?
>
> Correct.
>
> >   And
> > of course I wasn't doing that so it was behaving the same as
> > ChoiceField, and it looks like the default there is to just return the
> > unicode.
>
> Also correct. The documentation says "Defaults to an identity function"
> and all the data coming from a form submission are strings (Python
> unicode objects), so if you don't supply the coerce parameter, it does
> nothing.
>
> It's probably a slight API wart that TypedChoiceField doesn't just raise
> an exception if you don't supply coerce(). The default is slightly
> dangerous, as it almost always means you're misusing the field. Not a
> fatal flaw in the design, however.
>
>
>
> > When I don't declare the status field at all (ie, just let django do
> > it's default thing), my guess is that it is choosing a coerce function
> > based on the integer type of my choices, is that true?
>
> Yes. The django.db.models.fields.Field.formfield() method detects if you
> have specified "choices" in the field and uses the Field subclass's
> to_python() function as the coerce method.
>
> >   I have never
> > used anything but sqlite3 so far, so I guess that was masking the
> > error and I would have run into this in a more serious way when I
> > moved to a different db?
>
> Actually, my SQLite observation was entirely bogus. I suspect what
> you're seeing is the difference between these two lines:
>
>         t1 = Task.objects.create(status=u'3')
>         t2 = Task.objects.get(id=t1.id)
>
> In this case, t1.status will be a unicode string, but t2.status will
> always be an integer, no matter what DB backend is involved. So you are
> seemingly stumbling over a case like the t1 situation -- where you're
> using the object after it has been populated and saved, but still using
> the raw data.
>
> I've long argued that allowing the wrong types to be assigned to
> attributes in Django models is a flaw (Python got rid of automatic type
> coercion for operator arguments years ago for the same reason), but it's
> been there forever in Django-years, so isn't going to go away now.
>
> Regards,
> Malcolm
--~--~---------~--~----~------------~-------~--~----~
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