2017-02-23 142 views
0

我试图做一个插入和更新数据的形式。我已阅读这些:表格验证插入与更新

在我的项目,但是,我没有使用的ModelForm。

forms.py:

这是登记他/她的用户名和FIRST_NAME当用户看到的形式。这也是现有用户在尝试更改他/她的用户名和/或first_name时看到的形式。

from django import forms 
from .models import User 

class SettingsForm(forms.Form): 
    username = forms.CharField(max_length=16) 
    first_name = forms.CharField(max_length=32) 
    # ... and many more form fields 

    def clean_slug(self): 
     """Make sure that the username entered by the user will be unique in the database""" 

     username = self.cleaned_data['username'] 
     try: 
      product = User.objects.get(username=username) 
     except User.DoesNotExist: 
      # Good, there is no one using this username 
      pass 
     else: 
      # There is alreaady a user with this username 
      raise forms.ValidationError('This username has been used. Try another.') 

     return username 

表格清理按预期用于插入数据。但是,更新数据时,它会抱怨用户名已被使用(自然,因为用户名已经存在于数据库中)。

如何在不使用FormForm时(而不使用ModelForm)引发ValidationError而更新数据?

(在这种情况下不使用ModelForm的原因是:我们可能会停止使用orm,SettingsForm可能包含来自不同模型的字段的混合,某些字段可能会以显示的形式重复数百次用户,我们还需要不与任何模型绑定的自定义字段......以及使用ModelForm相当具有挑战性(不可能)的其他场景。此问题的目的是找出是否有方法实现所需的结果,而无需使用ModelForm。)

+0

你想要的形式允许更改现有用户的用户名? –

+0

@RomanB。是。更新了问题以反映这一点。 – Flux

+0

您可以很好地自定义ModelForms。看看我的博客文章:https://colinkingswood.github.io/Model-Form-Customisation/ –

回答

1

ValidationError显然是因为你正在实例化用户名已存在时的SettingsForm,正如你已经说过的。

所以,如果你想添加的形式,可以做双责,我想补充一个__init__到SettingsForm接受一个is_update并将其保存为一个成员变量,像这样......

def __init__(self, is_update=False, **kwargs): 
    self.is_update = is_update 
    return super(SettingsForm, self).__init__(**kwargs) 

然后修改您的clean_slug()是:

def clean_slug(self): 
    username = self.cleaned_data['username'] 
    try: 
     product = User.objects.get(username=username) 
    except User.DoesNotExist: 
     # Good, there is no one using this username 
     pass 
    else: 
     if not self.is_update: # for 'create' usage 
      # There is already a user with this username 
      raise forms.ValidationError('This username has been used. Try another.') 
     else: # for 'update' usage 
      pass 
    return username 
+0

谢谢!所以在views.py中,我做'forms = SettingsForm(is_update = True)'来更新?希望能够在您的答案中使用该表单的例子。初学者在这里。 – Flux

+0

当然,基本上在你的创建视图中,你将用'is_update = False'实例化表单,并在更新中使用True。如果你想把它写出来,你可以把你现有的视图代码放到问题的实例化表单中,我会编辑它。 (否则我不知道你是否使用基于类或基于功能的视图等) – neomanic

+0

解决方案有一个小问题。如果对于现有用户,新用户名将与另一个现有用户的用户名相同?它不会引发错误,它应该。您需要检查用户名是否与正在更新的用户的用户名相同。看看我的答案。 –

0

实际上,你希望你的形式做两回事取决于它是否是创建或更新。

因此,要么有两种形式使用不同的clean_slug方法,要么传入一个参数来告诉表单,如果它是更新或创建的(这里有另一个来自neomanic的回答)。

就我个人而言,我认为最简单的方法是子类化您的窗体并更改干净的slu method方法。使用新表单进行更新并使用您的原始表单进行创建。

class UpdateSettingsForm(settingsForm): 

    def clean_slug(self): 
     username = self.cleaned_data['username'] 
     return username 
+0

在这两种情况下(无论是关于创建还是更新),都需要检查用户名是否已存在,因为用户可能会更改它。我认为只用一个班就可以轻松处理。 –

2

你有三种情况:

  1. 是新用户,
  2. 的用户存在,不会改变他/她的用户名
  3. 用户存在和改变他/她的用户名

您需要检查用户名是否仅在前两种情况下才存在。

如果它是一个现有的用户,您应该将User实例传递给表单,以便您可以在clean_slug函数中使用它,比方说self.user变量。

然后,你可以只添加两行clean_slug功能,当你想它应该工作:

def clean_slug(self): 
    """Make sure that the username entered by the user will be unique in the database""" 

    username = self.cleaned_data['username'] 

    # If the user exists and the username has not been changed, 
    # just return the username 
    if self.user and self.user.username == username: 
     return username 

    try: 
     product = User.objects.get(username=username) 
    except User.DoesNotExist: 
     # Good, there is no one using this username 
     pass 
    else: 
     # There is alreaady a user with this username 
     raise forms.ValidationError('This username has been used. Try another.') 

    return username