0

I've recently been learning Django and HTML but I'm completely new to JavaScript. I'm having a go at creating a database display page with a filter menu at the side. For this page I have the following code:

Model.py:

class Part(models.Model):
    PartID = models.AutoField(primary_key=True, unique=True)
    SiteID = models.ForeignKey('Site', on_delete=models.CASCADE, null=True)
    Comment = models.CharField(max_length=255, blank=True)
    Subtype = models.ForeignKey('Subtype', on_delete=models.CASCADE, null=True)
    Location = models.CharField(max_length=255, blank=True)
    ConnectedTo= models.ManyToManyField('self', null=True)
    BatchNo = models.CharField(max_length=32, blank=False, null=True)
    SerialNo = models.CharField(max_length=32,blank=True)
    Manufacturer = models.CharField(max_length=32, blank=False, null=True)
    Length = models.FloatField(blank=True, null=True)
    InspectionPeriod = models.IntegerField(blank=True, null=True)
    LastInspected = models.DateField(blank=True, null=True)
    InspectionDue = models.CharField(max_length=255, blank=True)

View.py:

@login_required(login_url='/accounts/login/')
def sites(request, site):

    siteselected = site
    warnings = 0
    expired = 0
    good = 0
    PartsAtSite = Part.objects.filter(SiteID = siteselected)
    TypesList = Type.objects.values_list('TypeName', flat=True).distinct()
    InspectionList = Part.objects.values_list('InspectionPeriod', flat=True).distinct()
    LengthList = Part.objects.values_list('Length', flat=True).distinct()
    LocationList = Part.objects.values_list('Location', flat=True).distinct()
    ManufacturerList = Part.objects.values_list('Manufacturer', flat=True).distinct()

    for part in PartsAtSite:
        if part.LastInspected == None:
            part.InspectionDue = "Yes"
            expired = expired + 1

        else:
            Deadline = part.LastInspected + timedelta(days=part.InspectionPeriod)

        if datetime.now().date() > Deadline:
            part.InspectionDue = "Yes"
            expired = expired + 1

        elif datetime.now().date() > (Deadline - timedelta(days=30)):
            part.InspectionDue = "<30 Days"
            warnings = warnings + 1
        else:
            part.InspectionDue = "No"
            good = good + 1
    part.save()

    context = {
        'TypesList': TypesList,
        'InspectionList': InspectionList,
        'LengthList': LengthList,
        'LocationList': LocationList,
        'ManufacturerList': ManufacturerList,
        'PartsAtSite': PartsAtSite,
        'expired': expired,
        'warnings': warnings,
        'good': good,
        'SiteName': Site.objects.get(SiteID = siteselected).SiteName,
        'SiteNo': Site.objects.get(SiteID = siteselected).SiteID,
    }

template = loader.get_template('myproject/sites.html')
return HttpResponse(template.render(context, request))

And the HTML for my filter div:

<div id="filterdiv" class="dark">
    <center><h3>Filters</h3></center>
    <br>

    <center>Type</center>
    <select name="Types">
        <option>All</option>
        {% for types in TypesList %}
            <option>{{types}}</option>
        {%endfor%}
    </select>
    <br>
    <br>

    <center>Inspection Period</center>
    <select name="Inspection Period">
        <option>All</option>
        {% for inspections in InspectionList %}
            <option>{{inspections}}</option>
        {%endfor%}
    </select>
    <br>
    <br>

    <center>Length</center>
    <select name="Length">
        <option>All</option>
        {% for lengths in LengthList %}
            <option>{{lengths}}</option>
        {%endfor%}
    </select>
    <br>
    <br>

    <center>Location</center>
    <select name="Location">
        <option>All</option>
        {% for locations in LocationList %}
            <option>{{locations}}</option>
        {%endfor%}
    </select>
    <br>
    <br>

    <center>Manufacturer</center>
    <select name="Manufacturer">
        <option>All</option>
        {% for manufacturers in ManufacturerList %}
            <option>{{manufacturers}}</option>
        {%endfor%}
    </select>
    <br>
    <br>
    <button>Apply Filter (TODO)</button>
    <button>Reset Filters (TODO)</button>
</div>

I am able to fill the lists just fine, but I want to be able to change it so that when I open the Type drop down box after selecting a Manufacturer, then I only get offered a list of Types from that Manufacturer.

Thanks.

3
  • Can you show the model for Type? Commented Jan 8, 2020 at 21:52
  • 1) In your code there is no connection to be seen between Type and Manufacturer (I suppose it has something to do with Subtype, but I don't think that Subtype = TypeName). So, there is no way to filter Type based on Manufacturer 2) And in the comment to the post of @JesusFung you wrote the opposite of what is in your post - that you need to filter the other way around Manufacturer based on Type. So, please, clarify these points and update your question accordingly. Commented Jan 13, 2020 at 13:57
  • 2
    I need both ways. Lets say I have a list of 10 items with all the columns mentioned above. The select boxes to filter for each column are filled only with the values used in that column rather than all total possibilities. I want that functionality to continue following a filter. So if we filter for Type A, and there are no Type A's with Manufacturer C, then Manufacturer C is dropped from the select. Commented Jan 13, 2020 at 14:02

2 Answers 2

3
+50

It looks like you are talking about "chained dropdowns feature".

In Django you can do it using django-select2 library easy.

https://django-select2.readthedocs.io/en/latest/extra.html#interdependent-select2

I am sure you can google a lot of solutions and methods of how to do it in any programming language and, of course, in Python + Django.

Just a few good examples articles from me I hope :)

Other libraries (from google)

Happy coding! :)

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

Comments

0

Using Javascript, you could add event listeners on your select elements that will trigger a request to your python backend. However you will have to edit the view so that it returns only data (usually in JSON format) in order to know which options you hide or not. Below code suppose that the view returns a simple list, you'll probably have to edit it.

document.getElementById("yourSelect").addEventListener("change", function () {
    // add a handler to the change event
    let req = new XMLHttpRequest(),
        other_select = document.getElementById("anotherSelect");
    req.open("POST", "yourUrl", true);
    // you will need to use json.loads in python code
    req.send(JSON.stringify({value: this.value}));
    req.onreadystatechange = function (res) {
        if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
            // the request is done and server returned 200 success code
            for (let i in other_select.children){
                let opt = other_select.children[i];
                if(res.indexOf(opt.value) > -1 ){
                    // shows the option if previously hidden
                    opt.style.display = "block";
                }else{
                    // hides the option
                    opt.style.display = "none";
                }
            }
        }
    }
});

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.