[django] Admin: dynamische Info einfügen

Django, Flask, Bottle, WSGI, CGI…
Antworten
Benutzeravatar
tjuXx
User
Beiträge: 67
Registriert: Freitag 21. September 2007, 09:25
Wohnort: Bremerhaven
Kontaktdaten:

Code: Alles auswählen

#models.py
class TopMenuArticle(models.Model):

    TYPE = models.CharField("Typ", max_length=1, choices=(('P', 'Promotion'), ('E', 'Event'), ('S','Sales & Marketing')))
    pos_CHOICES = ((1,'01'),(2,'02'),(3,'03'),(4,'04'),(5,'05'),(6,'06'),(7,'07'),(8,'08'),(9,'09'),(10,'10'),(11,'11'),(12,'12'))
    position = models.SmallIntegerField(choices=pos_CHOICES)
    # ... other fields
    
    class Meta:
        unique_together = ("TYPE", "position")
Je Typ soll jede Position einmal belegt werden können. Das funktioniert mit unique_together auch wunderbar. Allerdings ist die Usability auf diese Art und Weise nicht sehr gut, da man selber wissen muss welche Positionen schon belegt sind.

Um des zu verbessern würde ich gerne eine Tabelle hinzufügen, in der angegeben ist, welche Positionen Belegt und welche Frei sind.
Dazu habe ich die Felder TYPE und position in einem Fieldset zusammengefasst und eine description angegeben die ich nach den vorhandenen Instanzen generiere:

Code: Alles auswählen

#admin.py
class TopMenuArticleAdmin(admin.ModelAdmin):
    free = 'style="background-color:#afa;"'
    used = 'style="background-color:#faa;"'
    styles = {'P01':free,'P02':free,'P03':free,'P04':free,'P05':free,'P06':free,
              'P07':free,'P08':free,'P09':free,'P10':free,'P11':free,'P12':free,
              'E01':free,'E02':free,'E03':free,'E04':free,'E05':free,'E06':free,
              'E07':free,'E08':free,'E09':free,'E10':free,'E11':free,'E12':free,
              'S01':free,'S02':free,'S03':free,'S04':free,'S05':free,'S06':free,
              'S07':free,'S08':free,'S09':free,'S10':free,'S11':free,'S12':free,}
    for entry in TopMenuArticle.objects.all():
        styles['%s%02i'%(entry.TYPE,entry.position)] = used
    html= """<table>
    <tr><td colspan="4" style="text-align:right;">Frei: </td><td style="background-color:#afa;"></td>
        <td colspan="4" style="text-align:right;">Belegt: </td><td style="background-color:#faa;"></td>
        <td colspan="3"></td></tr>
    <tr><td>Promotion</td>
    <td %(P01)s>1</td><td %(P02)s>2</td><td %(P03)s>3</td><td %(P04)s>4</td>
    <td %(P05)s>5</td><td %(P06)s>6</td><td %(P07)s>7</td><td %(P08)s>8</td>
    <td %(P09)s>9</td><td %(P10)s>10</td><td %(P11)s>11</td><td %(P12)s>12</td></tr>
    <tr><td>Event</td>
    <td %(E01)s>1</td><td %(E02)s>2</td><td %(E03)s>3</td><td %(E04)s>4</td>
    <td %(E05)s>5</td><td %(E06)s>6</td><td %(E07)s>7</td><td %(E08)s>8</td>
    <td %(E09)s>9</td><td %(E10)s>10</td><td %(E11)s>11</td><td %(E12)s>12</td></tr>
    <tr><td>Sales & Marketing</td>
    <td %(S01)s>1</td><td %(S02)s>2</td><td %(S03)s>3</td><td %(S04)s>4</td>
    <td %(S05)s>5</td><td %(S06)s>6</td><td %(S07)s>7</td><td %(S08)s>8</td>
    <td %(S09)s>9</td><td %(S10)s>10</td><td %(S11)s>11</td><td %(S12)s>12</td></tr>
    </table>"""%styles
    fieldsets = (
        ('Position', {
            'description': html,
            'fields': ('TYPE', 'position')
        }),
        (None, {
            'fields': ('title', 'text', 'image', 'public')
        }),
    )
Das klappt soweit auch ganz gut. Allerdings wird die description nach dem Ändern oder Hinzufügen neue Instanzen nicht aktualisiert.

Hat jemand eine Idee wie ich einen Reload der Tabelle erzwingen kann??

Vielleicht hat auch jemand eine bessere Idee die fehlende Info in den Admin Bereich einzubauen.

tjuxx
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

So ganz habe ich es nicht verstanden ;)

