Question

I'm writing a Game Website, where the draw is a series of four digits. e.g 1234

I"m trying to write a query in django that will select all winners based on the four digits entered. winners are any combination of the same numbers or the same combination, 1 2 3 4, 2 3 1 4, 4 1 3 2 are all winners.

how is the most efficient way to write this query.

--------------------- Edit, sorry for not providing model samples here there are below: -----------

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.
Was it helpful?

Solution

I'd advise adjusting the code to save the digits so that they are saved in sorted order. E.g. if the user puts in "5262" then it should store that as "2256". Then, when you select a winning set of digits, you can sort those, and filter by simple equality. This will perform much, much better than trying to check for all possible combinations.

If you need the unsorted selection for other purposes, then add a new field to the model sortedDigits or something so that you have it to compare against.

OTHER TIPS

Code:

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)

Assuming GamesPlayed is the model object for all games played, with a text field numbers containing the four selected numbers in the format NNNN.

If you're on Python 2.5 itertools does not have permutations. The docs have an implementation you can use: http://docs.python.org/library/itertools.html#itertools.permutations

Is the order of the numbers important?

If not, you could sort the digits for tickets and draws in ascending order, then use your code

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

As an aside, Your try... except block won't catch the situation when there are no winners. The DoesNotExist exception is thrown by the get method (see docs).

If there isn't a winning ticket, the filter method will return an empty queryset, but not raise an error. You can then check whether there are winners using an if statement.

if winners
    # there are winners
    self.winner = True
else:
    # there are not winners
    self.winner = False
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top