如何添加其他模型以根据自定义条件列出和过滤

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

  

code returns 符合条件的玩家及其姓氏列表。

但是我无法将 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 不在足球比赛中。

希望能帮助我解决额外的问题,最终解决我对这个问题的担忧。

A) 可能的错误:

也许你忘记了在循环中为权重初始化一些变量。 (我不清楚你的意图)

其他可能的问题可能是制表符和空格的组合。将代码粘贴到 Whosebug 后,代码缩进不正确。也许你的编辑器有不同的标签大小,也许 Python2 将其解释为有效,但不是你在编辑器中看到的。尝试 运行 python 和 -t 选项,如果解释的逻辑取决于选项卡大小,则查看警告。 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))

在视图变慢之前不应该这样做,因为可读性很重要,也许这不是瓶颈。
缺点:
increaseCase() When() 函数的表达式可读性差。一切都重新制定,但它仍然不如普通 Python 列表上的过滤器可读。


编辑:
我接受您忘记设置建议@Houda 的主键和外键,这在 Django 中是正常的,允许 Django 向这些表添加索引可能为时已晚。

如果来自 ProfileWeight 的所有数据都可以放入内存中,那么您可以轻松地通过字典映射它,否则您可以像最初那样按个人名称过滤它或加载他们被一部分玩家记住了。

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模拟数据库关系。)

我写了自己的代码,你是对的结果总是空的因为这个条件:

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

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

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

views.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()