เมื่อฉันขอให้ตัวจัดการโมเดลรับวัตถุมันจะเพิ่มขึ้นDoesNotExistเมื่อไม่มีวัตถุที่ตรงกัน
go = Content.objects.get(name="baby")แทนที่จะเป็นDoesNotExistฉันgoจะNoneเป็นอย่างไร
เมื่อฉันขอให้ตัวจัดการโมเดลรับวัตถุมันจะเพิ่มขึ้นDoesNotExistเมื่อไม่มีวัตถุที่ตรงกัน
go = Content.objects.get(name="baby")แทนที่จะเป็นDoesNotExistฉันgoจะNoneเป็นอย่างไร
คำตอบ:
ไม่มีวิธีการ 'ภายใน' ในการทำเช่นนี้ Django จะเพิ่มข้อยกเว้น DoesNotExist ทุกครั้ง วิธีที่ใช้สำนวนในการจัดการสิ่งนี้ในไพ ธ อนคือการห่อมันด้วยการลองจับ:
try:
    go = SomeModel.objects.get(foo='bar')
except SomeModel.DoesNotExist:
    go = Noneสิ่งที่ฉันทำคือ subclass models.Manager สร้างsafe_getโค้ดที่เหมือนด้านบนและใช้ตัวจัดการนั้นสำหรับโมเดลของฉัน SomeModel.objects.safe_get(foo='bar')วิธีการที่คุณสามารถเขียน:
SomeModel.objects.filter(foo='bar').first()สิ่งนี้คืนค่าการจับคู่แรกหรือไม่มี มันจะไม่ล้มเหลวหากมีหลายกรณีเช่นqueryset.get()
                    filter().first()ฉันคิดว่าข้อยกเว้นเป็นวิธีที่จะดำเนินการ
                    ตั้งแต่ django 1.6 คุณสามารถใช้วิธีแรก ()ดังนี้:
Content.objects.filter(name="baby").first()
get()เพิ่มDoesNotExistข้อยกเว้นหากไม่พบวัตถุสำหรับพารามิเตอร์ที่กำหนด ข้อยกเว้นนี้ยังเป็นคุณลักษณะของคลาสโมเดลDoesNotExistสืบทอดยกเว้นจากdjango.core.exceptions.ObjectDoesNotExist
คุณสามารถตรวจจับข้อยกเว้นและกำหนดNoneให้ไปได้
from django.core.exceptions import ObjectDoesNotExist
try:
    go  = Content.objects.get(name="baby")
except ObjectDoesNotExist:
    go = Noneคุณสามารถสร้างฟังก์ชั่นทั่วไปสำหรับสิ่งนี้
def get_or_none(classmodel, **kwargs):
    try:
        return classmodel.objects.get(**kwargs)
    except classmodel.DoesNotExist:
        return Noneใช้สิ่งนี้เหมือนด้านล่าง:
go = get_or_none(Content,name="baby")go จะเป็น None หากไม่มีรายการที่ตรงกับที่อื่นจะส่งคืนรายการเนื้อหา
หมายเหตุ: มันจะเพิ่มข้อยกเว้น MultipleObjectsReturned ถ้ามีการส่งคืนมากกว่าหนึ่งรายการสำหรับ name = "baby"
คุณสามารถทำได้ด้วยวิธีนี้:
go  = Content.objects.filter(name="baby").first()ตอนนี้ตัวแปรไปอาจเป็นวัตถุที่คุณต้องการหรือไม่มี
Ref: https://docs.djangoproject.com/en/1.8/ref/models/querysets/#django.db.models.query.QuerySet.first
เพื่อทำให้สิ่งต่าง ๆ ง่ายขึ้นนี่คือตัวอย่างโค้ดที่ฉันเขียนโดยอิงจากอินพุตจากคำตอบที่ยอดเยี่ยมที่นี่:
class MyManager(models.Manager):
    def get_or_none(self, **kwargs):
        try:
            return self.get(**kwargs)
        except ObjectDoesNotExist:
            return Noneและจากนั้นในรูปแบบของคุณ:
