0
votes

Comment ajouter un modèle supplémentaire à la liste et filtrer sur une condition personnalisée

J'ai 4 modèles de 4 tableaux différents:

total_growth=list(map(lambda i,w: (i/w) if w else 0, total[0],total[1]))

J'utilise ces modèles pour filtrer en fonction de certaines conditions. La clé étrangère ne fonctionne pas pour moi (j'ai essayé de ne pas faire ce qui ne va pas).

total_growth=total2019/total2018

Ce code renvoie la liste des joueurs et leur nom de famille qui répondre aux critères.

Cependant, je ne peux pas intégrer la classe de poids dans la liste et le filtre basé sur

weight_list=[Weight.year19,Weight.year18]

, puis le filtrer if score_weight> 30

J'ai essayé d'intégrer

 score_weight=first_score/Weight.year19

Comment puis-je utiliser weight_list avec Mes résultats pour calculer score_weight=first_score/Weight.year19

Comment faire?

Est-ce possible du tout faire ça?


Supplémentaire :

Quand je vous ai posé cette question, j'ai minimisé la formule, je mets un filtre donc après avoir compris le code, j'ai répondu et je peux résoudre indépendamment. Ce que j'ai fait la majorité, mais je me perds car je ne l'ai jamais fait auparavant mais je veux apprendre.

Cependant, il y a 2 formules que je ne peux pas insérer dans le code et le faire fonctionner. Je continue d’apprendre et certains sont déroutants.

Questions:

  1. Le code a donc répondu à la question dans l'annotation:

    total = F ('second_score') + F ('premier_score')

Ceci provient du code.

La formule que je veux intégrer et filtrer est:

ABC = []
for MyResults in [Results_2019, Results_2018 ]:

     results_list = MyResults.objects.annotate(increase=F('second_score') / 
     F('first_score'),total=F('second_score') + 
     F('first_score',).filter(increase__gt=0.2,total__gt=average_score,)
     ABC.extend(results_list.values_list('player_name', flat=True))
DoubleSNames = list(set([x for x in ABC if ABC.count(x) == 2]))

finallist=list(Profile.objects.filter(player_name__in=DoubleSNames).
values_list('player_name', 'player_surname'))

  

Donc le total de 2019 divisé par total de 2018). En Python il y a la liste que j'ai essayé d'appliquer comme:

class Profile(models.Model):
    player_name = models.CharField(max_length=150)
    player_surname=models.CharField(max_length=200)
    sport_type=models.CharField(max_length=200)
  
class Results_2019(models.Model):
    player_name = models.CharField(max_length=150) 
    first_score=models.DecimalField(decimal_places=2)
    second_score=models.DecimalField(decimal_places=2)
    average_score=models.DecimalField(decimal_places=2)
       
class Results_2018(models.Model):
    player_name = models.CharField(max_length=150)         
    first_score=models.DecimalField(decimal_places=2)
    second_score=models.DecimalField(decimal_places=2)
    average_score=models.DecimalField(decimal_places=2)

class Weight(models.Model):
     player_name = models.CharField(max_length=150)         
     year2019=models.DecimalField(decimal_places=2)
     year2018=models.DecimalField(decimal_places=2)

Et vérifier à condition si total_growth> 0.05

Cependant ça ne marche pas et je ne sais pas exactement où le mettre dans le code pour le faire fonctionner?

  1. Comment filtrer par sport_type (profil de classe) pour que sport_type ne soit pas dans le football.

J'apprécierais de l'aide pour mes requêtes supplémentaires pour clore enfin mon inquiétude concernant cette question.


13 commentaires

1000 chiffres? Soyez réel.


Ces données iront-elles dans une base de données? Ou faut-il supprimer [MySQL] des balises?


Ce sont des données statiques de la base de données, donc les noms des modèles sont des noms de table réels


Pour déboguer cela, pouvez-vous enregistrer le score_weight calculé, ou l'inclure dans la sortie au lieu de l'utiliser dans l'instruction if , ou le calculer manuellement pour certains des joueurs pour qui, selon vous, devrait être supérieur à 30?


En remarque, quelques points qui pourraient être de grandes accélérations: (a) faire le filtrage côté base de données, avec des clauses .filter () plus complexes et objets F , plutôt que dans un < instruction code> if ; et (b) utilisez Profile.objects.filter (player_name__in = DoubleSNames) plutôt que d'appeler Profile.objects.filter (player_name = name) [0] dans une boucle. Leur valeur dépend de la quantité de données dont vous disposez et si les performances actuelles sont satisfaisantes ...


