使用 django 和 jquery 创建依赖下拉菜单时遇到问题

Posted

技术标签:

【中文标题】使用 django 和 jquery 创建依赖下拉菜单时遇到问题【英文标题】:Having problems creating dependent drop downs using django and jquery 【发布时间】:2012-12-18 12:09:55 【问题描述】:

所以我找到了this 关于如何制作两个依赖下拉菜单的信息。我按照示例进行操作,现在当我尝试使用下拉菜单加载页面时,出现以下错误:

AttributeError at /brewkeep/beers/
'dict' object has no attribute 'status_code'

这是回溯:

Environment:


Request Method: GET
Request URL: http://192.168.1.111:8080/brewkeep/beers/

Django Version: 1.4
Python Version: 2.7.3
Installed Applications:
('django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.sites',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'brewkeep',
 'django.contrib.admin')
Installed Middleware:
('django.middleware.common.CommonMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware')


Traceback:
File "/home/di/djangostack-1.4-1/apps/django/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
  188.                 response = middleware_method(request, response)
File "/home/di/djangostack-1.4-1/apps/django/lib/python2.7/site-packages/django/middleware/common.py" in process_response
  94.         if response.status_code == 404:

Exception Type: AttributeError at /brewkeep/beers/
Exception Value: 'dict' object has no attribute 'status_code'

这是我的代码:

urls.py

(r'^brewkeep/beers/$', 'brewkeep.templatetags.brewery_beer_select'),
(r'^brewkeep/beers/(?P<brewery_id>[-\w]+)/all_json_models/$', 'brewkeep.views.beer_views.show_beers'),

models.py

class Brewery(models.Model):
    idbrewery = models.AutoField(primary_key=True)
    name = models.CharField(max_length=765)
class Beer(models.Model):
    idbeer = models.AutoField(primary_key=True)
    brewery = models.ForeignKey(Brewery, null=True, on_delete=models.SET_NULL)

templatetags.py

from brewkeep.models import Brewery
from django import template

register = template.Library()

@register.inclusion_tag("show_beers.html")
def brewery_beer_select(request):
    breweries = Brewery.objects.all().order_by('name')
    return 'breweries' : breweries

show_beers.html

<form action="" method="get" accept-charset="utf-8">
    <p>Brewery:</p>
    <select name="brewery" id="brewery">
        <option value="">Select a brewery</option>
        % for brewery in breweries %
            <option value="brewery.idbrewery">brewery.name</option>
        % endfor %    
    </select>
    <select name="beer" id="beer" disabled="true">
        <option>Select a beer</option>
    </select>
</form>
<script src=" STATIC_URL admin/js/jquery.min.js">
    $(document).ready(
        function() 
            $("select#brewery").change(function() 
                if ($(this).val() == '') 
                    $("select#beer").html("<option>Select a beer</option>");
                    $("select#beer").attr('disabled', true);
                
                else 
                    var url = "/brewkeep/beers/" + $(this).val() + "/all_json_models";
                    var brewery = $(this).val();
                    $.getJSON(url, function(beers) 
                        var options = '<option value="">Select a beer</option>';
                        for (var i = 0; i < beers.length; i++) 
                            options += '<option value="' + beers[i].pk + '">' + beers[i].fields['description'] + '</option>';
                        
                        $("select#beer").html(options);
                        $("select#beer option:first").attr('selected', 'selected');
                        $("select#beer").attr('disabled', false);
                    );
                
            );


            $("select#beer").change(function(vent) 
                if ($(this).val() == '') 
                    return;
                
            );
        
    );

</script>

beer_views.py

def show_beers(request, brewery_id):
    brewery_obj = Brewery.objects.get(idbrewery=brewery_id)
    beers = Beer.objects.all().filter(brewery=brewery_obj).order_by('name')
    json_models = serializers.serialize("json", beers)
    return HttpResponse(json_models, mimetype="application/javascript")

知道我错过了什么吗?

谢谢!

【问题讨论】:

