2010-06-22 51 views

回答

168

沒有「內置」的方式來做到這一點。 Django每次都會引發DoesNotExist異常。 在Python來處理這種情況慣用的辦法是將它包裝在一個嘗試捕捉:

try: 
    go = SomeModel.objects.get(foo='bar') 
except SomeModel.DoesNotExist: 
    go = None 

我沒做什麼,就是要繼承models.Manager,創建safe_get像上面的代碼,並使用該經理爲我的楷模。這樣你可以寫:SomeModel.objects.safe_get(foo='bar')

+5

+1用於捕獲特定的異常。 –

+6

很好地使用SomeModel.DoesNotExist,而不是導入異常。 – Symmitchry

+102

該解決方案長四行。對我來說這太多了。使用django 1.6,你可以使用'SomeModel.objects.filter(foo ='bar')。first()'這會返回第一個匹配,或者返回None。它不會失敗,如果有'queryset.get()' – guettli

23

From django docs

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 
17

您可以爲此創建一個通用函數。

def get_or_none(classmodel, **kwargs): 
    try: 
     return classmodel.objects.get(**kwargs) 
    except classmodel.DoesNotExist: 
     return None 

使用此象下面這樣:

go = get_or_none(Content,name="baby") 

去將無如果沒有條目匹配否則將返回內容條目。

注:這將引發異常MultipleObjectsReturned如果超過一個條目返回的名稱=「寶貝」在你的意見不同點

6

處理異常真會是如何定義自定義模型管理器cumbersome..What,在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() 

通過這種方式也可以是EAS隨手處理的意見,即

post = Content.objects.get_nicely(pk = 1) 
if post: 
    # Do something 
else: 
    # This post doesn't exist 
+0

我真的很喜歡這個解決方案,但無法讓它工作就像在使用python 3.6時一樣。想要留下一個說明,即修改ContentManager中的返回值爲'return self.get(** kwargs)'讓它爲我工作。不要說任何關於答案的錯誤,只是對於任何人試圖在更高版本中使用它的提示(或者其他任何使它不能爲我工作的提示)。 – skagzilla

9

爲了方便起見,這裏是我寫的代碼,根據輸入從精彩回帖這裏的一個片段:

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()

+4

另外,不要忘記從django.core.exceptions導入: import ObjectDoesNotExist –

8

你可以使用exists帶有過濾器:

Content.objects.filter(name="baby").exists() 
#returns False or True depending on if there is anything in the QS 

只是如果你只是想知道,如果它存在

+1

這會在存在時導致額外的數據庫調用。不是一個好主意 – Christoffer

1

這裏有輔助功能,可以讓你的變化替代如果您希望從除模型的all對象查詢集(例如,來自屬於父實例的子項子集的子集)以外的查詢集獲取唯一對象(如果存在),則可以傳入QuerySet實例:

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 

這可以以兩種方式使用,例如:

  1. obj = get_unique_or_none(Model, **kwargs)如previosuly討論
  2. obj = get_unique_or_none(Model, parent.children, **kwargs)
+0

我發現'django煩人'已經處理了這種情況。 – Gary

76

由於django的1.6可以使用像first()方法,以便:

Content.objects.filter(name="baby").first() 
+10

在這種情況下,如果有多個匹配項,則不會引發錯誤。 –

+1

我喜歡這個解決方案,因爲使用'objecst.get()'推斷我們知道數據庫中有一個或沒有。 – EmptyFlash

+2

'FeroxTL'你需要爲這個答案寫信@guettli,正如他在你發佈前一年接受的答案中所評論的那樣。 – colminator

1

毫無例外:

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 

有一個關於何時應該在Python中使用的異常位的說法。一方面,「請求原諒比獲得許可要容易」。雖然我同意這一點,但我認爲應該保留一個例外,那就是例外,「理想情況」應該運行而不會觸及一個例外。

1

從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() 
7

這是其中之一annoying functions你可能不想重新執行:

from annoying.functions import get_object_or_None 
#... 
user = get_object_or_None(Content, name="baby") 
1

我們可以使用Django內建的異常,它是一個連接到名爲.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 
2

如果你想要一個簡單的單行的解決方案,不涉及異常處理,條件語句或1.6或更高版本的Django的要求,而是執行此操作:

x = next(iter(SomeModel.objects.filter(foo='bar')), None) 
1

,我認爲它不是「T壞主意使用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.") 

您可以在django在線文檔中閱讀更多關於get_object_or_404()

相關問題