2010-02-19 85 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