John
John

Reputation: 155

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?

Upvotes: 1

Views: 2465

Answers (2)

czarchaic
czarchaic

Reputation: 6318

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(),)

Upvotes: 2

Related Questions