Re: rendering values from ManyToMany fields

2009-04-13 Thread Adam Fraser

figured it out!

class ModelForm(forms.ModelForm):
'''
Define our own model forms so we can use the form to render a
read-only detail page.
'''
def __init__(self, *args, **kwargs):
readonly = kwargs.get('readonly', False)
if readonly:
del kwargs['readonly']
super(ModelForm, self).__init__(*args, **kwargs)
if readonly:
obj = self.instance
for field_name in self.fields:
if hasattr(obj, 'get_%s_display' % field_name):
display_value = getattr(obj, 'get_%s_display' %
field_name)()
else:
# ---
# for fields that don't have a get_FIELD_display,
try to join the values manually in a  separated list.
try:
display_value = ''.join([unicode(x) for x
in getattr(obj, field_name).get_query_set()])
except:
display_value = None
# --
self.fields[field_name].widget = ReadOnlyWidget(getattr
(obj, field_name, ''), display_value)


On Apr 13, 9:54 am, Adam Fraser  wrote:
> Okay, so I should probably be dealing with the field in my ModelForm
> class (the one that subclasses ModelForm).
>
> This code is where the display values are found before creating the
> ReadOnlyWidget.  In the case of my stains field (a ManyToMany field),
> there isn't a get_stains_display function, so there's no way of
> displaying it nicely (yet).
>
> for field_name in self.fields:
>                 if hasattr(obj, 'get_%s_display' % field_name):
>                     display_value = getattr(obj, 'get_%s_display' %
> field_name)()
>                 else:
>                     # what to do?
>                     display_value = None
>                 self.fields[field_name].widget = ReadOnlyWidget(getattr
> (obj, field_name, ''), display_value)
>
> I assume the get_XXX_display functions are being defined automatically
> for my other fields in the project model (all of which are
> PositiveIntegerFields).  How do I define one to get the display value
> (s) for my stains ManyToManyField which maps to this model?
>
> class Stain(models.Model):
>     def __unicode__(self):
>         return unicode(self.name)
>     name = models.CharField(max_length=40)
>
> On Apr 10, 7:31 pm, Malcolm Tredinnick 
> wrote:
>
> > On Fri, 2009-04-10 at 12:16 -0700, Adam Fraser wrote:
>
> > [...]
>
> > > The problem I'm running into is that the value that comes into render
> > > for the ManyToManyField is a list of the id's for the selected stains
> > > and not the stains themselves.  I assume I should be getting them
> > > somehow through the django.db.models.fields.related.ManyRelatedManager
> > > which is in the original_value, but I haven't been able to figure out
> > > how.
>
> > > Anyone know what I'm missing?
>
> > The Widget subclass should only be processing the data that is going to
> > be displayed on the form. For something like a choice field based on
> > models, this would be, say, the pk value and a string to use for the
> > human-readable portion.
>
> > The django.forms.models.ModelChoiceField is a good example to look at to
> > see what's going on. It uses ModelChoiceIterator.choice() to generate
> > the data that is passed to the widget for rendering and you'll see that
> > it returns (pk, label) pairs.
>
> > So it sounds like things are working as expected. What extra work are
> > you trying to do at the widget level that requires more than what is
> > already passed in (the sequence of (pk, label) values)? Why isn't
> > whatever field you're using generating the right data? It's the Field
> > subclass that you want to be addressing here, not the widget.
>
> > In summary, widgets are objects that know how to take flat data and
> > convert it to HTML. Fields are objects that know how to take more
> > complex Python things (models, arbitrary objects, ...) and convert them
> > to flat data for passing to the widgets.
>
> > 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
-~--~~~~--~~--~--~---



Re: rendering values from ManyToMany fields

2009-04-13 Thread Adam Fraser

Okay, so I should probably be dealing with the field in my ModelForm
class (the one that subclasses ModelForm).

This code is where the display values are found before creating the
ReadOnlyWidget.  In the case of my stains field (a ManyToMany field),
there isn't a get_stains_display function, so there's no way of
displaying it nicely (yet).

for field_name in self.fields:
if hasattr(obj, 'get_%s_display' % field_name):
display_value = getattr(obj, 'get_%s_display' %
field_name)()
else:
# what to do?
display_value = None
self.fields[field_name].widget = ReadOnlyWidget(getattr
(obj, field_name, ''), display_value)

I assume the get_XXX_display functions are being defined automatically
for my other fields in the project model (all of which are
PositiveIntegerFields).  How do I define one to get the display value
(s) for my stains ManyToManyField which maps to this model?

class Stain(models.Model):
def __unicode__(self):
return unicode(self.name)
name = models.CharField(max_length=40)


