2017-09-21 101 views
0

因此我定義了一個模型Language。我需要跟蹤創建語言對象的人。我也不需要同一種語言的多個實例。出於這個原因,我希望能夠檢查用戶是否嘗試創建語言時是否已經存在語言。如果它存在,那麼我會告訴用戶他們可以使用已經存在的那個。如果不是,他們可以創建它。我正在使用自定義User模型。如何檢查模型的實例是否已經存在於數據庫中

USERS = get_user_model().objects.all() 
from random import choice 

class Language(models.Model): 
    language = models.CharField(max_length=25, unique=True) 
    creator = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) 

    def __str__(self): 
     return self.language 

    def get_absolute_url(self): 
     return reverse('chinemerem:language_index') 

    def save(self, *args, **kwargs): 
     self.language = self.language.upper() 
     super(Language, self).save(*args, **kwargs) 

我可以在djangoshell創建try/exceptLanguage情況如下圖所示。

try: 
    language, exists = Language.objects.get_or_create(creator=choice(USERS), 
           language='german') 
except IntegrityError: 
    pass 

django admin拋出IntegrityError當我嘗試創建通過Django管理語言實例。

我的問題:如何在模型中實現類似try/except塊的內容,以檢查用戶是否嘗試創建一個語言時是否已經存在語言?

我已經做了很多搜索,並且遇到了signals pre_save,我猜想這可能會有幫助。但django文檔通過示例的方式很少。

任何幫助,將不勝感激。

+0

製作模型管理器並定義一個管理器方法,檢查是否存在匹配的語言。在這種情況下,您始終需要使用管理器方法進行保存 –

+0

不相關,但不應將創建查詢集作爲模塊級變量 - 最終將生成陳舊數據 –

+0

[如何處理]匹配查詢的可能重複存在「當獲取對象](https://stackoverflow.com/questions/33119507/how-to-handle-matching-query-does-not-exist-when-getting-an-object) – Sayse

回答

3

Your problem comes from the way you call get_or_create() - 你可以在兩個領域的查詢參數,所以它首先試圖找到一個Languagelanguage='german'creator=<youruserhere>。如果相同的語言存在,但具有不同的創造者,它不where條款,因此ORM試圖創建一個新的記錄匹配,然後在language踢的唯一約束英寸

的解決方案是通過creator在一個字典爲defaults參數,所以查找時只languagecreator提出僅用於創建如有必要,新的記錄:

language, created = Language.objects.get_or_create(
    # this is used for lookup (get) 
    language="german", 
    # this is used for eventual create 
    defaults={'creator':choice(USERS)} 
    ) 

作爲一個側面說明,返回的元組的第二個元素是True如果如果已經存在的記錄是f,則創建新記錄並且False ound。

WRT /在管理問題,除非你做了一些奇怪的事情在你的ModelAdmin或它的形式,或者你沒有張貼您的整個模型的代碼,它應該只是重新顯示形式的錯誤消息,不會引發IntegrityError(除非最終你得到表單驗證和實例保存之間的競爭條件,但這應該是非常非常罕見的)。驗證過程中的唯一性檢查是ModelForm的默認功能,因此我不能應用它的唯一原因就是不會調用super().clean()而忽略表單的clean()方法。

+0

我在那裏有整個型號代碼。從你的回答中我知道你並不完全理解我的問題。也許我沒有很好地描述它。但是您已經提醒我注意,我只能使用**語言來調用'get_or_create',因爲這是我感興趣的變量,而不是創建者。 – Parousia

+0

** ...繼續... **但我的問題不是在'django' shell中創建'Language'模型。問題是,django管理員在嘗試創建一個已經存在的語言時抱怨'UNIQUE約束失敗'。比方說,用戶*布魯諾*第一次創建一個'Language' *德語*。後來另一個用戶* parousia *想要創建相同的*德語*'語言'。現在有一個衝突,因爲* german *是'unique'。所以問題是:**我如何檢查'語言'表是否存在*德語*並優雅地退出,如果它已經存在?** *優雅退出是我尋求的* – Parousia

+0

@Parousia正如已經提到的,除非你奇怪的事情,Django管理員應該在這裏做正確的事情 - 重新顯示錯誤消息的形式。我只是雙重檢查,它開箱即用。如果你得到了一個500錯誤,那麼你的代碼中還有一些你沒有發佈的東西或者在你的安裝中某處破壞了的東西(除非你最終在表單驗證和實例保存之間得到競爭條件,但是這應該是非常特殊的)。 –

0

可以使用exists方法,

getLanguage = Language.objects.filter(language=request['langugage']).exists() 

if not getLanguage: 
# create the model 
0

感謝大家。以下是我如何用模型管理器解決問題。

我使用了兩個模型管理器。我使用objects = models.Manager()作爲模型管理者之一,因此我不需要重寫很多代碼。

from django.db import models 
class LanguageManager(models.Manager): 
    def language_exists(self, language): 
     return super(LanguageManager, self).get_queryset().filter(language=language.upper()).exists() 

class Language(models.Model): 
    creator = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) 
    language = models.CharField(max_length=25, unique=True) 
    objects = models.Manager() 
    languages = LanguageManager() 

    def __str__(self): 
     return self.language 

    def get_absolute_url(self): 
     return reverse('chinemerem:language_index') 

    def save(self, *args, **kwargs): 
     self.language = self.language.upper() 
     if Language.languages.language_exists(self.language): 
      return "Language already exists." 
     else: 
      super(Language, self).save(*args, **kwargs) 
相關問題