在Django中,如何编写查询以选择四个整数的所有组合?

1 投票
3 回答
556 浏览
提问于 2025-04-15 15:25

我正在制作一个游戏网站,游戏的结果是四个数字,比如1234。

我想在django中写一个查询,来选出所有的赢家,赢家是指输入的四个数字的任意组合。比如1 2 3 4,2 3 1 4,4 1 3 2这些都是赢家。

我想知道,写这个查询的最有效的方法是什么。

--------------------- 编辑,抱歉没有提供模型示例,下面有: -----------

class Draw(models.Model):
    digit1 = models.PositiveSmallIntegerField(null=True,blank=True)
    digit2 = models.PositiveSmallIntegerField(null=True,blank=True)
    digit3 = models.PositiveSmallIntegerField(null=True,blank=True)
    digit4 = models.PositiveSmallIntegerField(null=True,blank=True)
    draw_date = models.DateTimeField()
    closed = models.BooleanField()
    winner = models.BooleanField()

    def __unicode__(self):
        return "Draw For Week Ending %s" %(self.draw_date)

    def get_absolute_url(self):
        return "/draw/%s/" % (self.draw_date)

    def save(self, force_insert=False, force_update=False):
        if self.digit1 and self.digit2 and self.digit3 and self.digit4:
            #check if there are winners
            try:
                winners = Ticket.objects.filter(draw=self.id,digit1=self.digit1,digit2=self.digit2,digit3=self.digit3,digit4=self.digit4)
                self.winner = True
            except Ticket.DoesNotExist:
                self.winner = False                
            #close & save draw/winners
            self.closed = True
            # Add new Draw for following week.
            new_date = self.draw_date + datetime.timedelta(hours=168)
            new_draw= Draw(draw_date=new_date)
            new_draw.save()
        super(Draw, self).save(force_insert, force_update) # Call the "real" save() method.

class Serial(models.Model):
    serial = models.CharField(max_length=4)
    closed = models.BooleanField(unique=False)

    def __unicode__(self):
        return "%s" %(self.serial)

    def get_absolute_url(self):
        return "/draw/serial/%s/" % (self.serial)    

class Ticket(models.Model):
    draw = models.ForeignKey(Draw)
    digit1 = models.PositiveSmallIntegerField()
    digit2 = models.PositiveSmallIntegerField()
    digit3 = models.PositiveSmallIntegerField()
    digit4 = models.PositiveSmallIntegerField()
    date = models.DateField(auto_now_add=True,editable=False)
    active = models.BooleanField(default=True)
    serial_used = models.ForeignKey(Serial,related_name="ticket_serial_used")

    def __unicode__(self):
        return "#: %s - %s" %(self.id,self.draw)

    def get_absolute_url(self):
        return "/ticket/%s/" % (self.id)    

    def save(self, force_insert=False, force_update=False):
        if self.serial_used:
            serial = Serial.objects.get(pk=self.serial_used.id)
            serial.closed = True
            serial.save()
        super(Ticket, self).save(force_insert, force_update) # Call the "real" save() method.

3 个回答

0

数字的顺序重要吗?

如果不重要的话,你可以把彩票的数字按从小到大的顺序排列,然后再用你的代码。

winners = Ticket.objects.filter(draw=self.id,digit1=self.digit1,digit2=self.digit2,digit3=self.digit3,digit4=self.digit4)

顺便提一下,你的try...except代码块无法处理没有中奖者的情况。当没有中奖者时,get方法会抛出DoesNotExist异常(查看文档)。

如果没有中奖的彩票,filter方法会返回一个空的查询集,但不会报错。你可以用一个if语句来检查是否有中奖者。

if winners
    # there are winners
    self.winner = True
else:
    # there are not winners
    self.winner = False
0

代码:

from itertools import permutations
winning_numbers = "1234"
winning_combinations = map(lambda v: "".join(v), list(permutations(winning_numbers, 4)))

winners = GamesPlayed.objects.filter(numbers__in=winning_combinations)

假设GamesPlayed是一个模型对象,用来表示所有玩过的游戏,其中有一个文本字段numbers,里面包含了四个选中的数字,格式是NNNN

如果你使用的是Python 2.5版本,itertools这个库里没有permutations这个功能。文档里有一个你可以使用的实现方法:http://docs.python.org/library/itertools.html#itertools.permutations

5

我建议你调整一下代码,把数字保存成排序好的样子。比如说,如果用户输入“5262”,那么你应该把它存成“2256”。这样,当你要选出一组中奖的数字时,可以先把这些数字排序,然后简单地进行比较。这样做的效率会高很多,比起去检查所有可能的组合要好得多。

如果你需要保留原始顺序的数字用于其他目的,可以在模型里加一个新字段,比如叫 sortedDigits,这样你就可以用它来进行比较了。

撰写回答