On Apr 10, 7:31 pm, Malcolm Tredinnick 
wrote:
> On Fri, 2009-04-10 at 12:16 -0700, Adam Fraser wrote:
>
> [...]
>
> > The problem I'm running into is that the value that comes into render
> > for the ManyToManyField is a list of the id's for the selected stains
> > and not the stains themselves.  I assume I should be getting them
> > somehow through the django.db.models.fields.related.ManyRelatedManager
> > which is in the original_value, but I haven't been able to figure out
> > how.
>
> > Anyone know what I'm missing?
>
> The Widget subclass should only be processing the data that is going to
> be displayed on the form. For something like a choice field based on
> models, this would be, say, the pk value and a string to use for the
> human-readable portion.
>
> The django.forms.models.ModelChoiceField is a good example to look at to
> see what's going on. It uses ModelChoiceIterator.choice() to generate
> the data that is passed to the widget for rendering and you'll see that
> it returns (pk, label) pairs.
>
> So it sounds like things are working as expected. What extra work are
> you trying to do at the widget level that requires more than what is
> already passed in (the sequence of (pk, label) values)? Why isn't
> whatever field you're using generating the right data? It's the Field
> subclass that you want to be addressing here, not the widget.
>
> In summary, widgets are objects that know how to take flat data and
> convert it to HTML. Fields are objects that know how to take more
> complex Python things (models, arbitrary objects, ...) and convert them
> to flat data for passing to the widgets.
>
> 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
-~--~~~~--~~--~--~---



Re: rendering values from ManyToMany fields

2009-04-10 Thread Malcolm Tredinnick

On Fri, 2009-04-10 at 12:16 -0700, Adam Fraser wrote:
[...]
> The problem I'm running into is that the value that comes into render
> for the ManyToManyField is a list of the id's for the selected stains
> and not the stains themselves.  I assume I should be getting them
> somehow through the django.db.models.fields.related.ManyRelatedManager
> which is in the original_value, but I haven't been able to figure out
> how.
> 
> Anyone know what I'm missing?

The Widget subclass should only be processing the data that is going to
be displayed on the form. For something like a choice field based on
models, this would be, say, the pk value and a string to use for the
human-readable portion.

The django.forms.models.ModelChoiceField is a good example to look at to
see what's going on. It uses ModelChoiceIterator.choice() to generate
the data that is passed to the widget for rendering and you'll see that
it returns (pk, label) pairs.

So it sounds like things are working as expected. What extra work are
you trying to do at the widget level that requires more than what is
already passed in (the sequence of (pk, label) values)? Why isn't
whatever field you're using generating the right data? It's the Field
subclass that you want to be addressing here, not the widget.

In summary, widgets are objects that know how to take flat data and
convert it to HTML. Fields are objects that know how to take more
complex Python things (models, arbitrary objects, ...) and convert them
to flat data for passing to the widgets.

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
-~--~~~~--~~--~--~---



rendering values from ManyToMany fields

2009-04-10 Thread Adam Fraser

Hello,

I'm using a ManyToManyField to model a relationship where a "Project"
object may have many different "Stain" objects.  The code is working
successfully and looks like this

class Stain(models.Model):
def __unicode__(self):
return unicode(self.name)
name = models.CharField(max_length=40)

class Project(models.Model):
name = models.CharField(max_length=200)
stains = models.ManyToManyField(Stain, blank=True) # not required
...


However, I've also subclassed ModelForm in the interest of defining a
readonly view of the Project data (ie: a view without inputs).  The
code in forms.py is like this:

class ReadOnlyWidget(forms.Widget):
'''
Widget used by our ModelForm when rendering in readonly mode.
'''
def __init__(self, original_value, display_value):
self.original_value = original_value
self.display_value = display_value
super(ReadOnlyWidget, self).__init__()

def render(self, name, value, attrs=None):
if self.display_value is not None:
return unicode(self.display_value)
if type(value) == list:
#
#  Need to format list fields so they're seen in read only
view
#
return unicode(value)
return unicode(self.original_value)

def value_from_datadict(self, data, files, name):
return self.original_value

class ModelForm(forms.ModelForm):
'''
Define our own model forms so we can use the form to render a
read-only detail page.
'''
def __init__(self, *args, **kwargs):
readonly = kwargs.get('readonly', False)
if readonly:
del kwargs['readonly']
super(ModelForm, self).__init__(*args, **kwargs)
if readonly:
obj = self.instance
for field_name in self.fields:
if hasattr(obj, 'get_%s_display' % field_name):
display_value = getattr(obj,
'get_%s_display' %
field_name)()
else:
display_value = None
self.fields[field_name].widget = ReadOnlyWidget(getattr
(obj, field_name, ''), display_value)

class ProjectForm(ModelForm):
class Meta:
model = Project



The problem I'm running into is that the value that comes into render
for the ManyToManyField is a list of the id's for the selected stains
and not the stains themselves.  I assume I should be getting them
somehow through the django.db.models.fields.related.ManyRelatedManager
which is in the original_value, but I haven't been able to figure out
how.

Anyone know what I'm missing?
--~--~-~--~~~---~--~~
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
-~--~~~~--~~--~--~---