14

I need django modelform with 2 fields, where second field choice list depends on what was chosen in first one. My model:

class Offer(BaseModel):

    VEHICLE_TYPES = (
        ('personal','Personal car'),
        ('truck','Truck'),
    )
    vehicle_type = models.CharField(max_length=32, choices=VEHICLE_TYPES, default='personal', verbose_name='Vehicle type')

    PERSONAL_MAKES = (
        ('',''),
    )
    TRUCK_MAKES = (
        ('',''),
    )
    make = models.CharField(max_length=32)#what more??

How can I set choices of make field to PERSONAL_MAKES if vehicle_type is set to personal? How can I do this? Is it possible on model level?

dease
  • 2,975
  • 13
  • 39
  • 75

3 Answers3

5

You probably can't because it depends of user interaction with your form: your server can't know in advance which element your user will select before sending the form to the browser. You could probably achieve this using ajax. I think a working process could be :

  • Create a form with all the fields, and make make field hidden
  • Create a view (I'll call it AjaxMakeFieldView) that will catch an ajax request taking a vehicle_type argument and return the HTML for make field, populated with relevant data. Add a URL in your URLConf for this view.
  • In your template, add a Javascript binding : when user select a vehicle_type, the browser will send aan ajax request to AjaxMakeFieldView and replace hidden make field with returned HTML

If you don't want javascript, another way would be a two step form :

  • A first form with a vehicle_type field
  • Once the first form is submitted, your user get a second form with a make field, which initial data is populated depending of vehicle_type selected in the first form.

I've never done this, but Django documentation on Form wizard seems a good place to start.

Community
  • 1
  • 1
Agate
  • 3,152
  • 1
  • 19
  • 30
  • JS solution is fine, but I would need some guide with it. What should I initialy render? – dease Jun 26 '14 at 16:31
  • I edited my answer. Sorry for not providing code sample, but I'm busy now. If you don't achieve what you want, just tell me, I'll try to give more details. – Agate Jun 27 '14 at 09:25
0

This is how I ended up having two model choice fields depending on each other, on one page. In the below, field2 is depending on field1:

Javascript portion

Note that in $.each(), $.parseJSON(resp) should NOT be used (instead of just json) as we're already have it parsed by jQuery (due to the content_type='application/json' response) - see I keep getting "Uncaught SyntaxError: Unexpected token o".

$(document).ready(function() {

    $("#id_field2").empty();

    $("#id_field1").change(function(){

        $.ajax({
            url: "{% url 'ajax_get_field_2' %}",
            type: 'GET',
            data:  {field1_id: $("#id_field1").val()},
            dataType: "json",
            success: function(resp){
                $("#id_field2").empty();
                $.each(resp, function(idx, obj) {
                    $('#id_field2').append($('<option></option>').attr('value', obj.pk).text(obj.fields.code + ' (' + obj.fields.affection + ')'));
                });
            },
            error: function(jqXHR, textStatus, errorThrown) {
                alert(errorThrown);
            }
        });

    });
});

Django views.py portion

Note that this can probably be done by django-rest-framework as well. I'm obtaining fields=('id', 'code', 'affection')) from my MyModel2 - these can then be reached in JQuery using obj.fielsd.<myfieldname>.

class AjaxField2View(generic.View):

    def get(self, request, *args, **kwargs):
        field_1 = get_object_or_404(MyModel1, pk=request.GET.get('field1_id', ''))
        model2_results = MyModel2.objects.filter(k_value=field_1 .k_value)
        return HttpResponse(serializers.serialize('json', model2_results, fields=('id', 'code', 'affection')), content_type='application/json')
Community
  • 1
  • 1
SaeX
  • 17,240
  • 16
  • 77
  • 97
0

Another smart method query/free and no views needed,

is to make html tags for options that related to field A choice.

For example, in field B options:

<option example_tag="example_value" value="5"></option>

This tag should be related to either field A value or text.

Using JS to display block/none using this option tag accordingly.

And don't forget to reset value for every time user changes field A.

Yousef Alm
  • 238
  • 1
  • 8