Question

I have two models: Play and PlayParticipant, defined (in part) as:

class PlayParticipant(models.Model):
    player = models.ForeignKey('Player')
    play = models.ForeignKey('Play')
    note = models.CharField(max_length=100, blank=True)

A piece of my code has a play p which has id 8581, and I'd like to add participants to it. I'm trying to use RelatedManager's .create() to do that, like:

p.playparticipant_set.create(player_id=2383)

From which, Django constructs:

INSERT INTO `api_playparticipant` (`player_id`, `play_id`, `note`) VALUES (2383, 2383, '')

Is this a bug in Django, or am I misusing .create()?

Copy-pasting shell for sanity check:

In [17]: p = Play.objects.get(id=8581)

In [18]: p.id
Out[18]: 8581L

In [19]: p.playparticipant_set.create(player_id=2383)
...
IntegrityError: (1452, 'Cannot add or update a child row: a foreign key constraint fails (`gc/api_playparticipant`, CONSTRAINT `play_id_refs_id_60804ffd462e0029` FOREIGN KEY (`play_id`) REFERENCES `api_play` (`id`))')

From query.log:

5572 Query       INSERT INTO `api_playparticipant` (`player_id`, `play_id`, `note`) VALUES (2383, 2383, '')
Was it helpful?

Solution

I don't see how is your first example supposed to be a bug? This behavior is completely intuitive. Your p is a play with an id of 2383, and you're calling the create method on its related set. You're also specifying an extra field, called player_id, and giving it a value of 2383. It's only logical that both play id will be 2383 (because that's the id of the play containing this related set) and that player id will also be 2383 (because you explicitly passed that value in).

Your second example would seem to indicate a bug, but I cannot reproduce it. Here are my models:

class Player(models.Model):
    name = models.CharField(max_length=100)

class Play(models.Model):
    title = models.CharField(max_length=100)

class PlayParticipant(models.Model):
    player = models.ForeignKey('Player')
    play = models.ForeignKey('Play')
    note = models.CharField(max_length=100, blank=True)

Here's the shell output:

>>> player1 = Player.objects.create()
>>> player2 = Player.objects.create()
>>> player1.id
2
>>> player2.id
3
>>> play1 = Play.objects.create()
>>> play2 = Play.objects.create()
>>> play1.id
3
>>> play2.id
4
>>> pp1 = play1.playparticipant_set.create(player_id=2)
>>> pp1.play.id
3
>>> pp1.player.id
2

In any case, why are you posting this to SO? Django has a bugtracker, a couple of active official mailing lists and a couple of IRC channels.

OTHER TIPS

You should be using a ManyToManyField in the Play model that relates to the zero or more participants. In that code you would just be doing

play.players.add(player)

It is not a bug; check the documentation; specifically the section on Extra fields on many-to-many relationships. It specifies:

Unlike normal many-to-many fields, you can't use add, create, or assignment (i.e., beatles.members = [...]) to create relationships.

The only way to create this type of relationship is to create instances of the intermediate model.

I cannot reproduce that behaviour. With similar models, I can run:

m = Manufacturer.objects.get(1)
p = m.product_set.create(name='23',category_id=1,price=23,delivery_cost=2)

and I get new instance p of Product, whose p.manufacturer foreign key equals m.

This is on Django-1.0.2 with PostgreSQL; which version of Django do you use, and which SQL backend?

Try to use two new minimal models with ForeignKey field on one of them, which should work; then make these models gradually closer to models that exhibit the failing behaviour. This way you can isolate single change that makes it misbehave; this change is key to the reason.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top