Django: iterating over the options in a custom select field
I'm using a custom MM/YY field and widget based on this example. I want to iterate over the individual month and year options defined in the widget class in order to apply "selected='selected'" to the MM/YY value that corresponds with the MM/YY value stored in the database. This seems like such a messy way of doing this, so if you have any better ideas please post them here.
class MonthYearWidget(forms.MultiWidget):
def __init__(self, attrs=None):
months = (
('01', 'Jan (01)'),
('02', 'Feb (02)'),
('03', 'Mar (03)'),
('04', 'Apr (04)'),
('05', 'May (05)'),
('06', 'Jun (06)'),
('07', 'Jul (07)'),
('08', 'Aug (08)'),
('09', 'Sep (09)'),
('10', 'Oct (10)'),
('11', 'Nov (11)'),
('12', 'Dec (12)'),
)
year = int(datetime.date.today().year)
year_digits = range(year, year+10)
years = [(year, year) for year in year_digits]
widgets = (forms.Select(attrs=attrs, choices=months), forms.Select(attrs=attrs, choices=years))
super(MonthYearWidget, self).__init__(widgets, attrs)
def decompress(self, value):
if value:
return [value.month, value.year]
return [None, None]
def render(self, name, value, attrs=None):
try:
value = datetime开发者_如何学编程.date(month=int(value[0]), year=int(value[1]), day=1)
except:
value = ''
return super(MonthYearWidget, self).render(name, value, attrs)
class MonthYearField(forms.MultiValueField):
def __init__(self, *args, **kwargs):
forms.MultiValueField.__init__(self, *args, **kwargs)
self.fields = (forms.CharField(), forms.CharField(),)
def compress(self, data_list):
if data_list:
return datetime.date(year=int(data_list[1]), month=int(data_list[0]), day=1)
return datetime.date.today()
and then here's where I'm stuck, in the template. I can't figure out what the name of the iterable list for the months and years is (if there is one). Finding that iterable list is the problem; I already plan to use an ifequal statement to determine which option the "selected='selected'" should apply to. I have only tried to iterate over the months so far.
<form action="#" method="POST">
{% csrf_token %}
<p>{{ form.from_email.label_tag }}: {{ form.from_email }}</p>
<p>{{ form.working_month.label_tag }}:
<select name="working_month_0" id="id_working_month_0">
{% for i in form.working_month.data_list %}
<option value="{{ i }}">{{ option.from_email }}</option>
{% endfor %}
</select>
<p><input type="submit" value="Change Settings Now" /></p>
</form>
Thanks in advance for any guidance you all can provide.
EDIT: Here is the generic view:
def option_edit(request,option_id):
try:
option = Option.objects.get(pk=option_id)
except Option.DoesNotExist:
raise Http404
return create_update.update_object(
request,
form_class = OptionForm,
template_name = 'options.html',
template_object_name = 'option',
object_id = option_id,
post_save_redirect = '/some/address/' + option_id + '/edit/'
)
... and the form class:
class OptionForm(ModelForm):
class Meta:
model = Option
working_month = MonthYearField(widget=MonthYearWidget)
I think the model is relevant, too:
class Option(models.Model):
from_email = models.EmailField()
working_month = models.DateField()
Do I have to create a custom model field in addition to the custom form field, or can I use this setup?
The magic of django forms is that you don't need to do all that. By calling the form's select field by name, it will render it and select the right option as based on initial/instance data passed into the form on instantation.
{{form.working_month}}
If you're still having troubles, can you post the form class as well?
Good luck!
EDIT
In looking at the first comment on the link you posted, this issue is addressed. The commenter included this code
def __init__(self, *args, **kwargs):
forms.MultiValueField.__init__(self, *args, **kwargs)
self.fields = (forms.CharField(), forms.CharField(),)
A slight variation of your problem is solved here
http://skyl.org/log/post/skyl/2010/01/subclass-django-forms-widgets-radiofieldrenderer-and-django-forms-widgets-radioselect-for-custom-rendering-of-individual-choices/
精彩评论