2016-04-12 8 views
1

データベースから削除された外部キー値を変更したいと思います。だから私はその文書を見て、on_delete = models.SET(foo)メソッドを使いました。 https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.SETDjangoはmodels.SET on_deleteに自己を渡します

は、これは私のモデル定義

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) 

されており、ここでの問題は、私は、このメソッドに引数を渡すことができないということですが、これは削除

def getDuplicateProduct(orderline): 
    productToDelete = orderline.product 
    # some logic to generate duplicate copy and returning it 

に呼び出された私の方法であります私はどの製品が削除されたのか分からないのです。私もこの答えで指定された信号を使用してみましたdjango model on_delete pass self to models.SET()

私も信号を使ってみましたが、それも動作しませんでした。私はこれに対して適切な解決策を見つけることができないようです。 誰かがこれを達成する方法について考えているかどうか教えてください。

EDIT

これが今の問題はDjangoは(デフォルトon_deleteをカスケードに設定されているもの)だけでなく、私の注文ラインを削除しようとすることです私は信号

@receiver(pre_delete, sender=Product) 
def getDuplicateProduct(sender, **kwargs): 
    product = kwargs['instance'] 
    orderlines = product.orderline_set.all() 
    #further processing 

に使っていたコードです。また、on_DeleteをSET_NULLに設定すると、外部キーがNULLに設定されます。

EDIT -2 ここでは、私は完全のための完全な実施を投稿

@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 を使用していたコードです。

@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()    
+0

"受信者方法での注文ラインの参照はありません。"何故なの?シグナルで使用したコードを投稿できますか? – solarissmoke

+0

2回目の編集では、問題を引き起こしているのは「deepcopy」だと思います。 'post_delete'ハンドラに移動できるかどうか確認してください。また、それはclobbered(私は私の答えを編集した)を避けるために、クエリセットをコピーする必要があります。 – solarissmoke

+0

@solarissmoke私はpost_deleteハンドラに深いコピーを移動しようとしましたが、それはうまくいくようですが、感謝と遅れて返事申し訳ありません、町から10日間行きました。 – Anurag

答えて

2

信号はこれを行う正しい方法です。

あなたは、信号受信機からOrderLineを取得することができます。

@receiver(pre_delete, sender=Product) 
def getDuplicateProduct(sender, **kwargs): 
    product = kwargs['instance'] 
    orderlines = product.orderline_set.all() 
    # orderlines contains all the OrderLines foreign keyed to the product. 

orderlinesあなたが反復処理またはupdate in bulkできるクエリセットです。

EDITはアプローチは、時間によってpre_delete信号が、Djangoはすでにそれがon_deleteで処理する必要がある、とこれらの変更が上書きされます関連をモデルに決定している解雇しているため、動作しません上記の提案が判明します。それは少し不格好ですが

このアプローチは、動作します:

pre_delete受信機ではまず、: post_delete受信機で、その後

@receiver(pre_delete, sender=Product) 
def handlePreDelete(sender, **kwargs): 
    product = kwargs['instance'] 
    # Store the OrderLines as a property of the object 
    # Have to copy it otherwise it will be empty later 
    product.old_orderlines = copy(product.orderline_set.all()) 

コピーインポートコピーから:

@receiver(post_delete, sender=Product) 
def handlePostDelete(sender, **kwargs): 
    product = kwargs['instance'] 
    # Do whatever you want with product.old_orderlines 
    for line in product.old_orderlines: 
     # ... 

これらの2つのイベントの間で、DjangoはOr3でSET_NULL(またはあなたが設定したもの)を実行しました。 derLines。

+0

この解決策の問題は、djangoがデフォルトのon_deleteがカスケードに設定されているのと同様に、私の注文線を削除しようとしていることです。そして、もし私がSET_NULLにon_Deleteをセットすると、それはヌルに外部キーを設定します。 – Anurag

+0

私は、削除が起こる前に別の製品を指すようにForeignKeyを変更することを考えましたか? – solarissmoke

+0

それは本当です、私は新しい製品に注文線を指したいと思います。しかし、私はこの変更が適切に行われているか競合状態があるかどうかはわかりません。 – Anurag

0

@ solarissmokeの回答には適切な解決策がありますが、これ以上の選択肢を与えるために私はこれを投稿します。 productインスタンスをお持ちの場合はorderlinesにすることができます。たとえば、あなたはそうのようOrderLine.productrelated_nameを追加した場合:あなたは、あなたの信号でこれを行うことができます

class OrderLine(models.Model): 
    product = models.ForeignKey(Product, related_name='orderlines') 

:それを行うの

@receiver(pre_delete, sender=Product) 
def getDuplicateProduct(sender, **kwargs): 
    product = kwargs['instance'] 
    orderlines = product.orderlines.all() 

ちょうど別の方法を、orderlinesを取得します。

関連する問題