class MyModel(models.Model):
    objects = MyManager()แค่นั้นแหละ. ตอนนี้คุณมี MyModel.objects.get () รวมถึง MyModel.objetcs.get_or_none ()
คุณสามารถใช้existsกับตัวกรอง:
Content.objects.filter(name="baby").exists()
#returns False or True depending on if there is anything in the QSทางเลือกสำหรับถ้าคุณเพียงต้องการทราบว่ามีอยู่
exists()จะใช้ร่วมกับifข้อก่อนดึงวัตถุจึงก่อให้เกิดการตีสองครั้งเพื่อ db ฉันจะยังคงแสดงความคิดเห็นในกรณีที่มันช่วยคนอื่น
                    การจัดการข้อยกเว้นที่จุดต่าง ๆ ในมุมมองของคุณอาจยุ่งยากจริง ๆ แล้วเรื่องการกำหนด Model Manager แบบกำหนดเองในไฟล์ models.py เช่น
class ContentManager(model.Manager):
    def get_nicely(self, **kwargs):
        try:
            return self.get(kwargs)
        except(KeyError, Content.DoesNotExist):
            return Noneและรวมไว้ในคลาสโมเดลเนื้อหา
class Content(model.Model):
    ...
    objects = ContentManager()ด้วยวิธีนี้สามารถจัดการได้อย่างง่ายดายในมุมมองเช่น
post = Content.objects.get_nicely(pk = 1)
if post:
    # Do something
else:
    # This post doesn't existreturn self.get(**kwargs)มันทำงานได้สำหรับฉัน อย่าบอกว่ามีอะไรผิดปกติกับคำตอบเพียงแค่เคล็ดลับสำหรับทุกคนที่พยายามใช้มันกับรุ่นที่ใหม่กว่า
                    เป็นหนึ่งในฟังก์ชั่นที่น่ารำคาญที่คุณอาจไม่ต้องการนำมาใช้ใหม่:
from annoying.functions import get_object_or_None
#...
user = get_object_or_None(Content, name="baby")get_object_or_Noneแต่พบว่ายังคงเพิ่มขึ้นMultipleObjectsReturnedหากมีวัตถุมากกว่าหนึ่งรายการ ดังนั้นผู้ใช้อาจพิจารณาล้อมรอบด้วยtry-except(ซึ่งฟังก์ชั่นของตัวเองมีtry-exceptอยู่แล้ว)
                    หากคุณต้องการโซลูชันแบบบรรทัดเดียวที่ไม่เกี่ยวข้องกับการจัดการข้อยกเว้นคำสั่งแบบมีเงื่อนไขหรือข้อกำหนดของ Django 1.6+ ให้ทำสิ่งนี้แทน:
x = next(iter(SomeModel.objects.filter(foo='bar')), None)ฉันคิดว่ามันไม่ควรใช้ get_object_or_404()
from django.shortcuts import get_object_or_404
def my_view(request):
    my_object = get_object_or_404(MyModel, pk=1)ตัวอย่างนี้เทียบเท่ากับ:
from django.http import Http404
def my_view(request):
    try:
        my_object = MyModel.objects.get(pk=1)
    except MyModel.DoesNotExist:
        raise Http404("No MyModel matches the given query.")คุณสามารถอ่านเพิ่มเติมเกี่ยวกับget_object_or_404 ()ในเอกสารออนไลน์ django
จาก django 1.7 เป็นต้นไปคุณสามารถทำสิ่งต่อไปนี้:
class MyQuerySet(models.QuerySet):
    def get_or_none(self, **kwargs):
        try:
            return self.get(**kwargs)
        except self.model.DoesNotExist:
            return None
class MyBaseModel(models.Model):
    objects = MyQuerySet.as_manager()
class MyModel(MyBaseModel):
    ...
class AnotherMyModel(MyBaseModel):
    ...ข้อดีของ "MyQuerySet.as_manager ()" คือทั้งสองอย่างต่อไปนี้จะทำงานได้:
