J'ai écrit cet article en participant au Tokyo Django Meetup # 3.
Nouvelle fonctionnalité ajoutée dans Django 1.8 Expressions conditionnelles, Vous pouvez maintenant passer des expressions conditionnelles aux méthodes ʻannotation, ʻaggregation
et ʻupdate` utilisées lors de la manipulation de modèles.
Les modèles suivants sont disponibles. [^ 1]
models.py
# -*- coding: utf-8 -*-
from django.db import models
class Sponsor(models.Model):
u"""
Sponsor de 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,
)
Les données de test sont les suivantes.
>>> 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>
Les expressions conditionnelles sont écrites en combinant les deux classes suivantes.
La classe When
spécifie la" condition "en premier et le" résultat "en dernier.
La méthode de spécification de la "condition" est la même que la méthode filter.
>>> from django.db.models import When, F, Q
>>> #Reportez-vous au champ de nom lorsque le plan est Gold
>>> When(plan=Sponsor.GOLD, then='name')
>>> When(plan=Sponsor.GOLD, then=F('name'))
>>> from datetime import date
>>> # registered_le est 2015/2/1 à 2015/9/Reportez-vous au champ du plan s'il est compris entre 1
>>> When(registered_on__gt=date(2015, 2, 1),
... registered_on__lt=date(2015, 9, 1),
... then='plan')
>>> #Vous pouvez également spécifier des conditions OR dans l'objet Q
>>> When(Q(name__startswith="Crazy") | Q(name__startswith="Giorno"),
... then='name')
Combinons la classe When
ci-dessus avec la classe Case
et demandons les frais de parrainage de chaque sponsor.
>>> from django.db.models import Case, When, Value, CharField
>>> Sponsor.objects.annotate(
... fee=Case(
... When(plan=Sponsor.DIAMOND, then=Value(u'1,000,000 yens(Hors tax)')),
... When(plan=Sponsor.PLATINUM, then=Value(u'500,000 yens(Hors tax)')),
... When(plan=Sponsor.GOLD, then=Value(u'300,000 yens(Hors tax)')),
... When(plan=Sponsor.SILVER, then=Value(u'100,000 yens(Hors tax)')),
... 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)')]
Mettons à jour plan
en fonction de la valeur de registered_on
.
>>> 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')]
Découvrez combien d'entreprises ont postulé pour chaque «plan».
>>> 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}
Jetons un œil au SQL réel créé en utilisant la commande debugsqlshell
dans djnago-debug-toolbar. [^ 2]
>>> Sponsor.objects.annotate(
... fee=Case(
... When(plan=Sponsor.DIAMOND, then=Value(u'1,000,000 yens(Hors tax)')),
... When(plan=Sponsor.PLATINUM, then=Value(u'500,000 yens(Hors tax)')),
... When(plan=Sponsor.GOLD, then=Value(u'300,000 yens(Hors tax)')),
... When(plan=Sponsor.SILVER, then=Value(u'100,000 yens(Hors tax)')),
... output_field=CharField(),
... ),
... ).values_list('name', 'fee')
SELECT `sponsors_sponsor`.`name`,
CASE
WHEN `sponsors_sponsor`.`plan` = 'D' THEN '1,000,000 yens(Hors tax)'
WHEN `sponsors_sponsor`.`plan` = 'P' THEN '500,000 yens(Hors tax)'
WHEN `sponsors_sponsor`.`plan` = 'G' THEN '300,000 yens(Hors tax)'
WHEN `sponsors_sponsor`.`plan` = 'S' THEN '100,000 yens(Hors tax)'
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]: Exemple de code du document original [PyCon JP 2015 Sponsorship Information](https :: Modifié en référence à (/ pycon.jp/2015/sponsors/prospectus.html). [^ 2]: La base de données utilise MySQL 5.5.43.
Recommended Posts