Mal so ins Blaue hinein: Du kannst beim ModelAdmin eine eigene Form angeben. Das könnte eine Modelform sein, mit einem eigenen, dynamischen Choice-Field, welches nur die freien Positionen zur Auswahl anzeigt...

Btw. unique_together funktioniert nur dann, wenn die Datenbank es unterstützt. Bei SQLite ist das nicht der Fall.
Hab mir deswegen einen eigene Lösung geschrieben: https://github.com/jedie/django-tools/b ... ils.py#L23

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
tjuXx
User
Beiträge: 67
Registriert: Freitag 21. September 2007, 09:25
Wohnort: Bremerhaven
Kontaktdaten:

Nach mehreren Fehlschlägen habe ich jetzt endlich eine funktionierende Lösung gefunden:

Ich habe einen eigenen Template-Tag geschrieben der mir die Tabelle ausgibt:

Code: Alles auswählen

# django/contrib/admin/templatetags/positionUsed.py
from django import template
from mainpage.models import TopMenuArticle

def do_used_positions(parser, token):
    return UsedPositionNode()

class UsedPositionNode(template.Node):
    def render(self, context):
        free = 'style="background-color:#afa;"'
        used = 'style="background-color:#faa;"'
        styles = {'P01':free,'P02':free,'P03':free,'P04':free,'P05':free,'P06':free,
                  'P07':free,'P08':free,'P09':free,'P10':free,'P11':free,'P12':free,
                  'E01':free,'E02':free,'E03':free,'E04':free,'E05':free,'E06':free,
                  'E07':free,'E08':free,'E09':free,'E10':free,'E11':free,'E12':free,
                  'S01':free,'S02':free,'S03':free,'S04':free,'S05':free,'S06':free,
                  'S07':free,'S08':free,'S09':free,'S10':free,'S11':free,'S12':free,}
        for entry in TopMenuArticle.objects.all():
            styles['%s%02i'%(entry.TYPE,entry.position)] = used
        html= """<table>
        <tr><td colspan="4" style="text-align:right;">Frei: </td><td style="background-color:#afa;"></td>
        <td colspan="4" style="text-align:right;">Belegt: </td><td style="background-color:#faa;"></td>
        <td colspan="3"></td></tr>
        <tr><td>Promotion</td>
        <td %(P01)s>1</td><td %(P02)s>2</td><td %(P03)s>3</td><td %(P04)s>4</td>
        <td %(P05)s>5</td><td %(P06)s>6</td><td %(P07)s>7</td><td %(P08)s>8</td>
        <td %(P09)s>9</td><td %(P10)s>10</td><td %(P11)s>11</td><td %(P12)s>12</td></tr>
        <tr><td>Event</td>
        <td %(E01)s>1</td><td %(E02)s>2</td><td %(E03)s>3</td><td %(E04)s>4</td>
        <td %(E05)s>5</td><td %(E06)s>6</td><td %(E07)s>7</td><td %(E08)s>8</td>
        <td %(E09)s>9</td><td %(E10)s>10</td><td %(E11)s>11</td><td %(E12)s>12</td></tr>
        <tr><td>Sales & Marketing</td>
        <td %(S01)s>1</td><td %(S02)s>2</td><td %(S03)s>3</td><td %(S04)s>4</td>
        <td %(S05)s>5</td><td %(S06)s>6</td><td %(S07)s>7</td><td %(S08)s>8</td>
        <td %(S09)s>9</td><td %(S10)s>10</td><td %(S11)s>11</td><td %(S12)s>12</td></tr>
        </table>"""%styles
        return html

register = template.Library()
register.tag('used_positions', do_used_positions)
Im Admin fieldset Template habe ich dann die Ausgabe der Beschreibung so verändert, dass mein eigener Tag anstelle der Beschreibung ausgegeben wird:

Code: Alles auswählen

    {% if fieldset.description %}
        {% if fieldset.description == "positionsUSED" %}
            {% load positionUsed %}{% used_positions %}
        {% else %}
            <div class="description">{{ fieldset.description|safe }}</div>
        {% endif %}
    {% endif %}
Jetzt kann ich in der admin.py ein Fieldset mit der entsprechenden Beschriebung ('positionsUSED') definieren:

Code: Alles auswählen

#admin.py
class TopMenuArticleAdmin(admin.ModelAdmin):
    fieldsets = (
        ('Position', {
            'description': 'positionsUSED',
            'fields': ('TYPE', 'position')
        }),
        (None, {
            'fields': ('title', 'text', 'image', 'public')
        }),
    )
Ergebnis:
Bild

Gruß Tjuxx
Antworten