MyModel.objects.filter(...).get_or_none()
MyModel.objects.get_or_none()นี่คือความแตกต่างของฟังก์ชั่นตัวช่วยที่อนุญาตให้คุณเลือกส่งผ่านQuerySetตัวอย่างในกรณีที่คุณต้องการรับวัตถุที่ไม่ซ้ำกัน (ถ้ามี) จากชุดแบบสอบถามนอกเหนือจากallชุดแบบสอบถามวัตถุของโมเดล(เช่นจากชุดย่อยของรายการเด็กที่เป็นของ ตัวอย่างผู้ปกครอง):
def get_unique_or_none(model, queryset=None, **kwargs):
    """
        Performs the query on the specified `queryset`
        (defaulting to the `all` queryset of the `model`'s default manager)
        and returns the unique object matching the given
        keyword arguments.  Returns `None` if no match is found.
        Throws a `model.MultipleObjectsReturned` exception
        if more than one match is found.
    """
    if queryset is None:
        queryset = model.objects.all()
    try:
        return queryset.get(**kwargs)
    except model.DoesNotExist:
        return Noneสามารถใช้สองวิธีเช่น:
obj = get_unique_or_none(Model, **kwargs) ดังที่ได้กล่าวไว้ก่อนหน้าobj = get_unique_or_none(Model, parent.children, **kwargs)โดยไม่มีข้อยกเว้น:
if SomeModel.objects.filter(foo='bar').exists():
    x = SomeModel.objects.get(foo='bar')
else:
    x = Noneใช้ข้อยกเว้น:
try:
   x = SomeModel.objects.get(foo='bar')
except SomeModel.DoesNotExist:
   x = Noneมีข้อโต้แย้งเล็กน้อยเกี่ยวกับเมื่อหนึ่งควรใช้ข้อยกเว้นในหลาม ในอีกด้านหนึ่ง "การขอการอภัยได้ง่ายกว่าการขออนุญาต" ในขณะที่ฉันเห็นด้วยกับสิ่งนี้ฉันเชื่อว่าข้อยกเว้นควรจะยังคงอยู่ข้อยกเว้นและ "กรณีอุดมคติ" ควรรันโดยไม่ต้องกดปุ่มใดปุ่มหนึ่ง
เราสามารถใช้ Django builtin .DoesNotExistยกเว้นที่แนบมากับรุ่นที่มีชื่อเป็น ดังนั้นเราไม่ต้องนำเข้าObjectDoesNotExistข้อยกเว้น
แทนที่จะทำ:
from django.core.exceptions import ObjectDoesNotExist
try:
    content = Content.objects.get(name="baby")
except ObjectDoesNotExist:
    content = Noneพวกเราสามารถทำได้:
try:
    content = Content.objects.get(name="baby")
except Content.DoesNotExist:
    content = Noneนี่เป็นตัวเลียนแบบจาก get_object_or_404 ของ Django ยกเว้นว่าเมธอดจะคืนค่า None สิ่งนี้มีประโยชน์มากเมื่อเราต้องใช้only()แบบสอบถามเพื่อเรียกคืนบางฟิลด์เท่านั้น วิธีนี้สามารถยอมรับรูปแบบหรือชุดแบบสอบถาม
from django.shortcuts import _get_queryset
def get_object_or_none(klass, *args, **kwargs):
    """
    Use get() to return an object, or return None if object
    does not exist.
    klass may be a Model, Manager, or QuerySet object. All other passed
    arguments and keyword arguments are used in the get() query.
    Like with QuerySet.get(), MultipleObjectsReturned is raised if more than
    one object is found.
    """
    queryset = _get_queryset(klass)
    if not hasattr(queryset, 'get'):
        klass__name = klass.__name__ if isinstance(klass, type) else klass.__class__.__name__
        raise ValueError(
            "First argument to get_object_or_none() must be a Model, Manager, "
            "or QuerySet, not '%s'." % klass__name
        )
    try:
        return queryset.get(*args, **kwargs)
    except queryset.model.DoesNotExist:
        return Noneอาจจะดีกว่าที่คุณใช้:
User.objects.filter(username=admin_username).exists()