Dropdown select option to filter a Django list

…衆ロ難τιáo~ 提交于 2020-12-12 01:47:27

问题


Coming from Angular, this was easy to do, but I am not sure where to begin on creating a dropdown form that will filter from a list of objects. Basically, I have the code below, that will pull in and display all real estate listings; I would like to create a dropdown that will have 2 selections, 'Featured' and 'New Listing' and when a user selects one, the list will filter out and display only those listings that match. Thank you for your help.

Here is my model

from django.db import models
from django.utils import timezone


class Listing(models.Model):
    FAIR = 'FAIR'
    GOOD = 'GOOD'
    VERY_GOOD = 'VERY_GOOD'
    EXCELLENT = 'EXCELLENT'

    NEW_LISTING = 'NEW_LISTING'
    PRICE_REDUCED = 'PRICE_REDUCED'
    UNDER_AGREEMENT = 'UNDER_AGREEMENT'
    SOLD = 'SOLD'

    YES = 'YES'
    NO = 'NO'

    FULL_SERVICE = 'FULL_SERVICE'
    FOR_LEASE = 'FOR_LEASE'
    WITH_REAL = 'WITH_REAL'
    QUICK_SERVE = 'QUICK_SERVE'

    CONDITION_CHOICES = (
        ('FAIR', 'Fair'),
        ('GOOD', 'Good'),
        ('VERY_GOOD', 'Very Good'),
        ('EXCELLENT', 'Excellent'),
    )

    STATUS_CHOICES = (
        ('NEW_LISTING', 'New Listing'),
        ('PRICE_REDUCED', 'Price Reduced'),
        ('UNDER_AGREEMENT', 'Under Agreement'),
        ('SOLD', 'Sold'),
    )

    FEATURED_CHOICES = (
        ('YES', 'Yes'),
        ('NO', 'No'),
    )

    LOCATION_TYPE = (
        ('FULL_SERVICE', 'Full Service'),
        ('FOR_LEASE', 'For Lease'),
        ('WITH_REAL', 'With Real'),
        ('QUICK_SERVE', 'Quick Serve'),
    )

    photo = models.ImageField(upload_to="media/properties/", max_length=250, blank=True, null=True)
    broker = models.ForeignKey('auth.User')
    phone = models.CharField(max_length=20, null=True)
    title = models.CharField(max_length=250, null=True)
    description = models.TextField(null=True)
    concept = models.CharField(max_length=250, null=True)
    location = models.CharField(max_length=250, null=True)
    size = models.CharField(max_length=250, null=True)
    seating = models.CharField(max_length=250, null=True)
    condition_choices = models.CharField(max_length=20, choices=CONDITION_CHOICES, blank=True)
    hours = models.CharField(max_length=250, null=True)
    asking_price = models.CharField(max_length=250, null=True)
    sales_price = models.CharField(max_length=250, null=True)
    rent_price = models.CharField(max_length=250, null=True)
    lease_terms = models.CharField(max_length=250, null=True)
    licenses = models.CharField(max_length=250, null=True)
    parking = models.CharField(max_length=250, null=True)
    status_choices = models.CharField(max_length=20, choices=STATUS_CHOICES, blank=True, null=True)
    featured_choices = models.CharField(max_length=5, choices=FEATURED_CHOICES, blank=True, null=True)
    location_type = models.CharField(max_length=20, choices=LOCATION_TYPE, blank=True, null=True)
    created_date = models.DateTimeField(default=timezone.now, null=True)
    published_date = models.DateTimeField(default=timezone.now, null=True)

    listing_order = models.PositiveIntegerField(default=0, blank=False, null=False)

    class Meta(object):
        ordering = ('listing_order',)

    def publish(self):
        """This is a docstring"""
        self.published_date = timezone.now()
        self.save()

    def __str__(self):
        return self.title

And here is my template

{% extends "listing/base.html" %}{% load staticfiles %}

