[PYTHON] Neu in Django 1.8 Bedingte Ausdrücke #djangoja

Ich habe diesen Artikel geschrieben, als ich an [Tokyo Django Meetup # 3] teilgenommen habe (http://django.connpass.com/event/14219/).

Was kannst du tun?

Neue Funktion in Django 1.8 [Bedingte Ausdrücke] hinzugefügt (https://docs.djangoproject.com/de/1.8/ref/models/conditional-expressions/ ), Sie können jetzt bedingte Ausdrücke an die beim Betrieb des Modells verwendeten Methoden "Annotation", "Aggregation" und "Update" übergeben.

Beispielmodell

Die folgenden Modelle sind verfügbar. [^ 1]

models.py


# -*- coding: utf-8 -*-
from django.db import models


class Sponsor(models.Model):

    u"""
Sponsor der PyCon JP 2015
    """
    DIAMOND = 'D'
    PLATINUM = 'P'
    GOLD = 'G'
    SILVER = 'S'
    PLAN_CHOICES = (
        (DIAMOND, 'Diamond'),
        (PLATINUM, 'Platinum'),
        (GOLD, 'Gold'),
        (SILVER, 'Silver'),
    )
    name = models.CharField(max_length=50)
    registered_on = models.DateField()
    plan = models.CharField(
        max_length=1,
        choices=PLAN_CHOICES,
        default=SILVER,
    )

Die Testdaten sind wie folgt.

>>> from datetime import date, timedelta
>>> Sponsor.objects.create(
...     name='Crazy Inc.',
...     plan=Sponsor.DIAMOND,
...     registered_on=date.today() - timedelta(days=19))
<Sponsor: Sponsor object>
>>> Sponsor.objects.create(
...     name='Star Inc.',
...     plan=Sponsor.PLATINUM,
...     registered_on=date.today() - timedelta(days=36))
<Sponsor: Sponsor object>
>>> Sponsor.objects.create(
...     name='Experience Inc.',
...     plan=Sponsor.GOLD,
...     registered_on=date.today() - timedelta(days=11))
<Sponsor: Sponsor object>
>>> Sponsor.objects.create(
...     name='Giorno co., ltd.',
...     plan=Sponsor.GOLD,
...     registered_on=date.today() - timedelta(days=6))
<Sponsor: Sponsor object>
>>> Sponsor.objects.create(
...     name='Chariot Inc.',
...     plan=Sponsor.SILVER,
...     registered_on=date.today() - timedelta(days=1))
<Sponsor: Sponsor object>
>>> Sponsor.objects.create(
...     name='Polnareff co., ltd.',
...     plan=Sponsor.SILVER,
...     registered_on=date.today() - timedelta(days=2))
<Sponsor: Sponsor object>

Eigentlich verwenden

Bedingte Ausdrücke werden durch Kombinieren der folgenden zwei Klassen geschrieben.

Die Klasse "When" gibt zuerst die "Bedingung" und am Ende das "Ergebnis" an. Die Methode zum Angeben der "Bedingung" entspricht der Methode filter.

>>> from django.db.models import When, F, Q
>>> #Beziehen Sie sich auf das Namensfeld, wenn der Plan Gold ist
>>> When(plan=Sponsor.GOLD, then='name')
>>> When(plan=Sponsor.GOLD, then=F('name'))
>>> from datetime import date
>>> # registered_am ist 2015/2/1 bis 2015/9/Beziehen Sie sich auf das Planfeld, wenn es zwischen 1 liegt
>>> When(registered_on__gt=date(2015, 2, 1),
...      registered_on__lt=date(2015, 9, 1),
...      then='plan')
>>> #Sie können im Q-Objekt auch ODER-Bedingungen angeben
>>> When(Q(name__startswith="Crazy") | Q(name__startswith="Giorno"),
...      then='name')

Kombinieren Sie die oben genannte "Wann" -Klasse mit der "Fall" -Klasse und fordern Sie die Sponsorengebühr für jeden Sponsor an.

>>> from django.db.models import Case, When, Value, CharField
>>> Sponsor.objects.annotate(
...     fee=Case(
...         When(plan=Sponsor.DIAMOND, then=Value(u'1,000,000 Yen(Steuer nicht inbegriffen)')),
...         When(plan=Sponsor.PLATINUM, then=Value(u'500,000 Yen(Steuer nicht inbegriffen)')),
...         When(plan=Sponsor.GOLD, then=Value(u'300,000 Yen(Steuer nicht inbegriffen)')),
...         When(plan=Sponsor.SILVER, then=Value(u'100,000 Yen(Steuer nicht inbegriffen)')),
...         output_field=CharField(),
...     ),
... ).values_list('name', 'fee')
[(u'Crazy Inc.', u'1,000,000\u5186 (\u7a0e\u629c\u304d)'), (u'Star Inc.', u'500,000\u5186 (\u7a0e\u629c\u304d)'), (u'Experience Inc.', u'300,000\u5186 (\u7a0e\u629c\u304d)'), (u'Giorno co., ltd.', u'300,000\u5186 (\u7a0e\u629c\u304d)'), (u'Chariot Inc.', u'100,000\u5186 (\u7a0e\u629c\u304d)'), (u'Polnareff co., ltd.', u'100,000\u5186 (\u7a0e\u629c\u304d)')]

Lassen Sie uns plan entsprechend dem Wert von register_on aktualisieren.

>>> from django.db.models import Case, When, Value
>>> from datetime import date,timedelta
>>> a_week_ago = date.today() - timedelta(weeks=1)
>>> a_month_ago = date.today() - timedelta(days=30)
>>> Sponsor.objects.update(
...     plan=Case(
...         When(registered_on__lte=a_week_ago ,
...              then=Value(Sponsor.PLATINUM)),
...         When(registered_on__lte=a_month_ago,
...              then=Value(Sponsor.GOLD)),
...         default=Value(Sponsor.SILVER)
...     ),
... )
>>> Sponsor.objects.values_list('name', 'plan')
[(u'Crazy Inc.', u'P'), (u'Star Inc.', u'P'), (u'Experience Inc.', u'P'), (u'Giorno co., ltd.', u'S'), (u'Chariot Inc.', u'S'), (u'Polnareff co., ltd.', u'S')]

Finden Sie heraus, wie viele Unternehmen sich für jeden "Plan" beworben haben.

>>> from django.db.models import Case, When, Value, IntegerField, Sum
>>> Sponsor.objects.aggregate(
...     silver=Sum(
...         Case(When(plan=Sponsor.SILVER, then=1),
...              output_field=IntegerField())
...     ),
...     gold=Sum(
...         Case(When(plan=Sponsor.GOLD, then=1),
...              output_field=IntegerField())
...     ),
...     platinum=Sum(
...         Case(When(plan=Sponsor.PLATINUM, then=1),
...              output_field=IntegerField())
...     )
... )
{'platinum': 3, 'silver': 3, 'gold': None}

Welche Art von SQL wird erstellt?

Werfen wir einen Blick auf das tatsächliche SQL, das mit dem Befehl debugsqlshell in djnago-debug-toolbar erstellt wurde. [^ 2]

>>> Sponsor.objects.annotate(
...     fee=Case(
...         When(plan=Sponsor.DIAMOND, then=Value(u'1,000,000 Yen(Steuer nicht inbegriffen)')),
...         When(plan=Sponsor.PLATINUM, then=Value(u'500,000 Yen(Steuer nicht inbegriffen)')),
...         When(plan=Sponsor.GOLD, then=Value(u'300,000 Yen(Steuer nicht inbegriffen)')),
...         When(plan=Sponsor.SILVER, then=Value(u'100,000 Yen(Steuer nicht inbegriffen)')),
...         output_field=CharField(),
...     ),
... ).values_list('name', 'fee')
SELECT `sponsors_sponsor`.`name`,
       CASE
           WHEN `sponsors_sponsor`.`plan` = 'D' THEN '1,000,000 Yen(Steuer nicht inbegriffen)'
           WHEN `sponsors_sponsor`.`plan` = 'P' THEN '500,000 Yen(Steuer nicht inbegriffen)'
           WHEN `sponsors_sponsor`.`plan` = 'G' THEN '300,000 Yen(Steuer nicht inbegriffen)'
           WHEN `sponsors_sponsor`.`plan` = 'S' THEN '100,000 Yen(Steuer nicht inbegriffen)'
           ELSE NULL
       END AS `fee`
FROM `sponsors_sponsor` LIMIT 21 [0.23ms]

>>> Sponsor.objects.update(
...     plan=Case(
...         When(registered_on__lte=a_week_ago ,
...              then=Value(Sponsor.PLATINUM)),
...         When(registered_on__lte=a_month_ago,
...              then=Value(Sponsor.GOLD)),
...         default=Value(Sponsor.SILVER)
...     ),
... )
UPDATE `sponsors_sponsor`
SET `plan` = CASE
                 WHEN `sponsors_sponsor`.`registered_on` <= '2015-04-22' THEN 'P'
                 WHEN `sponsors_sponsor`.`registered_on` <= '2015-03-30' THEN 'G'
                 ELSE 'S'
             END [0.62ms]

>>> Sponsor.objects.aggregate(
...     silver=Sum(
...         Case(When(plan=Sponsor.SILVER, then=1),
...              output_field=IntegerField())
...     ),
...     gold=Sum(
...         Case(When(plan=Sponsor.GOLD, then=1),
...              output_field=IntegerField())
...     ),
...     platinum=Sum(
...         Case(When(plan=Sponsor.PLATINUM, then=1),
...              output_field=IntegerField())
...     )
... )
SELECT SUM(CASE WHEN `sponsors_sponsor`.`plan` = 'P' THEN 1 ELSE NULL END) AS `platinum`,
       SUM(CASE WHEN `sponsors_sponsor`.`plan` = 'S' THEN 1 ELSE NULL END) AS `silver`,
       SUM(CASE WHEN `sponsors_sponsor`.`plan` = 'G' THEN 1 ELSE NULL END) AS `gold`
FROM `sponsors_sponsor` [0.32ms]

[^ 1]: Beispielcode des Originaldokuments [PyCon JP 2015 Sponsorship Information](https :: Geändert mit Bezug auf (/ pycon.jp/2015/sponsors/prospectus.html). [^ 2]: Die Datenbank verwendet MySQL 5.5.43.

Recommended Posts

Neu in Django 1.8 Bedingte Ausdrücke #djangoja
Was ist neu in Python 3.5?
Was ist neu in Python 3.6?
Was ist neu in Python 3.10 (Zusammenfassung)
Neu in Python 3.4.0 (2) --enum
Was ist neu in Python 3.9 (Zusammenfassung)
Neu in Python3.9 Wörterbücher zusammenführen
Modell in Django
Bis Sie eine neue App in Django erstellen
Form in Django
Modelländerungen in Django
Neu in Python 3.4.0 (1) --pathlib
[Django] Ich möchte mich nach einer neuen Registrierung automatisch anmelden