依赖下拉列表是什么意思?一个选择框,其值由另一个选择框中的输入确定? @NickBewley 是的。我有两个下拉菜单。当我选择一个下拉列表时,我希望另一个下拉列表自动填充某些内容。然后当我选择第二个下拉菜单时,我希望页面显示某些内容。 【参考方案1】:

为了满足您的要求,我喜欢使用django-smart-selects。它包含 js 功能,可以使用名为 ChainedForeignKey 的模型字段链接您的模型。例如,如果您想要一个电话链接选择,用户可以在其中选择一种手机类型、品牌和型号(例如 Iphone 4 S 或三星 Galaxy 2),它看起来像这样:

models.py:

from smart_selects.db_fields import ChainedForeignKey

class Series(models.Model):
    series = models.CharField(max_length=10)

class Model(models.Model):
    model = models.CharField(max_length=20)
    series = models.ForeignKey(Series)

class Make(models.Model):
    make = models.CharField(max_length=20)
    model = models.ForeignKey('Model')

class Phone(models.Model):
     make = models.ForeignKey(Make)
     model = ChainedForeignKey(Model, chained_field='make', chained_model_field='make',)
     series = ChainedForeignKey(Series, chained_field='model', chained_model_field='model',)

class PhoneForm(ModelForm):
    class Meta:
        model=Phone

模板.html:

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>

% block content %
  <form action='' method='post' enctype='multipart/form-data'>
   form.as_p 
  % csrf_token %
  <input type='submit' value='submit' />
  </form>
% endblock %

编辑:基于评论

来自文档

链接字段是同一模型上的字段,该字段也应链接。 链式模型字段是链式模型的字段,对应于链式字段也链接的模型。

更改为chained_model_field='name'

【讨论】:

所以我尝试使用django-smart-selects。在我的模型中,我将Beer 模型中的Brewery 字段更改为:brewery = ChainedForeignKey(Brewery, chained_field="brewery", chained_model_field="brewery")。在我这样做之后,当我转到我的表单时,Brewery 字段的下拉列表不会填充。 按照编辑中的描述更改链式模型字段,看看是否能解决您的问题。【参考方案2】:

为您的啤酒选择中的选项编写一个简单的模板beers_select_options.html -

<option>Select a beer</option>
    % for beer in beers %
        <option value=" beer.idbeer "> beer </option>
    % enfor %

为它提供一个视图

def ajax_get_beers(request):
    idbrewery = int(request.POST['idbrewery'])
    brewery = Brewery.objects.get(idbrewery=idbrewery)
    beers = Beer.objects.filter(brewery=brewery)
    return render_to_response('beers_select.html', 'beers': beers)

然后将函数附加到啤酒厂选择框上的更改事件 -

$('#brewery').change(function() 
    var idbrewery = $(this).find(':selected').val();
    $.ajax(
        type: 'POST',
        url: '/your/ajax_get_beers/view',
        data: 'idbrewery': idbrewery
        success: function(options_html) 
            $('#beer').html(options_html);
        
    );
);

这样就可以了,除了你可能有 csrf 保护,所以你需要在你的 javascript 之前添加以下内容(参见docs) -

function csrfSafeMethod(method) 
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));


var csrftoken = $.cookie('csrftoken');
$.ajaxSetup(
    crossDomain: false, 
    cache: false,
    beforeSend: function(xhr, settings) 
        if (!csrfSafeMethod(settings.type)) 
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        
    
);

这需要jquery cookie plugin(有一个替代方法可以在django docs 中获取cookie)。

我还没有测试我的代码,但我认为这就是你真正需要的(我想你需要在你的 url conf 中添加一个 ajax 视图)。

【讨论】:

以上是关于使用 django 和 jquery 创建依赖下拉菜单时遇到问题的主要内容,如果未能解决你的问题,请参考以下文章

根据 DJango/Ajax 中的第一个选定下拉菜单创建下拉选择

django & ajax 依赖的 html 选择列表(级联下拉列表)

使用 jquery-select2 的依赖下拉内容

如何在 Django 中使用 Ajax JQuery 调用下拉列表 html 选择

Django的依赖链下拉选择列表 - 不工作

jquery依赖下拉菜单选择