2

So I found this about how to make two dependent drop downs. I followed the example, and now when I try and load the page with the drop down menus, I get this error:

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

This is the traceback:

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'

This is my 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")

Any idea what I'm missing?

Thanks!

2
  • What do you mean by dependent dropdown? A select box whose values are determined by the input in another select box? Commented Jan 4, 2013 at 6:38
  • @NickBewley Yes. I have two drop downs. When I select one dropdown, I want the other dropdown to auto fill with certain things. Then when I select the 2nd drop down, I want the page to display certain things. Commented Jan 5, 2013 at 17:21

2 Answers 2

3

To do what you ae asking for, I like to use django-smart-selects. It includes js functionality to chain your models with a modelfield called ChainedForeignKey. For example, if you wanted to have a Phone chained select, where a user could select a type of phone, make, and model (ex. Iphone 4 S, or Samsung Galaxy 2), it would look something like this:

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

template.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 %}

EDIT: based on comment

From the docs

The chained field is the field on the same model the field should be chained too. The chained model field is the field of the chained model that corresponds to the model linked too by the chained field.

Change to chained_model_field='name'.

Sign up to request clarification or add additional context in comments.

2 Comments

So I tried using django-smart-selects. In my models, I changed my Brewery field in my Beer model to this: brewery = ChainedForeignKey(Brewery, chained_field="brewery", chained_model_field="brewery"). After I do that, when I go to my form, the drop down for the Brewery field doesn't populate.
Change the chained model field as described in the edit and see if that solves your issues.
0

Write a simple template, beers_select_options.html, for the options in your beer select -

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

serve it up with a view

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})

Then attach a function to the change event on the brewery select box -

$('#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);
        }
    });
});

That would do it, except that you've probably got csrf protection, so you'll need to add the following before your javascript (see the 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);
        }
    }
});

This requires the jquery cookie plugin (there's an alternative for getting the cookie in the django docs).

I haven't tested my code, but I think it's all you really need (I guess you'll need an addition to your url conf for the ajax view).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.