9
votes

Comment puis-je obtenir des éléments calculés d'une table dans un requérant Django?

J'essaie d'utiliser l'API de QuerySet de Django pour imiter la requête suivante:

if(use_date_due):
    sum_qs = sum_qs.extra(select={'chosen_date': 'CASE WHEN date_due IS NULL THEN date ELSE date_due END'})
else: 
    sum_qs = sum_qs.extra(select={'chosen_date':'date'})
sum_qs = sum_qs.extra(select={'year': 'EXTRACT(year FROM chosen_date)',
                              'month': 'EXTRACT(month FROM chosen_date)',
                              'is_paid':'date_paid IS NOT NULL'})


1 commentaires

Je garderais cela simple et utiliser une requête crue. C'est ce qu'ils sont là pour.


5 Réponses :


3
votes

Bien voici quelques soluarrages

1. Dans votre cas particulier, vous pouvez le faire avec un extra: xxx

2. Il est également possible d'utiliser un python ordinaire pour obtenir des données dont vous avez besoin: xxx

ou xxx p > 3. dans le monde SQL Ce type de calcul de nouveaux champs est généralement effectué par la sous-requête Uing ou Expression de table commune . J'aime CTE plus à cause de sa lisibilité. Il pourrait être comme: xxx

Vous pouvez également chaîner autant de CTE que vous le souhaitez: xxx

donc dans django vous peut utiliser Query brut comme: xxx

et vous aurez des objets de facturation avec quelques propriétés supplémentaires.

4. ou vous pouvez simplement substituer des champs dans votre Requête avec python ordinaire xxx


0 commentaires

1
votes

Est-ce que cela fonctionnerait?:

from django.db import connection, transaction
cursor = connection.cursor()

sql = """
    SELECT 
        %s AS year, 
        %s AS month,
        date_paid IS NOT NULL as is_paid
    FROM (
        SELECT
            (CASE WHEN date_due IS NULL THEN date_due ELSE date END) AS chosen_date, *
        FROM
            invoice_invoice
    ) as t1;
    """ % (connection.ops.date_extract_sql('year', 'chosen_date'),
           connection.ops.date_extract_sql('month', 'chosen_date'))

# Data retrieval operation - no commit required
cursor.execute(sql)
rows = cursor.fetchall()


0 commentaires

1
votes

Vous pouvez ajouter une propriété à votre définition de modèle, puis faire:

model_instance.chosen_date.year


2 commentaires

En fait, la raison pour laquelle je le fais est parce que, plus tard, je fais une somme d'agrégation basée sur l'année et le mois. Afin de faire cela, je dois appeler valeurs avec les valeurs que je veux grouper par ... et je ne peux pas utiliser les recherches sur le terrain comme __ année dans Valeurs .


Une autre chose est que ce que j'utilise pour chrosen_date dépend du contexte: parfois j'utilise le dus_date avec la date Date Fallback, parfois juste Date .



1
votes

Utilisez simplement le SQL brut. La méthode RAW () Manager peut être utilisée pour effectuer des requêtes SQL brutes qui renvoient des instances de modèle.

https: //docs.djangoproject .COM / EN / 1.5 / TOWS / DB / SQL / # Effectuer-RAW-SQL-QUERIES


0 commentaires

7
votes

Réponse courte: Si vous créez une colonne aliasée (ou calculée) à l'aide de extra (SELECT = ...) Ensuite, vous ne pouvez pas utiliser la colonne aliasée dans un appel ultérieur à filtre () . De plus, comme vous l'avez découvert, vous ne pouvez pas utiliser la colonne aliasée dans les appels ultérieurs vers extra (SELECT = ...) ou extra (where = ...) .

une tentative d'expliquer pourquoi:

Par exemple: xxx

filtrer_qs va essayer de produire une requête comme: xxx

et extra_qs essaie quelque chose comme: xxx

aucun de ceux-ci n'est valide SQL. En général, si vous souhaitez utiliser un alias de colonne calculé plusieurs fois dans la sélection ou les clauses de la requête, vous devez réellement le calculer à chaque fois. C'est pourquoi la réponse de Roman Pekar résout votre problème spécifique - au lieu d'essayer de calculer chrosen_date une fois, puis utilisez-le plus tard, il l'a calcule à chaque fois qu'il est nécessaire. <

vous mentionne l'annotation / agrégation dans votre question. Vous pouvez utiliser filtre () sur les alias créés par annotate () (Donc, je voudrais voir les erreurs similaires dont vous parlez, il a été assez robuste dans mon expérience). C'est parce que lorsque vous essayez de filtrer sur un alias créé par Annotate, l'ORM reconnaît ce que vous faites et remplace l'alias avec le calcul qui l'a créée.

de sorte qu'un exemple: xxx

produit quelque chose comme: xxx

utilisant "ayant max alias_col> 0 "ne fonctionnerait pas.


J'espère que c'est utile. S'il y a quelque chose que j'ai expliqué mal laissé-moi savoir et je verrai si je peux l'améliorer.


0 commentaires