簡體   English   中英

如何添加額外的 model 以在自定義條件下列出和過濾

[英]How to add additional model to list and filter on custom condition

我有來自4 個不同表4 個模型

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)

我使用這些模型根據滿足特定條件進行過濾。 外鍵對我不起作用(我試過我沒有什么問題)。

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'))

  

代碼返回符合條件的玩家列表及其姓氏。

但是我不能在列表中嵌入Weight class並根據

 score_weight=first_score/Weight.year19

然后過濾score_weight > 30

我試圖嵌入

weight_list=[Weight.year19,Weight.year18]

我如何使用weight_listMyResults來計算score_weight=first_score/Weight.year19

怎么做?

有可能做到這一點嗎?


附加

當我問你這個問題時,我最小化了我放入過濾器的公式,所以在我理解代碼回答后,我學習並且我可以獨立解決。 我做了大多數,但是我迷路了,因為我以前沒有做過,但想學習。

但是有 2 個公式我無法在代碼中插入並使其工作。 我一直在學習,有些令人困惑。

問題:

  1. 所以代碼在注釋中回答了這個問題:

    總計=F('second_score') + F('first_score')

這是來自代碼。

我要嵌入和過濾的公式是:

total_growth=total2019/total2018

所以 2019 年的總數除以 2018 年的總數)。 在 Python 中有我嘗試應用的列表,例如:

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

並檢查條件是否total_growth > 0.05

但是它不起作用,我不確切地將它放在代碼中以使其工作?

  1. 如何按sport_type (class Profile)過濾,以便sport_type不在足球中。

希望對我的其他查詢有所幫助,以最終結束我對這個問題的關注。

我寫了自己的代碼,你是對的,因為這種情況,結果總是空的:

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)

score_weight 永遠不會 > 30

你可以在我的代碼下面找到,當我把 score_weight > 1 我可以得到結果:

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,)

視圖.py

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)

A)可能的錯誤:

也許你忘了在權重的循環中初始化一些變量。 (我不清楚你的意圖)

其他可能的問題可能是制表符和空格的組合。 將代碼粘貼到 Stackoverflow 后,代碼縮進不正確。 也許您的編輯器有不同的選項卡大小,也許 Python2 將其解釋為有效,但不是您在編輯器中看到它的方式。 嘗試使用-t選項運行 python 以查看解釋邏輯是否取決於選項卡大小的警告。 Python 的推薦代碼樣式是不使用制表符並將所有縮進固定為 4 個空格的倍數。 Python 的最佳編輯器設置是自動將所有制表符展開為空格。


B)優化:

很重要

finallist從許多數據庫請求簡化為一個請求:

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

不太重要的優化

MyResults.objects.all()簡化為具有較少數據行的請求

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))

在視圖變慢之前不應該這樣做,因為可讀性很重要,也許這不是瓶頸。
缺點:
使用Case() When()函數increase表達式的可讀性不好。 一切都重新制定,但它仍然不如普通 Python 列表上的過濾器可讀。


編輯
我接受您忘記設置建議@Houda 的主鍵和外鍵,Django 中的正常情況如何,並且允許 Django 向這些表添加索引可能為時已晚。

如果ProfileWeight中的所有數據都可以放入 memory 中,那么您可以通過字典輕松地 map

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])

(現在不是django-queryset的高級問題,而是Python如何模擬數據庫關系。)

model.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,)

視圖.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()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM