Queryset c'est quoi?
Lorsque vous avez crée un modèle, vous pouvez utiliser un manager de ce modèle avec la syntaxe suivante:
Product.objects
Ce manager génère des queryset qui sont des points d'entrée vers l'ORM de Django . C'est grâce à ce manager que vous allez pouvoir communiquer avec votre base de données. Un queryset est donc une liste d'objets d'un modèle donné.
Voic un exemple de queryset :
Product.objects.all()
Ce queryset vous retournera une liste avec toutes les entrées en base du modèle Product .
Il existe d'autres possibilités de recherche:
# Retourne tous les produits où la date est supérieure à 2010 Product.objects.filter(date__gt=2010) # Retourne les produits à 15 euros Product.objects.filter(price_ttc=15) # Retourner les produits qui ne sont pas à 15 euros Product.objects.exclude(price_ttc=15)
Il est d'ailleurs possible de chainer les filtres pour affiner sa recherche:
Product.objects.filter(date__lt=2010).exclude(price_ttc=15).order_by(name)
Les relations dans les queryset
Rapidement vous lierez les objets entre eux. Pour les retrouver vous pouvez partir de l'objet que vous voulez:
product_item = ProductItem.objects.filter(product__id=1)
Revient au meme que:
product_item = Product.objects.get(id=1).productitem_set.all()
Modifier des données
Exemple de modification:
p = Product.objects.get(pk=1) p.name = "ipod" p.save()
Ou cette syntaxe
Product.object.get(pk=1).update(name="ipod")
Supprimer des données
Pour supprimer des entrées dans votre base, vous pouvez utiliser la méthode delete :
Product.objects.find(id=1).delete()
Faire des modifications groupées
Si vous voulez faire une modification de données sur plusieurs items vous pouvez utiliser la méthode update :
Product.objects.filter(date__year=2019).update(name="ipad")
Les méthodes qui retournent un queryset
filter(**kwargs) | filtre |
exclude(**kwargs) | exclu |
annotate(*args, **kwargs) | permet d'associer des valeurs type moyenne, sum et count au queryset |
order_by(*fields) | trie par le colonne désignée |
reverse() | inverse l'ordre du queryset |
distinct([*fields]) | élimine les doublons |
values(*fields) | retourne un dictionnaire au lieu d'instances de modèles |
values_list(*fields) | retourne un tuple au lieu d'instance de modèles |
dates(field, kind, order='ASC') | transforme les données dans un format datetime.date |
datetimes(field, kind, order='ASC', tzinfo=None) | transforme les données dans un format datetime.datetime |
none() | crée un queryset qui ne retourne jamais d'objets |
all() | l'inverse de none, c'est à dire tout |
select_related(*fields) | retourne un queryset qui "suit" la clé étrangère indiqué |
prefetch_related(*lookups) | optimise les requêtes pour éviter un déluge de SELECT |
extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None) | hook requete SQL pour créer des nouveaux champs |
defer(*fields)¶ | ignore des colonnes dans la requete SQL |
only(*fields)¶ | sélectionne uniquement les champs indiqués pour la reqête SQL |
using(alias) | indique la base de données à exploiter |
select_for_update(nowait=False) | retourne un queryset qui bloquera les lignes jusqu'à la fin de la transaction, générant un SELECT ... FOR UPDATE SQL statement sur les bases de données qui le supporte. |
raw(raw_query, params=None, translations=None) | Execute une requete SQL et retourne un modèle |
Les méthodes qui ne retournent pas un queryset
get(**kwargs) | retourne un objet suivant les paramètres indiqués |
create(**kwargs) | créer un objet |
get_or_create(defaults=None, **kwargs) | récupère un objet ou le crée |
update_or_create(defaults=None, **kwargs) | modifie un objet ou le crée |
bulk_create(objs, batch_size=None) | insert en une seule fois une liste d'objets dans la base |
count() | compte le nombre d'occurences |
in_bulk(id_list) | prend une liste de clé primaire et retourne les objets associés |
iterator() | retourne un itérateur |
latest(field_name=None) | retourne le dernier objet dans la table |
earliest(field_name=None) | retourne l'objet dans la base le plus récent |
first() | retourne le premier objet du queryset |
last() | retourne le dernier objet du queryset |
aggregate(*args, **kwargs) | retourne un dictionnaire des valeurs regroupées telles que sum, count, average, etc. |
exists() | retourne True si le queryset contient un résultat |
update(**kwargs) | modifier la valeur d'un champ |
delete() | Execute une requete SQL delete sur toutes les lignes dans le queryset |
as_manager() | retourne le manager |
Les champs de recherche
exact | Exacte correspondance. Si un None est demandé, la recherche sera Null au niveau SQL |
iexact | insensible à la casse (qu'importe les majuscules ou les minuscules). ILIKE "DATA" est utilisé au niveau SQL |
contains | contient tel élément. LIKE '%DATA%' |
icontains | contient tel élément quelque soit la casse ILIKE '%DATA%' |
in | est dans la liste indiqué. exemple .filter(id__in=[1, 2, 3]) en SQL: WHERE id IN (1, 2, 3) |
gt | plus grand que exemple: filter(id__gt=4) en sql: WHERE id > 4 |
gte | plus grand ou égal |
lt | plus petit que |
lte | plus petit ou égal |
startswith | Commence par. en sql LIKE 'DATA%' |
istartswith | insensible à la casse. en slq ILIKE 'DATA%' |
endswith | se termine par. en SQL LIKE '%DATA' |
iendswith | insensible à la casse. en SQL: ILIKE '%DATA' |
range | intervalle de date. exemple: filter(date_creation=(start_date, end_date)) |
year | recherche par année. exemple: filter(date_creation__year=2019) |
month | recherche par mois. exemple: filter(date_creation__month=10) |
day | recherche par jour. exemple: filter(date_creation__day=10) |
week_day | recherche par jour dans la semaine |
hour | recherche par heure |
minute | recherche par minute |
second | recherche par seconde |
isnull | recherche par valeur Null. exemple: filter(date_creation__isnull=True) |
search | recheche fonctionnant que sur MySQL utilisant la recherche full-text: filter(name__search="+Tshirt -product Short") |
regex | recherche avec une expression régulière. exemple: Product.objects.get(name__regex=r'^(PR?|TR) +') |
iregex | idem avec insensibilité à la casse |
Les fonctions de regroupement / calcul
Avg → moyenne Count → nombre occurences Max → maximum Min → minimum StdDev → écart-type Sum → somme Variance → variance
Exemples d'utilisation
la méthode annotate
>>> from django.db.models import Count >>> p = Product.objects.annotate(nb_items=Count("product_item")).get(pk=1) >>> p.nb_items 2
les méthodes values et values_list
>>> Product.objects.filter(pk=1) [Product object] >>> Product.objects.filter(pk=1).values() [{'code': u'a0', 'name': u'Tshirt', 'price_ht': Decimal('25'), 'date_creation': datetime.datetime(2010, 9, 7, 12, 55, 55, 935974, tzinfo=), 'price_ttc': Decimal('30'), u'id': 1}] >>> Product.objects.filter(pk=1).values_list() [(1, u'Tshirt', u'a0', Decimal('25'), Decimal('30'), 0, datetime.datetime(2019, 9, 7, 12, 55, 55, 935974, tzinfo=))] >>> Product.objects.filter(pk=1).values("code") [{'code': u'a0'}] >>> Product.objects.filter(pk=1).values_list("code") [(u'a0',)]
La méthode extra
>>> p = Product.objects.extra(select={'items_count': 'SELECT COUNT(*) FROM backoffice_productitem WHERE backoffice_productitem.product_id = backoffice_product.id'})
>>> p[0].items_count
2
Voir la requete SQL
Vous pouvez voir quelle sera la requete SQL utilisé par le manager avec l'attribut query
Product.object.all().query
Retournera:
SELECT "backoffice_product"."id", "backoffice_product"."name", "backoffice_product"."code", "backoffice_product"."price_ht", "backoffice_product"."price_ttc" FROM "backoffice_product"
L'objet Q
Les requètes de base proposées par l'ORM Django reste simple et donc limité. Lorsque vous chainez les méthodes, l'opérateur "AND" sera utilisé, si vous voulez utiliser l'opérateur "OR", il vous faudra utiliser l'objet Q
Pour importer le module:
from django.db.model import Q
Exemple d'utilisation:
Product.objects.filter(Q(id=1))
Avec l'opérateur AND:
Product.objects.filter(Q(id=1) & Q(name="TEST"))
Et avec l'opérateur OR:
Product.objects.filter(Q(id=1) | Q(id=2))
Utiliser le notion de contraire:
Product.objects.filter(~Q(id=1))
Pensez à utiliser l'attribut query pour vérifier vos requètes SQL en cas de doute:
print Product.objects.filter(~Q(id=1)) # SELECT "backoffice_product"."id", "backoffice_product"."name", "backoffice_product"."code", "backoffice_product"."price_ht", "backoffice_product"."price_ttc" FROM "backoffice_product" WHERE NOT ("backoffice_product"."id" = 1 )
L'objet F
L'objet F vous permet d'incrémenter des valeurs d'une colonne:
Product.objects.filter(code="0001").update(stock=F("stock")+1)