.create () utilizzo di Django RelatedManager?
-
12-09-2019 - |
Domanda
Ho due modelli: Play
e PlayParticipant
, definito (in parte) come:
class PlayParticipant(models.Model):
player = models.ForeignKey('Player')
play = models.ForeignKey('Play')
note = models.CharField(max_length=100, blank=True)
Un pezzo del mio codice ha un p
gioco che ha id 8581, e vorrei aggiungere partecipanti ad esso. Sto cercando di usare .create()
di RelatedManager per farlo, come:
p.playparticipant_set.create(player_id=2383)
Da cui, Django costrutti:
INSERT INTO `api_playparticipant` (`player_id`, `play_id`, `note`) VALUES (2383, 2383, '')
Si tratta di un bug in Django, o sto abusando .create()
?
conchiglia copia-incolla per controllo di integrità:
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`))')
Da query.log:
5572 Query INSERT INTO `api_playparticipant` (`player_id`, `play_id`, `note`) VALUES (2383, 2383, '')
Soluzione
Non vedo come è il tuo primo esempio dovrebbe essere un bug? Questo comportamento è del tutto intuitivo. Il vostro è un p giocare con ID 2383, e si sta chiamando il metodo sul suo insieme correlato creare. Sei anche specificando un campo aggiuntivo, chiamato player_id , e dandogli un valore di 2383. E 'logico che sia il gioco id sarà 2383 (perché questa è l'id del gioco che contiene questo insieme correlato) e quel giocatore id sarà anche 2383 (perché è stato passato in modo esplicito che il valore in).
Il secondo esempio sembrerebbe indicare un bug, ma non riesco a riprodurlo. Qui sono i miei modelli:
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)
Ecco l'output della shell:
>>> 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 ogni caso, perché stai scrivendo questo per SO? Django ha un bugtracker, un paio di attivi mailing list ufficiali e un paio di canali IRC.
Altri suggerimenti
Si dovrebbe essere utilizzando un ManyToManyField nel modello di gioco che fa riferimento ai zero o più partecipanti. In quel codice si sarebbe solo essere facendo
play.players.add(player)
Non è un bug; controllare la documentazione ; in particolare la sezione campi extra su molti-a-molti . Esso specifica:
A differenza dei normali molti-a-molti campi, non è possibile utilizzare
add
,create
, oassignment
(vale a dire,beatles.members = [...]
) per creare relazioni.L'unico modo per creare questo tipo di rapporto è quello di creare istanze del modello intermedio.
Non riesco a riprodurre quel comportamento. Con modelli simili, posso fare funzionare:
m = Manufacturer.objects.get(1)
p = m.product_set.create(name='23',category_id=1,price=23,delivery_cost=2)
e ottengo nuova p
di Product
, la cui p.manufacturer
chiave esterna è uguale m
esempio.
Questo è il Django-1.0.2 con PostgreSQL; quale versione di Django si usa, e che SQL backend?
Prova ad utilizzare due nuovi modelli minimali con il campo ForeignKey su uno di essi, che dovrebbe funzionare; poi fare questi modelli via via più vicino a modelli che mostrano il comportamento in mancanza. In questo modo è possibile isolare singola modifica che lo rende comportano male; questo cambiamento è la chiave per la ragione.