pourrait s'il vous plaît partager votre réponse et votre code dans une réponse - c'est une question de prime


le code que vous avez partagé ne fonctionne pas non plus. Ma question concerne mon souci d'intégrer un filtre complexe avec des valeurs de liste. Si vous savez comment partager le code. J'ai essayé plusieurs fois, j'obtiens une erreur indiquant que le profil ne contient que des colonnes: player_name, player_surname, sport_type.


Le correctif de @sabik est correct et très utile. Votre problème était que la ligne suivante devait également être modifiée ou que les cinq lignes pouvaient être combinées en une seule commande. (Je le partage dans ma réponse car c'est long)


Question: Le player_name est-il unique dans chaque table de sorte qu'aucune ligne avec le même player_name ne puisse exister dans la même table pour aucun joueur? Si je comprends bien, vos tableaux Result_ * et Weight ne sont pas des données en direct qui sont ajoutées en continu, mais un récapitulatif pour l'année ou un récapitulatif de poids pour le joueur.


Oui, vous avez raison :Name est unique dans chaque table. Oui, vous avez des résultats corrects * et le poids sont des données statiques et représentent un résumé des résultats pour l'année pour chaque joueur.


@ Günel - Ma réponse était principalement de consigner ou de sortir ou d'obtenir autrement le score_weight calculé, pour m'assurer qu'il est effectivement supérieur à 30 pour les enregistrements pertinents. Cela exclura la possibilité que le code fonctionne comme écrit, mais les données ne contiennent en fait aucun enregistrement avec score_weight> 30 - que ce soit parce qu'il n'y en a pas, ou en raison d'une discordance entre les les données et le calcul (par exemple, il devrait peut-être être de 0,30 au lieu de 30).


@sabik en fait cela dépend des scores et des poids, si le score maximum est de 100 et le poids autour de 80, alors il sera au maximum égal à 1,25, mais si les scores sont> 1000 ....


@Houda - Oui, c'est pourquoi ma suggestion est de les imprimer et de voir quels sont les chiffres réels.


3 Réponses :


0
votes

A) Bogues possibles:

Peut-être avez-vous oublié d'initialiser certaines variables dans la boucle pour Weight. (votre intention n'était pas claire pour moi)

Un autre problème possible pourrait être la combinaison des tabulations et des espaces. Le code n'est pas correctement mis en retrait une fois que vous l'avez collé dans Stackoverflow. Peut-être que votre éditeur a une taille d'onglet différente, peut-être que Python2 l'a interprété comme valide, mais pas comme vous le voyez dans l'éditeur. Essayez d'exécuter python avec l'option -t , pour voir les avertissements si la logique interprétée dépend de la taille de l'onglet. Le style de code recommandé pour Python est de ne pas utiliser de tabulations et de fixer tous les retraits à des multiples de 4 espaces. Le meilleur réglage de l'éditeur pour Python est d'étendre automatiquement tous les onglets en espaces.


B) optimisations:

très important

finallist simplifié de nombreuses requêtes de base de données à une seule requête:

from collections import Counter

