在使用jQuery更新文本输入后,如何使用不同的QuerySet更改ModelChoiceField?

时间:2014-05-17 13:14:30

标签: jquery django

我有一个django报告表格,基本上就像这里的表格:

class EntryForm(ModelForm):
    year = forms.IntegerField()
    month = forms.ModelChoiceField(queryset = ... )
    report_category = form.ModelChoiceField(queryset = ... ) # FKey to some category model
    report_text = forms.CharField()

最初,用户会在文本输入框中输入年份值,选择月份,然后选择类别并输入报告。

现在我希望月份下拉列表中包含尚未有报告的月份列表。在2014年1月提交报告后,下次用户输入2014年时,下拉列表将仅填充11个月(减去1月份)。

我知道如何完成查询集,但是在文本输入失去焦点之后,我仍然对如何在下拉列表中更改jQuery / AJAX感到困惑。

1 个答案:

答案 0 :(得分:3)

这是一个有效的例子:

models.py

from django.db import models
#min and max values for integer fields
from django.core.validators import MinValueValidator, MaxValueValidator

class CategoryModel(models.Model):
    category = models.CharField(max_length=20, unique=True)

    def __unicode__(self):
        return u"%s" % self.category


class EntryModel(models.Model):
    year = models.IntegerField(validators=[MinValueValidator(1900), MaxValueValidator(2100)])
    month = models.IntegerField(validators=[MinValueValidator(1), MaxValueValidator(12)])
    report_category = models.ForeignKey(CategoryModel, blank=True, null=True, on_delete=models.SET_NULL)
    report_text = models.CharField(max_length=100, blank=True, null=True, default=None)

forms.py

from django import forms
from models import CategoryModel, EntryModel


class EntryForm(forms.ModelForm):
    months = (
        ('1','January'),
        ('2','February'),
        ('3','March'),
        ('4','April'),
        ('5','May'),
        ('6','June'),
        ('7','July'),
        ('8','August'),
        ('9','September'),
        ('10','October'),
        ('11','November'),
        ('12','December'),
    )

    month = forms.ChoiceField(choices=months)
    #hidden control used to populate the month drop down list
    month_hidden=forms.ChoiceField(choices=months)
    report_category = forms.ModelChoiceField(queryset = CategoryModel.objects.all())

    class Meta:
        model=EntryModel

urls.py

from django.conf.urls import patterns, url
from views import EntryCreateView


urlpatterns=patterns('so_23711764.views',
    url(r'^/?$', EntryCreateView.as_view(), name='display_entry'),
    url(r'^reload_controls.html$', 'reload_controls_view', name='reload_controls'),

)

views.py

# Create your views here.
from django.views.generic.edit import CreateView
from models import EntryModel
from forms import EntryForm
#use json for the ajax request
from django.http import HttpResponse
from django.utils import simplejson


class EntryCreateView(CreateView):
    model = EntryModel
    form_class=EntryForm
    template_name = "so_23711764/index.html"
    #~ fields = ['name']

#view called with ajax to reload the month drop down list
def reload_controls_view(request):
    context={}
    #get the year that the user has typed
    year=request.POST["year"]
    #get months without reports (months to be displayed in the drop down list)
    context["months_to_display"]=list(EntryModel.objects.filter(year=year, report_category__isnull=True).values_list('month', flat=True).distinct())

    return HttpResponse(simplejson.dumps(context), mimetype="application/json")

的index.html

<!-- css of the application -->
<link rel="stylesheet" href="{{STATIC_URL}}css/so_23711764.css?{% now 'U' %}" />

<form id="entry_form" method="post" action="{% url display_entry %}">
    {% csrf_token %}

    {{ form.as_p }}

    <!-- in urls.py, set the path to the view reload_controls -->
    <div id="reload_controls_view" style="display: none;">{% url reload_controls %}</div>
</form>


<!-- jquery -->
<script type="text/javascript" src="{{ STATIC_URL }}jquery.min.js"></script>
<!-- csrf file to avoid 403 (FORBIDDEN) on ajax views -->
<script type="text/javascript" src="{{ STATIC_URL }}csrf.js"></script>
<!-- js related to the application -->
<script type="text/javascript" src="{{ STATIC_URL }}js/so_23711764.js?{% now 'U' %}"></script>

so_23711764.js

/* bind the event to the form, so it still works after controls are reloaded with ajax */
$('#entry_form').on('blur', '#id_year', function()
{
    reload_controls(this.value);
});


/* update the month drop down list with ajax */
function reload_controls(year)
{
    $.ajax
    ({
        type: 'POST',
        url: $("#reload_controls_view").text(),
        dataType: 'json',
        data: "year="+year,
        success: function(result)
        {
            //empty month drop down list
            $("#id_month").empty()

            //add months with no report
            $.each( result.months_to_display, function( index, value )
            {
                //use the hidden drop down list to populate the month field
                month=$("#id_month_hidden option[value='" + value + "']").text()
                //add months to the drop down list
                $('#id_month').append('<option value="'+value+'">'+month+'</option>')
            });
        },
        error: function(xhr, status, error) 
        {
            window.console&&console.log(xhr.responseText);
        }
    });
}

so_23711764.css

/* hide month_hidden control */
#id_month_hidden, label[for="id_month_hidden"]
{
    display: none;
}

现在,如果我访问页面http://127.0.0.1:8000/so_23711764/(django开发服务器),我得到:

enter image description here

使用此条目模型表:

enter image description here

如果我输入&#34; 2014&#34;对于这一年,当控制失去焦点时,我得到:

enter image description here

希望它有所帮助:)。