{% block content %}

  <section class="listings mt64 mb64">
    <div class="container">
      {% for listing in listings %}
        <div class="row">
          <div class="col-md-4">
            <div class="listings-photo" style="background: #ccc url('{{ MEDIA_URL }}{{ listing.photo.name }}')no-repeat 50% 50%; background-size: cover; width: 350px; height: 220px"></div>
          </div>
          <div class="col-md-8">
            <h3 class="uppercase">{{ listing.title }}</h3>

            <p><span class="listings-title">Description:</span> {{ listing.description }}</p>

            <div class="row">
              <div class="col-md-6">
                <ul>
                  <li><span class="listings-title">Concept:</span> {{ listing.concept }}</li>
                  <li><span class="listings-title">Location:</span> {{ listing.location }}</li>
                  <li><span class="listings-title">Size:</span> {{ listing.size }}</li>
                  <li><span class="listings-title">Seating:</span> {{ listing.seating }}</li>
                  <li><span class="listings-title">Condition:</span> {{ listing.condition_choices }}
                  </li>
                  <li><span class="listings-title">Hours:</span> {{ listing.hours }}</li>
                </ul>
              </div>
              <div class="col-md-6">
                <ul>
                  <li><span class="listings-title">Asking Price:</span> {{ listing.asking_price }}
                  </li>
                  <li><span class="listings-title">Sales:</span> {{ listing.sales_price }}</li>
                  <li><span class="listings-title">Rent:</span> {{ listing.rent_price }}</li>
                  <li><span class="listings-title">Lease Terms:</span> {{ listing.lease_terms }}</li>
                  <li><span class="listings-title">Licenses:</span> {{ listing.licenses }}</li>
                  <li><span class="listings-title">Parking:</span> {{ listing.parking }}</li>
                </ul>
              </div>
            </div>
            <p>For more information please contact {{ user.first_name }} {{ user.last_name }} at {{ listing.phone }}.</p>
          </div>
        </div>
      {% endfor %}
    </div>
  </section>

{% endblock content %}

回答1:


I can see what you mean coming from Angular. The most classical way of doing that in Django would be creating a form with all the fields you need, then passing it to the view to process the data, filter records and pass them back to the template. I'll try to provide a basic example so you can hopefully get the idea:

Index.html:

<form action="{% url 'index' %}" method="get">
    <label for="featured">Format</label>
    <select name="featured">
        <option value="Yes" />Yes</option>
        <option value="No" />No</option>
    <input type="submit" name="featured" value="Filter" />
</form>     

Views.py

def index(request, template_name='index.html'):

    if request.GET.get('featured'):
        featured_filter = request.GET.get('featured')
        listings = Listing.objects.filter(featured_choices=featured_filter)
    else:
        listings = Listing.objects.all()

    context_dict = {'listings': listings}
    return render(request, template_name, context_dict)

This is pretty self-explanatory. If there's a "featured" parameter in GET, list will get filtered, otherwise it will pass all objects. Obviously we're looking at page refresh every filter request, if you expect a bit more of a one-page experience, you have to go for ajax and post requests, or something. Also, keep in mind this snippet is just a hard-coded example. Ideally, you would want to create a ModelForm class and instantiate that, then pass it to the template - a lot more readable and maintainable if you have more filter fields. If there's complex filtering involved, you would also probably want to have an additional view for filtering purposes, but this works too, it just gets messy really quick.




回答2:


Thanks for Zephi, your tip helped me a lot, but for me, only worked after I changed index.html to this:

index.html

<form action="{% url 'index' %}" method="get">
    <label for="featured">Format</label>
    <select name="featured">
        <option value="Yes" />Yes</option>
        <option value="No" />No</option>
    </select>   <!-- ADDED THIS LINE -->
    <input type="submit" value="Filter" />   <!-- DELETE name="featured" FROM ORIGINAL CODE -->  
</form>

here fragments from my app's code:

index.html

<form action="{% url 'index' %}" method="get">
    <label for="featured">Format</label>
    <select name="featured">
        {% for adoption in typeList %} 
            <option value="{{ adoption }}">{{ adoption }}</option>
        {% endfor %}
     </select>
     <input type="submit" value="Filter" />
</form>

views.py

def index(request, template_name='index.html'):
    if request.GET.get('featured'):
        featured_filter = request.GET.get('featured')
        query = Unit.listType.filter(unitType=featured_filter)
    else:
        query = Unit.listType.all()
    typeList = query.order_by('unitType').values_list('unitType',flat=True).distinct()
    _dict = {}
    for x in range(len(typeList)):
        _dict[typeList[x]] = typeList[x]
    return render(request, 'index.html', {'query':query, 'typeList':_dict})


来源:https://stackoverflow.com/questions/33726759/dropdown-select-option-to-filter-a-django-list

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!