profile_map = {x.player_name: x for x in Player.objects.all()}
weight_map = {x.player_name: x for x in Weight.objects.all()}
totals_map = {}  # like rows: player, columns: year
ABC = []
for MyResults in [[Results_2019, Results_2018 ]:
    results_list = (
        MyResults.objects
        .annotate(
            increase=F('second_score') / F('first_score'),
            total=F('second_score') + F('first_score')
        )
       .filter(
            increase__gt=0.2,
            total__gt=average_score,
            # ... possible more filters
        )
    )
    year_str = MyResults._meta.model_name[-4:]
    for result in results_list:
        player_name = result.player_name
        player = profile_map[player_name]
        weight = weight_map[player_name]
        weight_year = vars(weight)['year' + year_str[-2:]]
        score_weight = result.first_score / weight_year
        totals_map.setdefault(player_name, {})[year_str] = result.total
        if score_weight > 30 and player.sport_type not in ['football']:
            ABC.append(player_name)
counter = Counter(ABC)
DoubleSNames = {name for name, count in counter.items() if count == 2}

finallist = []
for player_name in DoubleSNames:
    totals = totals_map['player_name']
    total2018 = totals.get('2018', 0)
    total2019 = totals.get('2019', 0)
    if totals2018 > 0 and total2019 / total2018 > 0.05:
        player = player_map[player_name]
        finallist.append([player.player_name, player.player_surname])

optimisation moins importante

simplifier MyResults.objects.all () code> à une requête avec moins de lignes de données

results_list = MyResults.objects.filter(
    averrage__gt=50,
    second_score__gt=70 - F(first_score),
    average__lt=F(first_score) + F(second_score),
    first_score__gt=0,
    second_score__gt=0.2 * F(first_score),
)
ABC.extend(results_list.values_list('player_name', flat=True))

Cela ne devrait pas être fait avant que la vue ne soit lente, car la lisibilité compte et peut-être que ce ne sera pas le goulot de la bouteille.
Inconvénients:
L'expression pour les fonctions augmenter avec Case () When () serait mal lisible. Tout est reformulé, mais il est encore moins lisible qu'un filtre sur une liste Python simple.


MODIFIER :
J'accepte que vous ayez oublié de définir la clé primaire et les clés étrangères suggérant @Houda, comment est normal dans Django et qu'il peut être trop tard pour permettre à Django d'ajouter des index à ces tables.

Si toutes les données à partir de Profile et Weight peuvent tenir dans la mémoire, alors vous pouvez facilement le mapper par un dictionnaire, sinon vous pouvez le filtrer par noms individuels comme vous l'avez fait à l'origine ou pour les charger la mémoire par un sous-ensemble de joueurs.

finallist = list(
    Profile.objects.filter(player_name__in=DoubleSNames)
    .values_list('player_name', 'player_surname')
)

(Ce n'est pas une question avancée sur django-queryset maintenant, mais comment simuler une relation de base de données par Python.) p >


4 commentaires

Merci beaucoup pour votre réponse. Vos conseils d'optimisation imcode sont très utiles. Cependant, ma question est de savoir comment utiliser les valeurs de la classe Weight dans les calculs avec d'autres valeurs d'autres modèles. Le poids de la table est une table séparée dans la base de données et contient les valeurs exactes que j'ai répertoriées dans ce modèle. J'ai mis à jour ma question où j'ai suivi vos conseils, mais toujours dans ce code, je ne sais pas comment incorporer les valeurs de classe de poids calculer avec d'autres valeurs et filtrer si les valeurs sont supérieures à 30. Nous apprécierions si vous pouviez aider à comprendre comment faire et dans l'ensemble, est-il possible de le faire?


La question est en réalité mélange de modèles-quaryset et de la relation de table, car mes modèles n'acceptent pas la clé étrangère, je ne sais pas ici, je me suis trompé alors j'ai décidé d'utiliser le code Python pour obtenir le résultat souhaité. J'ai accompté votre réponse car il a répondu à la plupart de mes questions qui n'ont même pas demandé de conseils d'optimisation. Bien que j'ai 2 problèmes laissés dans mon esprit que je suis conccéré et j'apprécierais si vous pouviez aider à comprendre. Si cela ne vous dérange pas d'aider pourriez-vous s'il vous plaît voir ma question mise à jour dans la section supplémentaire que j'ai énumérée 2 questions pour cette question qui se posaient.


J'ai accepté ces deux dernières questions et je n'ai édité que le code sans aucun commentaire. Vous allez faire face à un problème si un joueur est en compétition dans deux sports :-) mais ce serait un problème de données, pas un problème de code


L'exemple n'élimine que le champ exact "football". Le code est correct. Vous pouvez déboguer le problème en filtrant temporairement un seul nom de personne problématique et en imprimant certaines variables internes. Peut-être qu'il y a un espace blanc à la fin du nom du sport. Il peut être intéressant de savoir quel était le problème, mais je ne répondrai pas davantage.



1
votes

J'ai écrit mon propre code, tu as raison le résultat est toujours vide à cause de ces conditions:

def myPageView():
    ABC = {}
    players = Profile.objects.all().values()

    for result in players:
        for data in [[Results2019, 'year19'], [Results2018, 'year18']]:
            Results = data[0].objects.get(player_name__exact=result['player_name'])
            if Results:
                wgt = Weight.objects.filter(player_name__exact=result['player_name']).values(data[1]).last()
                if wgt:
                    if float(Results.first_score) > 0.0:
                        increase19 = float(Results.second_score) / float(Results.first_score)
                    else:
                        increase19 = 0
                    total = float(Results.second_score) + float(Results.first_score)
                    score_weight = total / float(wgt[data[1]])
                    if (increase19 > 0.2) and (total > float(Results.average_score)) and \
                            (float(Results.average_score) > 50) and (total > 70) and (score_weight > 1):
                        ABC[result['player_name']] = result['player_surname']
                    else:
                        pass
                else:
                    pass
            else:
                pass
    print('*************ABC***************', ABC)
    finallist = []
    for name in ABC.keys():
        finallist.append([name, ABC[name]])
    print('*************finallist***************', finallist)

score_weight ne sera jamais> 30

vous pouvez trouver ci-dessous mon code, quand je mets score_weight> 1, je peux obtenir des résultats:

model.py:

class Profile(models.Model):
     player_name = models.CharField(max_length=150)
     player_surname = models.CharField(max_length=200)
     sport_type = models.CharField(max_length=200)


class Results2019(models.Model):
    player_name = models.CharField(max_length=150)
    first_score = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)
    second_score = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)
    average_score = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)


class Results2018(models.Model):
    player_name = models.CharField(max_length=150)
    first_score = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)
    second_score = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)
    average_score = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)


class Weight(models.Model):
    player_name = models.CharField(max_length=150)
    year19 = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)
    year18 = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)

views.py

total=second+first
score_weight=total/weight19
if increase > 0.2 and  total > average and average > 50 and total > 70 and 
score_weight > 30 : ABC.append(result.player_name)


4 commentaires

merci pour votre réponse, mais la clé étrangère ne fonctionne pas dans mon cas, c'est une manière de valider la manière de la liste pour pouvoir filtrer les différentes tables.


le pb n'est pas dans ton code par dans les conditions que tu as faites: score_weight> 30 n'est pas possible je pense,


vous n'avez pas besoin d'utiliser de clé étrangère. c'est facultatif


Pourriez-vous s'il vous plaît voir ma question mise à jour, j'ai changé le code et je l'ai amélioré pour qu'il soit plus efficace. Veuillez voir si vous pouvez intégrer des colonnes de classe de poids dans le code afin que je puisse calculer et filtrer en fonction de 3 modèles



0
votes

model.py

ABC = {}
weight_dict = defaultdict(dict)
player_dict = {}

for player in Profile.objects.values('player_name', 'player_surname'):
    player_dict[player['player_name']] = player['player_surname']

for wt in Weight.objects.values():
    weight_dict[wt['player_name']] = {'year19': wt['year19'], 'year18': wt['year18']}

for MyResults in [[Results2019, 'year19'], [Results2018, 'year18']]:
    results_list = MyResults[0].objects.\
        filter(increase__exact=True, total__exact=True).values('player_name', 'first_score')

    for t in results_list:
        if t['player_name'] in ABC.keys():
            pass
        elif float(t['first_score']) / float(weight_dict[t['player_name']][MyResults[1]]) > 30:
            ABC[t['player_name']] = player_dict[t['player_name']]

finallist = ABC.items()

views.py

from django.db import models


class Profile(models.Model):
    player_name = models.CharField(max_length=150)
    player_surname = models.CharField(max_length=200)
    sport_type = models.CharField(max_length=200)


class Results2019(models.Model):
    player_name = models.CharField(max_length=150)
    first_score = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)
    second_score = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)
    average_score = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)
    increase = models.BooleanField(null=False, blank=False, default=False, editable=False)
    total = models.BooleanField(null=False, blank=False, default=False, editable=False)

    def save(self, *args, **kwargs):
        if self.second_score / self.first_score > 0.2:
            self.increase = 1
        else:
            self.increase = 0
        if self.second_score + self.first_score > self.average_score:
            self.total = 1
        else:
            self.total = 0
        super().save(*args, **kwargs)


class Results2018(models.Model):
    player_name = models.CharField(max_length=150)
    first_score = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)
    second_score = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)
    average_score = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)
    increase = models.BooleanField(null=False, blank=False, default=False, editable=False)
    total = models.BooleanField(null=False, blank=False, default=False, editable=False)

    def save(self, *args, **kwargs):
        if self.second_score / self.first_score > 0.2:
            self.increase = 1
        else:
            self.increase = 0
        if self.second_score + self.first_score > self.average_score:
            self.total = 1
        else:
            self.total = 0
        super().save(*args, **kwargs)


class Weight(models.Model):
    player_name = models.CharField(max_length=150)
    year19 = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)
    year18 = models.DecimalField(decimal_places=2, max_digits=5, null=True, blank=True,)


0 commentaires