2010-02-19 88 views
22

我使用Django ModelForms來創建表單。我有我的表單設置,它工作正常。帶有get_or_create的Django表單

form = MyForm(data=request.POST) 

if form.is_valid(): 
    form.save() 

我現在想要的是,雖然表格首先檢查是否存在相同的記錄。如果是這樣,我希望它獲得該對象的ID,如果不是,我希望它將其插入數據庫,然後給我該對象的ID。這可能使用類似:

form.get_or_create(data=request.POST) 

我知道創建窗體時,我可以做

form = MyForm(instance=object) 

但是這是行不通的,因爲我還是想擁有的情況下不存在的實例反對

編輯:

說我的模型是

class Book(models.Model): 
    name = models.CharField(max_length=50) 
    author = models.CharField(max_length=50) 
    price = models.CharField(max_length=50) 

我想要一個有人可以填寫的表格來存儲書籍。但是,如果在db中已經有一本名稱,作者和價格相同的書,我顯然不希望再次添加此記錄,所以只想查找它的id並不添加它。

我知道在Django中有一個函數; get_or_create這樣做,但有什麼類似的形式?或者我會做這樣的事情

if form.is_valid(): 
    f = form.save(commit=false) 
    id = get_or_create(name=f.name, author=f.author, price=f.price) 

感謝

回答

27

我喜歡這種方法:

if request.method == 'POST': 
    form = MyForm(request.POST) 
    if form.is_valid(): 
     book, created = Book.objects.get_or_create(**form.cleaned_data) 

這樣,你得到採取的模型形式的所有功能(除.save())和get_or_create快捷的優勢。

+1

似乎是一種很好的方法,但並不真正遵循'** form.cleaned_data'位。具體來說,**有什麼作用?任何人都可以詳述嗎? – 2011-07-23 06:46:22

+5

'**'解開字典。請參閱:http://docs.python.org/tutorial/controlflow.html#unpacking-argument-lists – 2011-07-24 19:53:43

+0

@rz:感謝您的澄清。 – 2011-07-24 22:20:20

1

你只需要兩個案件在回發之前的觀點已經發生,像

if id: 
    form = MyForm(instance=obj) 
else 
    form = MyForm() 

,那麼你可以調用form.save ()在回發和Django將照顧其餘。

+0

有了這樣的假設: 「如果ID」 後你可以正確地實例化obj變量。 – Tom 2010-02-19 16:32:28

+0

請參閱上面的編輯以獲取更多信息。謝謝 – John 2010-02-22 09:33:40

1

你是什麼意思「如果存在相同的記錄」?如果這是一個簡單的ID檢查,那麼你的視圖代碼看起來是這樣的:

if request.method == 'POST': 
    form = MyForm(request.POST) 
    if form.is_valid(): 
     form.save() 
else: 
    if get_id: 
     obj = MyModel.objects.get(id=get_id) 
     form = MyForm(instance=obj) 
    else: 
     form = MyForm() 

這裏的概念是發生支票上的GET請求,以便對後保存,Django會已經確定如果這是一個新的或現有的記錄。

如果您檢查相同記錄更復雜,則可能需要將邏輯移位一下。

+0

請參閱上面的編輯以獲取更多評論。謝謝 – John 2010-02-22 09:39:24

0

我會做到這一點 -

if request.method == 'POST': 
    form = MyForm(request.POST) 
    if form.is_valid(): 
     name = form.cleaned_data['name'] 
     author = form.cleaned_data['author'] 
     price = form.cleaned_data['prince'] 

     if name and author and price: 
      book, created = Book.objects.get_or_create(name=name, \ 
       author=author, price=price) 

      if created: 
       # fresh entry in db. 
      else: 
       # already there, maybe update? 

      book.save() 
0

基礎上的答案和評論,我要創建我的情況,其中包括對基礎模型使用unique_together的不同的解決方案。你可能會發現這個代碼也很有用,因爲我實際上已經使其非常通用。

我在form.save()方法中有自定義代碼,我想用它來創建一個新對象,所以我不想簡單地不使用form.save()調用。我不得不把我的代碼檢查在form.save()方法中,我認爲這是一個合理的地方。

我有一個實用函數來壓扁iterables。

def flatten(l, a=list()): 
    """ 
     Flattens a list. Just do flatten(l). 
     Disregard the a since it is used in recursive calls. 
    """ 
     for i in l: 
      if isinstance(i, Iterable): 
       flatten_layout(i, a) 
      else: 
       a.append(i) 
     return a 

ModelForm,我覆蓋validate_unique()方法:

def validate_unique(self): 
    pass 

這是關於什麼的我保存方法是這樣的:

def save(self, commit=True): 
    unique_fields = flatten(MyObject._meta.unique_together) 
    unique_cleaned_data = {k: v for k, v in self.cleaned_data.items() if k in unique_fields} 
    # check if the object exists in the database based on unique data 
    try: 
     my_object = MyObject.objects.get(**unique_cleaned_data) 
    except MyObject.DoesNotExist: 
     my_object = super(MyModelFormAjax, self).save(commit) 
     # -- insert extra code for saving a new object here --- 
    else: 
     for data, value in self.cleaned_data.items(): 
      if data not in unique_fields: 
       # only update the field if it has data; otherwise, retain 
       # the old value; you may want to comment or remove this 
       # next line 
       if value: 
        setattr(my_object, data, value) 

     if commit: 
      my_object.save() 
    return my_object