简体   繁体   中英

Django - How to sort through a queryset based on the value of an attribute

I have created the following model which stores information for an html5 banner. I have a ForeignKey to associate the banner with a specific project.

class BannerCode(models.Model):
    ROUNDS_LIST = (
        ('1', '1'),
        ('2', '2'),
        ('3', '3'),
        ('4', '4'),
        ('5', '5'),
        ('6', '6'),
    )

    project = models.ForeignKey(Project)
    client = models.ForeignKey(Client, null=True, blank=True)
    name = models.CharField(max_length=256, null=True, blank=True)
    width = models.CharField(max_length=3, null=True, blank=True)
    height = models.CharField(max_length=3, null=True, blank=True)
    review_round = models.CharField(max_length=3, choices=ROUNDS_LIST, default=1)

I need to print out in my template something like this desired Output:

Round 1

  • banner name
  • banner name
  • banner name
  • banner name

Round 2

  • banner name
  • banner name
  • banner name
  • banner name

I am having trouble understanding how to loop through the objects and sort by the review_round attribute.

I created a custom filter and am able to sort them in one long list:

@register.filter
def sort_by(queryset, order):
    return queryset.order_by(order)

In Template:

{% for b in project.bannercode_set.all|sort_by:'review_round' %}
    {{ b.review_round }}
{% endfor %}

This loop works great for outputting something like this:

Current Output

  • banner name, round 1
  • banner name, round 1
  • banner name, round 2
  • banner name, round 3

How can I create a for loop that would match my desired output?

In your view:

banners = BannerCode.objects.all().order_by('review_round') 

***if you want to reverse order use '-review_round'

Then in your template:

{% for item in banners %}

    <li>{{ item.name }}</li>

{% endfor %}

您更改{{ b.review_round }}在你的模板{{ b.name }}

In this scenario you're either going to have to have different sections in your template for the different review rounds, or define the context for your template differently to render the headers.

Here's an example which defines the variable review_round_groups to hold our template context. review_round_groups is a dictionary which maps the header of each section to the queryset it should render (in this case each queryset is the result of filtering on a different round_review):

review_round_groups = {}

for review_round_int in BannerCode.ROUNDS_LIST:  # Group BannerCode's into review rounds
    review_round_int = review_round_int[0]  # Value to filter on
    review_round_groups['Round %d' % review_round_int] = BannerCode.objects.filter(review_round=review_round_int)

Then in your template:

{% for banner_group_name, banner_qs in review_round_group.items %}
    <h1>{{ banner_group_name }}</h1>
    {% if banner_qs.exists %}
        <ul>
        {% for banner in banner_qs %}
            <li>{{ banner.name }}</li>
        {% endfor %}
        </ul>
    {% endif %}
{% endfor %}

This should render all your different review rounds as unordered lists, if there are no banners for a certain review_round then it will not display that group. If you want to still render the header for an empty review round group, just remove the {% if banner_qs.exists %} .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM