Question

I have a Game model which uses a foreign key Moves like so:

class Moves(models.Model):
   player1 = []
   player2 = []

   def make_move(self, a_int, b_int, c_bool):        
    if c_bool:
        self.player1.append(a_int)
    else:
        self.player2.append(b_int)

   #...irrelevant functions

class Game(models.Model):
   #...irrelevant variables
   moves = models.ForeignKey(Moves)

So I want for each game to have a UNIQUE set of Moves. Moves are stored in the list of player1 and player2.

So in my tests I do something like this...

class MakeMoveTestCase(TestCase):    
    def test_make_move(self):
        g = Game()
        g.moves.make_move(3, 0, False) #####throws error here
        g.moves.make_move(4, 0, False)

and get this error:

TypeError: int() argument must be a string or a number, not 'list'

I need help getting rid of this error. Also, if you have a better design I would like to see it.

Was it helpful?

Solution

Instead of showing you how to get rid of this error, I will try to explain what is wrong with your design.

First, the Moves class, as you defined it, does not make sense as a model. This is because there are no model fields defined there. If you want to store data with this model, you have to define attributes which are instances of field classes.

So you would probably want to rename Moves to Move (as it represents a single move) and redefine it as follows:

from django.db import models
from django.utils.translation import ugettext as _

class Move(models.Model):
    PLAYER_1, PLAYER_2 = 1, 2
    PLAYERS = (
        (PLAYER_1, _('Player 1')),
        (PLAYER_2, _('Player 2'))
    )

    game = models.ForeignKey(Game, related_name='moves')
    player = models.IntegerField(choices=PLAYERS)
    x = models.IntegerField()
    y = models.IntegerField()

Now, if you want to create a game and a move and add it to the game then you could write something like this:

game = Game.objects.create(...)
move = Move.objects.create(game=game, x=1, y=5, player=Move.PLAYER_2)

OTHER TIPS

If you're implementing in Django, and you want to keep a good model-view-template distinction, then you should consider changes to your Moves model. Models should only represent data and therefore make_move should be moved to a view or some other support class. The players in your Moves model also seems like it should be a separate class since a player could theoretically have moves in multiple games, etc. In other words, decouple the players from the moves.

Also, I agree with @piotrekw, that Moves should become Move and should only represent a single move. Each move should link to the Player who made it as a foreign key field, and also to the Game it belongs to.

class Player(models.Model):
  pass

class Game(models.Model):
  player1 = models.ForeignKeyField(Player._id)

class Move(models.Model):
  game = models.ForeignKeyField(Game._id)
  player = models.ForeignKeyField(Player._id)
  a_int = models.IntegerField()
  b_int = models.IntegerField()

From here, actually adding a Move should follow standard Django practice you can find in the tutorial here.

You should create Moves instance in your test before Game instance and link it to game before call it's method:

class MakeMoveTestCase(TestCase):    
    def test_make_move(self):
        moves = Moves()
        game = Game(moves=moves)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top