ฉันจะแทนที่ Delete() บนโมเดลได้อย่างไรและยังคงใช้งานได้กับการลบที่เกี่ยวข้อง

ฉันประสบปัญหาเนื่องจากฉันกำลังลบ Widget โดยใช้ some_widget_instance.delete() ฉันยังมีโมเดลชื่อ WidgetFile ซึ่งมีเมธอด override Delete() เพื่อให้ฉันสามารถลบไฟล์ออกจากฮาร์ดไดรฟ์ของฉันได้เมื่อ WidgetFile ถูกลบ ปัญหาที่ฉันมีคือถ้าฉันลบวิดเจ็ตและมี WidgetFiles ที่เกี่ยวข้องดังนี้:

class WidgetFile(models.Model):

    widget = models.ForeignKey(Widget)

เมื่อฉันลบ Widget นั้น WidgetFiles นั้นจะถูกลบไป แต่เมธอด Delete() จะไม่ทริกเกอร์และทำสิ่งพิเศษในฮาร์ดไดรฟ์ของฉัน ความช่วยเหลือใด ๆ ที่ชื่นชมมาก


person orokusaki    schedule 08.10.2009    source แหล่งที่มา
comment
ปัญหานี้เกิดขึ้นเนื่องจากเมื่อวิดเจ็ตถูกลบ วิดเจ็ตจะไม่ทริกเกอร์เมธอด Delete() ในแต่ละวิดเจ็ตที่ขึ้นต่อกัน (คลาสที่มีการอ้างอิงคีย์ต่างประเทศ) เพียงลบวัตถุที่เกี่ยวข้องออกจากฐานข้อมูล ทำให้มีประสิทธิภาพมากขึ้น แต่นำไปสู่ปัญหาเช่นนี้อย่างเห็นได้ชัด   -  person orokusaki    schedule 17.12.2009


คำตอบ (8)


ฉันกำลังทำสิ่งเดียวกันและสังเกตเห็นนักเก็ตในเอกสาร Django ที่คุณควรคำนึงถึง

การเอาชนะวิธีโมเดลที่กำหนดไว้ล่วงหน้า

การแทนที่การลบ โปรดทราบว่าเมธอด Delete() สำหรับออบเจ็กต์ไม่จำเป็นต้องถูกเรียกเมื่อลบออบเจ็กต์จำนวนมากโดยใช้ QuerySet เพื่อให้แน่ใจว่าตรรกะการลบแบบกำหนดเองได้รับการดำเนินการ คุณสามารถใช้สัญญาณ pre_delete และ/หรือ post_delete

ซึ่งหมายความว่าข้อมูลโค้ดของคุณจะไม่เสมอไปทำสิ่งที่คุณต้องการ การใช้ Signals เป็นตัวเลือกที่ดีกว่าในการจัดการกับการลบ

ฉันไปกับสิ่งต่อไปนี้:

import shutil
from django.db.models.signals import pre_delete 
from django.dispatch import receiver

@receiver(pre_delete)
def delete_repo(sender, instance, **kwargs):
    if sender == Set:
        shutil.rmtree(instance.repo)
person ElementalVoid    schedule 01.10.2012
comment
Setคืออะไร? โมเดลที่คุณกำลังติดตามการลบ? - person John Wang; 07.11.2019

ฉันคิดออกแล้ว ฉันเพิ่งใส่สิ่งนี้ลงในโมเดล Widget นั้น:

def delete(self):
    files = WidgetFile.objects.filter(widget=self)
    if files:
        for file in files:
            file.delete()
    super(Widget, self).delete()

สิ่งนี้ทริกเกอร์เมธอด Delete() ที่จำเป็นในแต่ละออบเจ็กต์ที่เกี่ยวข้อง ดังนั้นจึงทริกเกอร์โค้ดการลบไฟล์แบบกำหนดเองของฉัน ใช่แล้ว ฐานข้อมูลมีราคาแพงกว่า แต่เมื่อคุณพยายามลบไฟล์ในฮาร์ดไดรฟ์ การเข้าถึง db เพิ่มอีกสองสามครั้งก็ไม่ใช่เรื่องใหญ่โตอะไร

person orokusaki    schedule 08.10.2009
comment
ยังไม่ชัดเจนว่าเหตุใดคุณจึงคิดว่า Celery หรือ cron จะไม่พบสถานการณ์ที่คล้ายกันซึ่งไฟล์ที่ถูกลบสามารถเปิดไว้แล้วสำหรับการดำเนินการอ่าน/เขียนจากกระบวนการอื่น ไม่ว่าในกรณีใด คุณจะต้องใช้รหัสเพื่อจัดการกรณีพิเศษ - person Joseph Paetz; 11.12.2013
comment
ฉันลบบิตนั้นออกแล้ว... เมื่อ 4.5 ปีที่แล้ว ฉันคิดว่าอาจเป็นความคิดที่ดี แต่ฉันไม่แน่ใจว่าทำไม - person orokusaki; 31.03.2014

การใช้ clear() ก่อนที่จะลบ จะลบอ็อบเจ็กต์ทั้งหมดออกจากชุดอ็อบเจ็กต์ที่เกี่ยวข้อง

ดู django-following-relationships-backward

ตัวอย่าง:

group.link_set.clear() 
group.delete() 
person panchicore    schedule 08.10.2009

ดูเหมือนว่าจะรู้สึกเต็มอิ่มหาก Widget หนึ่งเชื่อมต่อกับ WidgetFile เดียวเท่านั้น ในกรณีนั้น คุณควรใช้ OneToOneField< /ก>

จาก ตัวอย่างแบบ On-to-one:

# Delete the restaurant; the waiter should also be removed
>>> r = Restaurant.objects.get(pk=1)
>>> r.delete()
person vikingosegundo    schedule 08.10.2009
comment
จริงอยู่ แต่ Django ทำการลบจำนวนมากในระดับฐานข้อมูลกับบริกรทั้งหมดโดยไม่เรียกใช้วิธีการลบแต่ละวิธี ซึ่งมีราคาถูกกว่า แต่ก็ธรรมดาน้อยกว่าด้วย - person orokusaki; 08.10.2009

เพียงเพื่อหาทางที่เป็นไปได้ในการแก้ไขปัญหานี้: ลบล่วงหน้า สัญญาณ (ไม่ได้หมายความว่าไม่มีวิธีแก้ปัญหาที่แท้จริง)

person che    schedule 08.10.2009


some_widget_instance และอินสแตนซ์ของ Widget หรือของ WidgetFile ? เพราะหากเป็นอินสแตนซ์ของ Widget มันจะไม่ได้รับฟังก์ชัน delete() ที่คุณกำหนดเองซึ่งอยู่ในคลาส WidgetFile

person thornomad    schedule 08.10.2009

จาก Django 1.9 หากคุณกำหนด on_delete=models.CASCADE สำหรับฟิลด์ มันจะลบวัตถุที่เกี่ยวข้องทั้งหมดเมื่อลบ

person CLTanuki    schedule 08.04.2016
comment
นี่ไม่ถูกต้อง คำถามไม่ได้เกี่ยวกับการลบแบบเรียงซ้อน มันเกี่ยวกับการรับรองว่ามีการเรียกใช้เมธอด delete ที่เกี่ยวข้อง - person orokusaki; 09.04.2016