2016-07-10 20 views
1

In Django 1.9 habe ich eine Datenbanktabelle, die Automarken enthält. Ich versuche, einen Index von Automarken zu erstellen, wie er in einem Lehrbuch zu finden ist. Zum Beispiel:Iterieren durch ein Objekt in Django Vorlage

A
Aston Martin
Audi
...
B
Bentley
BMW
...

Hier ist Code aus meiner Ansicht. py:

def home(request): 

    car_index = {} 
    alphabet = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N', 
     'O','P','Q','R','S','T','U','V','W','X','Y','Z'] 

    for letter in alphabet: 
     car_index[letter] = {} 
     car_index[letter]['title'] = letter 
     car_index[letter]['brands'] = Cars.objects.filter(brand__startswith = letter) 

    return render(request, 'cars/home.html', {'car_index':car_index}) 

Hier ist Code aus meiner home.html Vorlage:

{% for each in car_index %} 

    {{ each.title }} 

    {% for brand in each.brands %} 
     <a href="{{ brand.link }}">{{ brand.name }}</a><br> 
    {% endfor %} 

{% endfor %} 

In view.py, ich habe versucht, .values() im queryset, .items() im Template-Kontext. In der Vorlage habe ich versucht car_index.items, each.brands.items, each.brands[0]. Nichts funktioniert. Mit dem obigen Code bekomme ich die Titel: E D X I A U H B T S N K Q Z J Y W V O L R F G P C M, aber keine Links. (Ich weiß, wie zu sortieren, aber die Arbeit auf Links zuerst)

ich gelesen habe:

https://docs.djangoproject.com/en/1.9/ref/templates/builtins/#for

how to iterate through dictionary in a dictionary in django template?

+1

sieht gut aus, was sehen Sie, wenn Sie 'each.brands' in Vorlage drucken? – doniyor

+1

Können Sie das Ergebnis von '{% für jedes in car_index%} {{each}} {% endfor%}' anzeigen. Haben Sie auch versucht, '{% für Schlüssel, Wert in jedem. Artikel%}' – kapilsdv

+0

@Doniyor 'each.brands' war leer. @KapilSachdev, Ihr Kommentar hat mir geholfen, es herauszufinden. Geänderter Code zu: '{% für k, v in car_index.items%}' und '{{v.title}}' und '{% für Marke in v.brands%}'. Argh, nachdem ich auf andere SO-Antworten zurückgekommen bin, kann ich die Antwort jetzt in Sichtweite sehen. Aber mit ihren Daten strukturiert ein bisschen anders, machte mein Gehirn nicht den Sprung. Danke Leute. Ich kenne die SO-Etikette nicht, um die akzeptierte Antwort auf einen Kommentar zu geben, der beantwortet. – FeFiFoFu

Antwort

1

besserer Ansatz - sauberer Code, abgesehen von db effeciency:

alphabet = ['A','B','C','D','E','F','G', ..] 

brands_list = [] 
for letter in alphabet: 
    letter_ = {'cars': Cars.objects.filter(brand__startswith=letter), 'letter': letter} 
    brands_list.append(letter_) 

return render(request, 'cars/home.html', {'brands': brands_list}) 

Vorlage

{% for brand in brands %}  
    {{ brand.letter }}  
    {% for car in brand.cars %} 
     <a href="{{ car.link }}">{{ car.name }}</a><br> 
    {% endfor %} 
{% endfor %} 
+1

Wow, sieht ähnlich wie mein Code auf den ersten Blick, aber eigentlich ist viel anders. Ich habe viel gelernt, danke! Ich habe dies aus mehreren Gründen als akzeptierte Antwort markiert: Erstens, die Struktur von 'brands_list' ist besser als mein' car_index', weil sie den von mir hinzugefügten Schlüssel ('car_index [letter]') eliminiert, was wiederum die Notwendigkeit von 'eliminiert {% für k, v in car_index.items%} '. Besser aussehende Vorlage und so dachte ich, die Vorlage hätte ursprünglich funktionieren sollen. Zweitens verwendet es ein Array anstelle des Objekts, das ich verwendet habe, was bedeutet, dass ich das Objekt nicht mehr sortieren muss - das Alphabet kommt in der richtigen Reihenfolge heraus. – FeFiFoFu

+0

@FeFiFoFu froh, ich könnte helfen – doniyor

1

Kann ich abraten Sie von Ihrem aktuellen Ansatz?

Sie führen einen vollständigen Tabellenscan in 26 Schritten durch. Wenn die Markenspalte nicht eindeutig ist, werden Sie feststellen, dass die Namen wiederholt werden. Wenn Sie Millionen von Datensätzen haben, werden Sie die Speicherkapazität erschöpfen. Wenn die Marke Spalte keinen Index haben, werden Sie feststellen, dass die folgende Abfrage ist sehr, sehr langsam:

Cars.objects.filter(brand__startswith = letter) 

Es gibt eine wirklich einfache Lösung ist. Auch das könnte eine vollständige Table-Scan, beinhalten aber zumindest Sie ausführen eine langsame Abfrage statt 26.

Cars.objects.raw('SELECT max(id), SubStr(brand,1,1) AS letter, brand 
    FROM myapp_cars GROUP BY substr(brand,1,1)') 

Dies ist bei der Verwendung von rohen Abfragen. Wenn Sie sie nicht mögen und Glück haben, auf Postgresql zu sein, können Sie distinct verwenden, um das selbe objektiv eleganter zu erzielen.

+0

Ich sehe was du sagst. Ich bin nicht mit SQL vertraut, also würde ich nur Ihren Code kopieren, ohne zu verstehen, was schlecht ist. Aber danke, dass Sie auf die Ineffizienz hingewiesen haben. Sobald ich die Version 1 fertig habe, werde ich SQL lernen und/oder den Python-Code ändern, um die DB einmal zu treffen. – FeFiFoFu

+0

Hallo, ich habe einige meiner alten Antworten durchgegangen, als ich auf dieses Problem gestoßen bin. Wie ist das gelaufen? – e4c5

+0

Ich lerne SQL jetzt wegen dir – FeFiFoFu

1

Ich bin froh, dass mein Kommentar helfen Ihnen irgendwie Ihr Problem zu lösen. Ich poste es nur als Antwort, damit es anderen helfen kann.

{% for each in car_index %}, iteriert nur den aktuellen dict aus und entpacken Sie nicht die dict von dicts, die die Marken dict enthalten

Da der car_index Kontext ein Wörterbuch ist, zeigen die folgenden würde die Schlüssel und Werte des car_index Wörterbuchs und entpackt die Marken dict.

{% for key,value in car_index.items %} 

    {{ value.title }} 

    {% for brand in value.brands %} 
     <a href="{{ brand.link }}">{{ brand.name }}</a><br> 
    {% endfor %} 

{% endfor %} 
Verwandte Themen