Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get additional data into django form dropdown selection

I have an Action model that has a foreign key which specifies how often an action reoccurs:

class Reoccurance(models.Model):
    label = models.CharField("Label", max_length=50, unique = True)
    days = models.IntegerField("Days")

    def __unicode__(self):
        return self.label

    class Meta:
        ordering = ['days']

class Action(models.Model):
    name = models.CharField("Action Name", max_length=200, unique = True)
    complete = models.BooleanField(default=False, verbose_name="Complete?")
    reoccurance = models.ForeignKey(Reoccurance, blank=True, null=True, verbose_name="Reoccurance")

I'm making a modelForm of Action that results in HTML code for reoccurance (based on the database values that exist for the Reoccurance table):

<select id="id_reoccurance" class="select" name="reoccurance">
    <option value="" selected="selected">---------</option>
    <option value="12">2 Days</option>
    <option value="1">3 Days</option>
    <option value="2">5 Days</option>
    <option value="10">6 Days</option>
    <option value="9">1 Week</option>
    <option value="3">10 Days</option>
    <option value="4">2 Weeks</option>
    <option value="11">3 Weeks</option>
    <option value="5">1 Month</option>
    <option value="13">6 Weeks</option>
    <option value="6">1 Quarter</option>
    <option value="7">6 Months</option>
    <option value="8">1 Year</option>
</select>

As you can see, though the selections are in ascending day order, the values are out of order because they were entered into the database out of order.

I want to create some jquery that dynamically calculates the date when the action will reoccur. It will take today's date and add the number of days that correspond to the selection that the user has chosen. But with the data I get in the form, I cannot translate the selection into a set number of days. Even if the values of the option items were in order, it still doesn't indicate that say "1 Year" is equal to 365 days.

This data though is in the Reoccurance table. For label = "1 Year", days = 365. Likewise for all of the items in the Reoccurance table.

Is there a way to rewrite my modelForm so that perhaps the option value of each drop down item is equal to the number of days for that selection? Because then, I could access the number of days:

$("#id_reoccurance").change(function() {
    alert( $(this).val() );
});

Would this adversely affect my ability to tie the proper reoccurance selection to the correct row of the Reoccurance table? Is there another way I can access this days/label tie in jquery on my form template?

Update

Thanks to Joseph's suggestion to check this post, I was able to include a title in my option element:

from django.utils.html import conditional_escape, escape
from django.utils.encoding import force_unicode

class SelectWithTitles(forms.Select):
    def __init__(self, *args, **kwargs):
        super(SelectWithTitles, self).__init__(*args, **kwargs)
        # Ensure the titles dict exists
        self.titles = {}

    def render_option(self, selected_choices, option_value, option_label):
        title_html = (option_label in self.titles) and \
            u' title="%s" ' % escape(force_unicode(self.titles[option_label])) or ''
        option_value = force_unicode(option_value)
        selected_html = (option_value in selected_choices) and u' selected="selected"' or ''
        return u'<option value="%s"%s%s>%s</option>' % (
            escape(option_value), title_html, selected_html,
            conditional_escape(force_unicode(option_label)))

class ChoiceFieldWithTitles(forms.ChoiceField):
    widget = SelectWithTitles

    def __init__(self, choices=(), *args, **kwargs):
        choice_pairs = [(c[0], c[1]) for c in choices]
        super(ChoiceFieldWithTitles, self).__init__(choices=choice_pairs, *args, **kwargs)
        self.widget.titles = dict([(c[1], c[2]) for c in choices])

class ActionForm(forms.ModelForm):
    reoccurance = ChoiceFieldWithTitles()

    def __init__(self, *args, **kwargs):
        super(ActionForm, self).__init__(*args, **kwargs)   

        choices = []
        for pt in Reoccurance.objects.all():
            choices.append((pt.id, pt.label, pt.days))
        self.fields['reoccurance'] = ChoiceFieldWithTitles(choices = choices)

Fantastic. So now I get the following in my template:

<select id="id_reoccurance" class="selectwithtitles" name="reoccurance">
    <option value="12" title="2" >2 Days</option>
    <option value="1" title="3" >3 Days</option>
    <option value="2" title="5" >5 Days</option>
    <option value="10" title="6" >6 Days</option>
    <option value="9" title="7" >1 Week</option>
    <option value="3" title="10" >10 Days</option>
    <option value="4" title="14" >2 Weeks</option>
    <option value="11" title="21" >3 Weeks</option>
    <option value="5" title="30" >1 Month</option>
    <option value="13" title="42" >6 Weeks</option>
    <option value="6" title="90" >1 Quarter</option>
    <option value="7" title="180" >6 Months</option>
    <option value="8" title="365" >1 Year</option>
</select>

Ok, it seems like we're almost there, but I'm getting tripped up. In the jquery, I'm trying the following to get the title of the option selected:

$(function() {
    $("#id_reoccurance").change(function() {
        alert($(this).attr('title'));
    }); 
});

Problem is that it's coming back as undefined!

Update Got it

$(function() {
    $("#id_reoccurance").change(function() {
        alert($(this).find("option:selected").attr("title"));
    }); 
});
like image 406
Ed. Avatar asked Nov 03 '22 16:11

Ed.


1 Answers

Basing off this question/answer (and this is rough, not tested, hopefully a start):

class myClassForm(forms.Form):
    class Meta:
        model = myClass
        fields=["name"]

    reoccurrance = forms.ChoiceField(label="Reoccurance", choices=(),
                                   widget=forms.Select(attrs={'class':'selector'}))


def __init__(self, *args, **kwargs):
    super(myClassForm, self).__init__(*args, **kwargs)
    choices = []
    for pt in Reoccurance.objects.all():
      choices.append((pt.id, unicode(pt.days)))
    self.fields['reoccurrance'].choices = choices
like image 50
Joseph Avatar answered Nov 15 '22 06:11

Joseph