Django, Views und Querysets

Django, Flask, Bottle, WSGI, CGI…
Antworten
Nothyman
User
Beiträge: 3
Registriert: Samstag 9. Januar 2010, 04:59
Wohnort: B*

Hallo alle zusammen,

ich bin neu hier im Forum und freue mich euch gefunden zu haben, nicht zuletzt weil ich denke, dass ihr mir bei meinem Problem helfen könnt.
Ich beschäftige mich erst seit relativ kurzer Zeit mit Python bzw. Django und möchte mit diesem Framework ein einfaches Webforum umsetzen. Ich möchte auch Vorneweg um Verzeihung bitte, wenn ich per SuFu mögliche Lösungen für mein Problem nicht gefunden habe. Man poste dann bitte entsprechenden Links.

Ich habe ein Verständnisproblem bezüglich des Views "index", der alle Foren nach Kategorien sortiert anzeigt. Ich verstehe zwar die Datenbankabfrage per Queryset und unter Berücksichtigung der Fremdschlüsselbeziehung zwischen den Models "Category" und "Board", allerdings bin ich bisher nicht in der Lage gewesen das zu implementieren; beziehungsweise funktionierten einige "Proben" durchaus fehlerfrei, es wurde mir im Browser aber auch nix angezeigt.

Wie muss der View und / oder das Tempalte ausehen um folgende Ausgabe zu erhalten?

Code: Alles auswählen

--Kategorie1
----Forum1
----Forum2
----Forum3
--Kategorie2
----Forum4
----Forum5
----Forum6
Ich habe jetzt schon viele Snippets, gefunden und geslesen, trotzalledem komm ich dem aber nicht auf die Spur. Auch habe versucht mich an den Sourcen von Snapboard, PythonBB, PyBB, u.a. zu orientieren. Da ich total auf dem Schlauch stehe wäre ich über eine Step-by-Step-Hilfe bzgl. dem View und auch kritischen Blicken auf das Template sehr dankbar.

Code: Alles auswählen

