เอกสาร Djangoเพียงตัวอย่างรายการเอาชนะและsave()
delete()
อย่างไรก็ตามฉันต้องการกำหนดการประมวลผลพิเศษสำหรับโมเดลของฉันเมื่อสร้างขึ้นเท่านั้น สำหรับทุกคนที่คุ้นเคยกับ Rails มันจะเทียบเท่ากับการสร้าง:before_create
ตัวกรอง เป็นไปได้หรือไม่
เอกสาร Djangoเพียงตัวอย่างรายการเอาชนะและsave()
delete()
อย่างไรก็ตามฉันต้องการกำหนดการประมวลผลพิเศษสำหรับโมเดลของฉันเมื่อสร้างขึ้นเท่านั้น สำหรับทุกคนที่คุ้นเคยกับ Rails มันจะเทียบเท่ากับการสร้าง:before_create
ตัวกรอง เป็นไปได้หรือไม่
คำตอบ:
การลบล้าง__init__()
จะทำให้โค้ดถูกเรียกใช้งานเมื่อใดก็ตามที่มีการสร้างอินสแตนซ์การเป็นตัวแทนของวัตถุไพ ธ อน ฉันไม่รู้จักราง แต่:before_created
ตัวกรองให้ฉันฟังเหมือนเป็นรหัสที่จะดำเนินการเมื่อสร้างวัตถุในฐานข้อมูล หากคุณต้องการรันโค้ดเมื่อสร้างอ็อบเจ็กต์ใหม่ในฐานข้อมูลคุณควรลบล้างsave()
ตรวจสอบว่าอ็อบเจ็กต์มีpk
แอตทริบิวต์หรือไม่ รหัสจะมีลักษณะดังนี้:
def save(self, *args, **kwargs):
if not self.pk:
# This code only happens if the objects is
# not in the database yet. Otherwise it would
# have pk
super(MyModel, self).save(*args, **kwargs)
create
? นั่นเป็นวิธีแก้ปัญหาที่น่าสนใจ แต่จะใช้ไม่ได้ในกรณีที่วัตถุกำลังถูกสร้างขึ้นโดยใช้Object(**kwargs).save()
หรือรูปแบบอื่น ๆ ในสิ่งนั้น
super(MyModel, self).save(*args, **kwargs)
หรือไม่?
self.pk
ไม่ใช่ตัวเลือกที่ดีที่สุดในการตรวจสอบว่าวัตถุกำลังสร้างขึ้นใหม่หรือเพิ่งอัปเดต บางครั้งคุณระบุอ็อบเจ็กต์ id ในเวลาสร้าง (ค่าที่สร้างที่ไม่ใช่ฐานข้อมูลที่กำหนดเองเช่นKSUID
) และจะทำให้ส่วนคำสั่งนี้ไม่ดำเนินการ ... มีself._state.adding
ค่าที่ต้องตรวจสอบว่ามีการบันทึกเป็นครั้งแรกหรือเพิ่งอัปเดตซึ่ง ช่วยในกรณีเหล่านั้น
นี่เป็นเรื่องเก่ามีคำตอบที่ได้รับการยอมรับว่าใช้ได้ผล (ของ Zach) และสำนวนอื่น ๆ ด้วยเช่นกัน (Michael Bylstra's) แต่เนื่องจากยังคงเป็นผลลัพธ์แรกใน Google ที่คนส่วนใหญ่เห็นฉันคิดว่าเราต้องการแนวทางปฏิบัติที่ดีที่สุดมากกว่า modern-django คำตอบสไตล์ที่นี่ :
from django.db.models.signals import post_save
class MyModel(models.Model):
# ...
@classmethod
def post_create(cls, sender, instance, created, *args, **kwargs):
if not created:
return
# ...what needs to happen on create
post_save.connect(MyModel.post_create, sender=MyModel)
ประเด็นคือ:
@classmethod
แทนที่จะเป็น@staticmethod
เพราะส่วนใหญ่คุณจะต้องอ้างอิงสมาชิกคลาสแบบคงที่ในโค้ดจะสะอาดกว่านี้ถ้าแกน Django มีpost_create
สัญญาณจริง (Imho ถ้าคุณต้องการส่งผ่านอาร์กิวเมนต์บูลีนเพื่อเปลี่ยนพฤติกรรมของเมธอดนั่นควรเป็น 2 วิธี)
ตัวอย่างวิธีสร้างสัญญาณ post_save (จากhttp://djangosnippets.org/snippets/500/ )
from django.db.models.signals import post_save
from django.dispatch import receiver
@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
"""Create a matching profile whenever a user object is created."""
if created:
profile, new = UserProfile.objects.get_or_create(user=instance)
นี่คือการอภิปรายอย่างรอบคอบว่าควรใช้สัญญาณหรือวิธีการบันทึกแบบกำหนดเองดีที่สุดหรือไม่https://web.archive.org/web/20120815022107/http://www.martin-geber.com/thought/2007/10/29/ django-signs-vs-custom-save-method /
ในความคิดของฉันการใช้สัญญาณสำหรับงานนี้มีประสิทธิภาพมากกว่าอ่านง่ายกว่า แต่ยาวกว่า
instance.save()
ดังนั้นในกรณีนี้ยังมีการลงโทษด้านประสิทธิภาพเนื่องจากจะมีหนึ่ง INSERT และหนึ่งแบบสอบถาม UPDATE ไปยังฐานข้อมูล
เพื่อตอบคำถามอย่างแท้จริงcreate
วิธีการในตัวจัดการแบบจำลองเป็นวิธีมาตรฐานในการสร้างวัตถุใหม่ใน Django หากต้องการลบล้างให้ทำสิ่งที่ต้องการ
from django.db import models
class MyModelManager(models.Manager):
def create(self, **obj_data):
# Do some extra stuff here on the submitted data before saving...
# For example...
obj_data['my_field'] = my_computed_value(obj_data['my_other_field'])
# Now call the super method which does the actual creation
return super().create(**obj_data) # Python 3 syntax!!
class MyModel(models.model):
# An example model
my_field = models.CharField(max_length=250)
my_other_field = models.CharField(max_length=250)
objects = MyModelManager()
ในตัวอย่างนี้ฉันกำลังลบล้างเมธอดเมธอดของผู้จัดการcreate
เพื่อทำการประมวลผลเพิ่มเติมก่อนที่จะสร้างอินสแตนซ์จริง
หมายเหตุ:รหัสเช่น
my_new_instance = MyModel.objects.create(my_field='my_field value')
จะเรียกใช้create
วิธีการแก้ไขนี้แต่รหัสเช่น
my_new_unsaved_instance = MyModel(my_field='my_field value')
จะไม่
การลบล้าง__init__()
จะช่วยให้คุณสามารถรันโค้ดได้เมื่อโมเดลถูกสร้างอินสแตนซ์ __init__()
อย่าลืมที่จะเรียกผู้ปกครอง
คุณสามารถแทนที่วิธีการสร้างด้วยตัวจัดการแบบกำหนดเองหรือเพิ่มวิธีการเรียนในคลาสแบบจำลอง https://docs.djangoproject.com/en/1.11/ref/models/instances/#creating-objects
คำตอบที่ต้องการนั้นถูกต้อง แต่การทดสอบเพื่อบอกว่าวัตถุกำลังสร้างไม่ได้ผลหรือไม่หากโมเดลของคุณมาจาก UUIDModel ฟิลด์ pk จะมีค่าอยู่แล้ว
ในกรณีนี้คุณสามารถทำได้:
already_created = MyModel.objects.filter(pk=self.pk).exists()