Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically update Django form field options using Ajax to GET new queryset

I'm new to coding and django and I'm struggling to find the solution to the following problem having reviewed the answers I've found.

Im creating a search form with multiple fields. When the user selects the first field category (and before hitting search) I would like to dynamically change the queryset for the second field sub_category such that only related values are shown.

I have models.py as follows:

class Product(models.Model):
    category = models.ForeignKey("Category")
    sub_category = models.ForeignKey("SubCategory")

class Category(models.Model):
    name = models.CharField(max_length=256)

class SubCategory(models.Model):
    category = models.ForeignKey("Category")
    name = models.CharField(max_length=256)

And my forms.py includes:

class BasicSearchForm(forms.Form):
    category = forms.ModelChoiceField(
        label='Category',
        queryset=Category.objects.all(),
        to_field_name="name",
        empty_label=None,
        initial="Red") 
    sub_category = forms.ModelMultipleChoiceField(
        required=False,
        label='Type',
        queryset= SubCategory.objects.all(),
        to_field_name="name",
        widget=forms.Select)

And my views.py includes:

def search(request):
    if request.method == 'POST':
        form = BasicSearchForm(request.POST)
        if form.is_valid():
            category = form.cleaned_data['category']
            sub_category = form.cleaned_data['sub_category']
            return render(request, 'myapp/search.html', {'form': form})
    else:
        form = BasicSearchForm()
        return render(request, 'myapp/search.html', {'form': form})

And finally the search.html includes:

<form class="search-form" role="search" action="/search/" method="get"> 
    {{ form }} 
    <input type="submit" value="Search" />
</form>

I've played around with a few answers but nothing seems to work. I'd really appreciate some help. Thanks in advance!

Update: Thanks for the feedback. As a result I updated the following:

In my urls.py:

urlpatterns = [
url(r'^ajax/update_subcategories/$', views.update_subcategories, name='update_subcategories'),

And in my views.py:

def update_subcategories(request):
    category = request.GET.get('category', None)
    sub_category = list(SubCategory.objects.filter(category__name__exact=category).values('name'))
    return JsonResponse(sub_category, safe=False)

And I have this in my myapp/search.html:

{% block javascript %}
<script>
    $("#id_category").change(function () {
        var category = $(this).val();
        $.ajax({
            url: '{% url "myapp:update_subcategories" %}',
            data: {
                'category': category,
            },
            success: function (response) {
                var  new_options = response; 
                alert(new_options[0].name);  // works
                $('#id_sub_category').empty();
                $.each(new_options, function(key, value) {   
                    $('#id_sub_category')
                        .append($('<option>', { value : key })
                        .text(value.name)); 
                });
            }
    });
</script>
{% endblock %}

Update: The sub_category options were showing as [object Object] until I changed value to value.name and it looks like it's working. I'll test it out and close unless there are any comments.

Update: Im still having an issue with the browser back button. When a user clicks back the dropdown values have changed back to the original queryset rather than the updated version.

like image 231
Luce Rawds Avatar asked May 12 '17 13:05

Luce Rawds


1 Answers

You can't do this from Django views side, ie, backend. You could try an ajax request for implementing this kind of requests, by sending a GET request to the server for populating the drop-down or whatever you are into.

For a simple example, you could refer here

How do I POST with jQuery/Ajax in Django?

EDIT

def update_subcategories(request):
    category = request.GET.get('category', None)
    sub_category = list(SubCategory.objects.filter(category__name__exact=category).values('name'))
    return JsonResponse(dict(sub_category=sub_category))

Then in ajax response you could grab it like response.data.sub_category

like image 191
zaidfazil Avatar answered Sep 30 '22 09:09

zaidfazil