class Category (models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField("title", max_length=255)
    rank = models.IntegerField("rank");
    class Meta:
        ordering = ['rank']
        verbose_name = "Category"
        verbose_name_plural = "Categories"
    def __unicode__(self):
        return u'%s' % (self.title)

Code: Alles auswählen

class Board (models.Model):
    id = models.AutoField(primary_key=True)
    category = models.ForeignKey(Category)
    title = models.CharField("title", max_length=255, unique=True)
    description = models.CharField("description", max_length=255)
    rank = models.IntegerField("rank");
    class Meta:
        ordering = ['rank']
        verbose_name = "Board"
        verbose_name_plural = "Boards"
    def __unicode__(self):
        return u'%s' % (self.title)

Code: Alles auswählen

{% extends "forum_base.html" %}
{% block content %}
{% for elem in queryset %}
<h3>{{ elem.cat }} - </h3>
    {% for forum in elem.forums %}
        {{forum}}<br />
    {% endfor %}
{% endfor %}

Code: Alles auswählen

def index(request):
    _boards = Board.objects.select_related().all()
    ToReturn = {}
    forums = {}
    for board in _boards:
        result = ToReturn.setdefault(board.category.id, {'cat' : board.category, 'forums' : []})
        result['forums'].append(board)
        forums[board.id] = board
    return render_to_response('forum/forum_list.html', {'queryset':ToReturn})

Mit Dank für eure Bemühungen und hilfreichen Tipps verbleibe ich mit freundlichen Grüßen

Nothyman
apollo13
User
Beiträge: 827
Registriert: Samstag 5. Februar 2005, 17:53

Hi, ein paar tipps:
* Django ist durch und durch Unicode, es reicht also in deiner __unicode__ Methode self.title zu returnen
* schau dir mal http://docs.python.org/library/itertool ... ls.groupby an, das ist im prinzip genau das was du willst…
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Eigentlich müsste dies reichen:

Code: Alles auswählen

{% for cat in categories %}
    <h3>{{ cat.title }}</h3>
    {% for board in cat.category_set.all %}
        <h4>{{ board.title }}</h4>
    {% endfor %}
{% endfor %}
Ich würde allerdings

Code: Alles auswählen

class Board(models.Model):
    category = models.ForeignKey(Category, related_name='boards')
benutzen, um dann statt `category_set` lieber `boards` benutzen zu können.

Stefan
Zuletzt geändert von sma am Montag 11. Januar 2010, 11:57, insgesamt 1-mal geändert.
Nothyman
User
Beiträge: 3
Registriert: Samstag 9. Januar 2010, 04:59
Wohnort: B*

Vielen Dank, für die beiden Tipps. Habe meine Models wie vorgeschlagen verändert und das Template entsprechend dem Vorschlag von sma im vorigen Post angepass. Meinen View habe ich bisher nicht verändert.
Leider folgte eine leere HTML-Seite als Ausgabe.

Ein simples

Code: Alles auswählen

{{ categories }}
im Template gibt mir folgendes aus:

Code: Alles auswählen

{1: {'forums': [<Board: Kommunikation>, <Board: Offtopic>], 'cat': <Category: Allgemein>},
   2: {'forums': [<Board: Snippets>, <Board: Ideeen>], 'cat': <Category: Inhalte & Entwicklung>}} 
Nachdem ich dann auf http://www.zedkep.com/blog/index.php?/a ... lates.html gestossen bin, habe ich mein Template wie folgt angepasst:

Code: Alles auswählen

{% for key, value in categories.items %}
    <h3>{{ value.cat }}</h3>
    {% for elem in value.forums %}
    <h4>{{ elem }}</h4>
    {% endfor %}
{% endfor %}
Jetzt funktioniert es einwandfrei, warum habe ich bis jetzt nicht wirklich verstanden. Leider muss ich sagen, dass ich das neue Template eher schlechter als das vorgeschlagene finde, weil komplizierter. Warum funktioniert dies aber und das alte nicht? Welche Änderungen muss ich am View vornehmen um das von sma vorgeschlagene Template nutzen zu können.

Vielen Dank für die Tipps. Mein Problem ist gelöst und der View und das Template funktionieren wie gewünscht. Gerne würde ich aber diesen Thread noch ein wenig am Leben erhalten wollen um die noch offenen Fragen zu klären.

Nothyman
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Dein "ToReturn" enthält ein Dictionary von board.category.id auf ein Dictionary mit anderen Dingen. Warum? Dies sollte reichen:

Code: Alles auswählen

render_to_response('...', dict(categories=Category.objects.all()))
Stefan
Nothyman
User
Beiträge: 3
Registriert: Samstag 9. Januar 2010, 04:59
Wohnort: B*

Wenn ich nur ein Dictionary mit allen Objekten vom Model "category" an das Template übergeben würde, könnte ich dort nicht die Foren mit auflisten. Mein View "index" tut ja eigentlich nichts anderes als das Queryset aus der Variable "_boards" in eine andere Struktur umzubauen:

Code: Alles auswählen

_boards = Board.objects.select_related().all()
Das so zurückgegebe Queryset enhält eine Liste aller Foren, deren Elemente, soweit ich das verstanden habe, ein Dictionaries sind. Jeder Schlüssel dieser Dictionaries entspricht dabei einem Feld des Models "Board".

Code: Alles auswählen

for board in _boards:
        result = ToReturn.setdefault(board.category.id, {'cat' : board.category, 'forums' : []})
        result['forums'].append(board)
        forums[board.id] = board
Mit dieser Schleife in meinem View "index" wird das Queryset in "_boards" umgebaut. So erhalte ich ein neues Dictionary mit den IDs der Kategorien als Schlüssel, während jeder Wert ein Dictionary mit den Schlüssel "category" und "forums" ist. Die zweite Zuordnung ist wieder eine Liste. So habe ich ein neues "Queryset", das alle Foren sortiert nach Kategorien enthält; und dieses übergebe ich an das Template.

Grüße

Nothyman
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Nothyman hat geschrieben:Wenn ich nur ein Dictionary mit allen Objekten vom Model "category" an das Template übergeben würde, könnte ich dort nicht die Foren mit auflisten.
Doch. Siehe mein Beispiel. Jede Kategorie kennt ihre Foren.

Stefan
Antworten