Je souhaite modifier une valeur clé étrangère lorsque son supprimée de la base de données. J'ai donc regardé le doc et utilisé la méthode on_delete = models.SET (foo). https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.SETDjango passer à l'auto models.SET on_delete
C'est ma définition du modèle
class OrderLine(models.Model):
product = models.ForeignKey(Product, on_delete=models.SET(getDuplicateProduct), null=True)
quantity = models.PositiveSmallIntegerField(default=1)
finalPricePerUnit = models.PositiveIntegerField()
order = models.ForeignKey(Order, on_delete=models.PROTECT)
dateCreated = models.DateTimeField(auto_now=False, auto_now_add=True)
Et voici ma méthode qui est appelé suppression
def getDuplicateProduct(orderline):
productToDelete = orderline.product
# some logic to generate duplicate copy and returning it
Cependant, le problème est que je ne peux pas passer argument à cette méthode C'est pourquoi je ne peux pas savoir quel produit a été supprimé. J'ai aussi essayé d'utiliser des signaux comme indiqué dans cette réponse django model on_delete pass self to models.SET()
J'ai aussi essayé d'utiliser des signaux, mais aussi ne fonctionne pas. Je n'arrive pas à trouver une solution appropriée pour cela. Dites-moi si quelqu'un a une idée sur la façon d'atteindre cet objectif.
EDIT
C'est le code que je utilise des signaux
@receiver(pre_delete, sender=Product)
def getDuplicateProduct(sender, **kwargs):
product = kwargs['instance']
orderlines = product.orderline_set.all()
#further processing
Maintenant, le problème est que django tente de supprimer mes lignes de commande aussi bien (comme on_delete par défaut est réglé sur cascade). Et si je définis le on_Delete à SET_NULL, il définit la clé étrangère à null.
EDIT -2 Voici le code que je utilise
@receiver(pre_delete, sender=Product)
def getDuplicateProduct(sender, **kwargs):
product = kwargs['instance']
orderlines = product.orderline_set.all()
product.name = product.name + ' ' + product.get_type_display()
newProduct = deepcopy(product)
newProduct.name = product.name + ' ' + product.get_type_display()
newProduct.pk=None
newProduct.id=None
newProduct.save()
product.duplicateProductId = newProduct.id
product.old_orderlines = orderlines
product.save()
@receiver(post_delete, sender=Product)
def handlePostDelete(sender, **kwargs):
product = kwargs['instance']
newProduct = Product.objects.get(id=product.duplicateProductId)
for orderline in product.old_orderlines:
orderline.product = newProduct
orderline.save()
EDIT-3 affichage mise en œuvre complète d'exhaustivité.
@receiver(pre_delete, sender=Product)
def handlePreDelete(sender, **kwargs):
product = kwargs['instance']
orderlines = product.orderline_set.all()
shouldCreate=False
for orderline in orderlines:
if orderline.order.status>1:
shouldCreate=True
product.shouldCreate = shouldCreate
if shouldCreate:
product.old_orderlines = orderlines
product.save()
else:
product.save()
return None
@receiver(post_delete, sender=Product)
def handlePostDelete(sender, **kwargs):
product = kwargs['instance']
shouldCreate = product.shouldCreate
if shouldCreate:
newProduct = deepcopy(product)
newProduct.name = product.name + ' ' + product.get_type_display()
newProduct.pk=None
newProduct.id=None
newProduct.save()
# Do whatever you want with product.old_orderlines
for orderline in product.old_orderlines:
orderline.product = newProduct
orderline.save()
"Je n'aurai aucune référence de ligne de commande dans la méthode du récepteur.". Pourquoi pas? Pouvez-vous poster le code que vous avez utilisé avec des signaux? – solarissmoke
Dans votre deuxième édition, je pense que c'est le 'deepcopy' qui cause le problème. Voyez si vous pouvez le déplacer dans le gestionnaire 'post_delete'. Aussi, vous devez copier le jeu de requête pour éviter qu'il ne soit tabassé (j'ai modifié ma réponse ci-dessous). – solarissmoke
@solarissmoke J'ai essayé de déplacer la copie profonde à handler post_delete et il semble fonctionner, merci et désolé pour réponse tardive, est sorti de la ville pendant 10 jours. – Anurag