[Django] i18n model und QuerySet...

Django, Flask, Bottle, WSGI, CGI…
Antworten
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ich arbeite daran, mein Blog besser zu Internationalisieren. Dazu habe ich nun das Model aufgesplittet und sieht vereinfacht so aus:

Code: Alles auswählen

class Entry(models.Model):
    sites = models.ManyToManyField(Site)

class Content(models.Model):
    entry = models.ForeignKey(Entry)
    language = models.ForeignKey(Language)
    content = models.TextField()
    is_public = models.BooleanField(default=True)
Einen QuerySet zu erzeugen, der alle Inhalte in einer bestimmten Sprache ausgibt ist nicht sonderlich schwer.

Allerdings möchte ich das haben:
* Gib mir alle Einträge bevorzugt in der vom Client gewünschten Sprache
* Wenn nicht in der gewünschten Sprache, dann in der "default"-Sprache

Ich frage mich, ob das in einem QuerySet überhaupt funktioniert?

Ich hab eine sortierte Liste der Sprachen, die der Client haben will. Doch wie sage ich der DB das ich jeweils nur einen Eintrag haben möchte?

Mal ein Beispiel:

Vorhandene Einträge (EN ist default):
1. Eintrag ist in DE und EN vorhanden
2. Eintrag nur in EN vorhanden
3. in DE, EN und ES vorhanden

Ein Client mit [DE, EN] erhält also:
1. Eintrag in DE
2. Eintrag in EN
3. Eintrag in DE

Ein Client mit [ES, EN] erhält:
1. EN
2. EN
3. ES

Hinzu kommt, das Pagination verwendet wird...

Gibt es so was wie OR-Verknüpfung mit "gibt nur das erste" ?

EDIT: Also laut den Aussagen von den Leuten in #django-de geht das mit dem ORM nicht. Man muß mindestens zwei Querys machen oder aber mit raw SQL CASE arbeiten...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Eine erste Implementierung hab ich nun mit https://github.com/jedie/PyLucid/commit ... 838#diff-0

Aber ich muß sagen, das es doch arg umständlich wirkt :(

Damit das Pagination richtig funktioniert habe ich auch z.Z. drei Queries:
1. Query: Filtern welche Einträge überhaupt in Frage kommen und das dann in den Paginator packen.

2. Query: Die Informationen zum Filtern der Sprache aus DB holen, aber nur die Einträge, die auf der aktuellen Paginator Seite sind.

3. Query: Die eigentlichen Inhalte aus der DB holen, die dann auch wirklich angezeigt werden.

Das eigentliche Filtern nach der bevorzugten Sprache erscheint mir auch ein wenig umständlich:

Code: Alles auswählen

        # Group language & content by entry
        values_list = queryset.values_list("pk", "entry", "language")
        entry_dict = {}
        for content_id, entry_id, language_id in values_list:
            if entry_id not in entry_dict:
                entry_dict[entry_id] = [(language_id, content_id)]
            else:
                entry_dict[entry_id].append((language_id, content_id))


        # Create a list of content id's which the best language match
        used_ids = []
        for existing_entries in entry_dict.values():
            temp_content_dict = dict(existing_entries)
            for prefered in prefered_languages_pk:
                if prefered in temp_content_dict:
                    used_ids.append(temp_content_dict[prefered])
                    break

        # Get the current blog content we display on the current paginator page
        used_content = self.model.objects.filter(pk__in=used_ids)

Wer eine bessere Lösung basteln möchte, der kann das hiermit machen:

Code: Alles auswählen

#values_list = queryset.values_list("pk", "entry", "language")
values_list = [
    (7, 5, "en"), (6, 5, "de"),
    (1, 4, "en"), (2, 4, "de"), (5, 4, "es"),
    (3, 3, "en"), (8, 3, "es"),
    (9, 1, "en"), (10, 1, "xx"),
    (4, 2, "en")
]

def filter_by_language(prefered_languages_pk):
    """
    >>> filter_by_language(("de", "en"))
    [9, 4, 3, 2, 6]

    >>> filter_by_language(("en", "de"))
    [9, 4, 3, 1, 7]

    >>> filter_by_language(("xx", "en"))
    [10, 4, 3, 1, 7]

    >>> filter_by_language(("es", "en", "de"))
    [9, 4, 8, 5, 7]

    >>> filter_by_language(("de", "es", "en"))
    [9, 4, 8, 2, 6]
    """
    entry_dict = {}
    for content_id, entry_id, language_id in values_list:
        if entry_id not in entry_dict:
            entry_dict[entry_id] = [(language_id, content_id)]
        else:
            entry_dict[entry_id].append((language_id, content_id))


    # Create a list of content id's which the best language match
    used_ids = []
    for existing_entries in entry_dict.values():
        temp_content_dict = dict(existing_entries)
        for prefered in prefered_languages_pk:
            if prefered in temp_content_dict:
                used_ids.append(temp_content_dict[prefered])
                break

    # Get the current blog content we display on the current paginator page
    #used_content = self.model.objects.filter(pk__in=used_ids)
    return used_ids

if __name__ == "__main__":
    import doctest
    print doctest.testmod()
    print "DocTest end."

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Antworten