发布于 

django笔记(4):为ModelForm表单添加样式、如何拼接GET参数

为 django 中的 modelform 添加样式。

写在前面

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

正文

ModelForm 表单

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

1
2
3
4
5
6
7
8
9
10
<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
9
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
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 后,例如

在开发中,这样的参数可能不止一个,对于多个参数,在点击超链接时为了防止参数的损失,解决方式之一就是对超链接进行后端的拼接。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
5
6
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"