写在前面

  最近的开发学习碰到了两个比较重要的知识点:ModelForm表单和后端URL拼接。这两点不算太难但也比较复杂,并且在后续开发也很常用。常不常用我不知道,反正我第一次是写懵了所以在这里总结一下这部分知识点。

正文

ModelForm表单

  得益于ModelForm表单,我们不必在前端写复杂的html代码来实现表单。我们只需要一个简单的循环,以及对每一个字段的引用就可以做到了:

1
2
3
4
5
6
7
8
9
10
11
<form method="post" novalidate>
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label for="exampleInputEmail1">{{ field.label }}</label>
{{field}}
<span style="color: red">{{ field.errors.0 }}</span>
</div>
{% endfor %}
<button type="submit" class="btn btn-success">确认提交</button>
</form>

  但是正是因为input框由django的ModelForm为我们自动生成,为其添加样式(例如BootStrap)就变得比较困难。在django中存在解决这个问题的途径。

第一种:修改ModelForm类的widget属性

  widget属性决定了每一个字段通过django渲染出的html代码格式。例如要为username字段添加class="form-control"的类名,那么我们就可以在定义ModelForm类时:

1
2
3
4
5
6
7
8
class ExampleModelForm(models.ModelForm):

class Meta:
model = models.Administrator
fields = ["username"]
widgets = {
"username": forms.CharField(attrs={"class":"form-control"})
}

  在字典中我们还可以添加其他键值关系,这样在前端渲染input时,就会带上我们所指定的class="form-control"。同样的,在widgets字典中还可以指定多个字段自己的widget属性。

  但是这样做会带来一个问题,例如我们对所有输入框都要应用BootStrap的样式,那么在widgets中逐个添加是否有些繁琐了呢?当然,我们也有办法解决这个问题。

第二种:重写init方法

在创造这个ExampleModelForm类时,其存在默认的__init__(self)方法。我们重写这个方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class BootStrapModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 循环每个字段为其插件进行设置
for name, field in self.fields.items():
# 字段中有属性,则增加
if field.widget.attrs:
field.widget.attrs["class"] = "form-control"
field.widget.attrs["placeholder"] = field.label
else:
field.widget.attrs = {
"class": "form-control",
# 还可以添加其他的标签,例如placeholder
"placeholder": field.label
}

  对上述代码做出一些解释。super().__init__(*args,**kwargs)是必须执行的,其初始化父类。然后,我们对存在的所有字段进行遍历,并对其中的field设置widget。其中,判断句if是为了防止覆盖原本的attrs属性。对于重写后的__init__(self)方法,我们可以单独将其作为一个父类,之后需要使用的所有ModelForm都改为继承此父类即可。

拼接URL

  在访问url时,许多网站采用GET方式传参,这种参数一般显式地拼接在url后,例如

1
https://127.0.0.1:8000/index/?page=4

在开发中,这样的参数可能不止一个,对于多个参数,在点击超链接时为了防止参数的损失,解决方式之一就是对超链接进行后端的拼接。django自然也支持这个操作。例如我们需要对上述url拼接一个key=12的参数使得其能够携带两个参数,我们首先要获取已有的参数。在访问url时,request变量会携带所有与这次url访问有关的信息,因此,我们要从这里动手脚。当然,出于保护机制,django不允许直接修改request的值,因此,我们需要拷贝一份。
1
query_dict = copy.deepcopy(request.GET)

  说明一下上一行代码:request.GET携带了以GET方式传递的所有参数,其类型是一个字典。然后,我们要对query_dict添加键值关系,setlist()方法支持这种操作。例如我们来添加key=12

1
query_dict.setlist("key", 12)

  这样,新的键值关系就被我们添加完成了。此时query_dict的值应该是

1
2
3
4
query_dict = {
"page": 4,
"key": 12
}

   最后,我们拼接url。

1
2
3
4
url = "https://127.0.0.1:8000/index/?{}".format(query_dict.urlencode())

print(url)
# "https://127.0.0.1:8000/index/?page=4&key=12"