文章目錄
- 前言
- 一、ModelForm美化
- 1.自定義radio標簽樣式
- 2.自定義select標簽樣式
- 三、django離線腳本
- 四、pillow生成驗證碼
前言
sass專案視頻地址:https://www.bilibili.com/video/BV1uA411b77M
搭建虛擬環境鏈接:https://blog.csdn.net/weixin_45859193/article/details/115408555
采用django3.2.6版本,以untitled7為根目錄創建的專案名為web,在web專案中的view.py撰寫所有視圖,templates檔案存放模板標記語言、script存放腳本測驗,資料庫采用sqlite3, ModelForm美化標簽相關操作在form檔案中,static存放第三方庫及靜態檔案
urls.py如下:
from django.conf.urls import url, include
urlpatterns = [
url(r"^web/", include("web.urls"))
]
web/urls.py如下:
from django.conf.urls import url
from web import views
urlpatterns = [
# ModelForm美化相關
url(r'register/', views.register, name="register"),
url(r'radio/', views.radio, name="radio"),
# 圖片驗證碼相關
url(r'login/', views.login, name="login"),
url(r'image_code/', views.image_code, name="image_code"),
]
一、ModelForm美化
概述:搭配通過django中自行通過ModelForm渲染標簽時使用bootstrap樣式,
示例:創建一個用戶表結構示例,
models.py如下:
class UserInfo(models.Model):
username = models.CharField(verbose_name="用戶名", max_length=32)
email = models.EmailField(verbose_name="郵箱", max_length=32)
phone = models.CharField(verbose_name="手機號", max_length=32)
password = models.CharField(verbose_name="密碼", max_length=32)
通過sqllite3創建控制臺輸入:
python manage.py makemigrations
python manage.py migrate
BootStrapForm類(重寫django渲染標簽樣式)如下:
class BootStrapForm(object):
bootstrap_class_exclude = []
# 初始化方法
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 每個欄位的欄位名和欄位值
for name, field in self.fields.items():
if name in self.bootstrap_class_exclude:
continue
old_class = field.widget.attrs.get('class', "")
field.widget.attrs['class'] = '{} form-control'.format(old_class)
field.widget.attrs['placeholder'] = '請輸入{}'.format(field.label)
視圖函式如下:
from django.shortcuts import render
from django.core.validators import RegexValidator
from django import forms
from web import models
from web.form.bootstarp import BootStrapForm
class RegisterModelForm(BootStrapForm, forms.ModelForm):
# 這里如果想排除某個欄位可以使用 bootstrap_class_exclude = [欄位]
bootstrap_class_exclude = []
# 重寫欄位規則
phone = forms.CharField(label="手機號", validators=[RegexValidator(r'^(1[3|5|6|8]\d{9}$)', "手機號格式錯誤")])
password = forms.CharField(label="密碼", widget=forms.PasswordInput())
code = forms.CharField(label="驗證碼")
class Meta:
model = models.UserInfo
fields = "__all__"
def register(request):
form = RegisterModelForm()
return render(request, "register.html", {"form": form})
html模板如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
</head>
<style>
.account {
width: 600px;
margin: 0 auto;
}
</style>
<body>
<div class="account">
<h1>注冊</h1>
{% for field in form %}
{% if field.name == 'code' %}
<div class="form-group">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
<div style="display: flex;justify-content: space-between;flex-direction: row-reverse">
<div class="col-xs-5">
<input id="btnSms" class="btn btn-info" type="button" value="獲取驗證碼">
</div>
<div class="col-xs-5">
{{ field }}
<span class="error-msg"></span>
</div>
</div>
</div>
{% else %}
<div class="form-group">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{{ field }}
<span class="error-msg"></span>
</div>
{% endif %}
{% endfor %}
<button type="button" class="btn btn-info">登錄</button>
</div>
</body>
</html>
此時訪問路由如下:

概述:對于標簽而言是通過django.widgets.forms中通過模板標記語言渲染出來的,但是如果我們想用自己的也可以通過重寫的方式修改標簽樣式,這里拿select、radio標簽來展示,
為了方便展示我們創建一個專案表,
models.py如下:
class Project(models.Model):
COLOR_CHOICES = (
(1, '#56b8eb'),
(2, '#f28033'),
(3, '#ebc656'),
(4, '#a2d148'),
(5, '#20BFA4'),
(6, '#7461c2'),
(7, '#20bfa3'),
)
name = models.CharField(verbose_name='專案名', max_length=32)
color = models.SmallIntegerField(verbose_name='顏色', choices=COLOR_CHOICES, default=1)
desc = models.CharField(verbose_name='專案描述', max_length=255, null=True, blank=True)
priority_choices = (
("danger", "高"),
("warning", "中"),
("success", "低"),
)
priority = models.CharField(verbose_name='優先級', max_length=12, choices=priority_choices, default='danger')
通過sqllite3創建控制臺輸入:
python manage.py makemigrations
python manage.py migrate
1.自定義radio標簽樣式
進入django.forms生成的函式RadioSelect原始碼:
class RadioSelect(ChoiceWidget):
input_type = 'radio'
template_name = 'django/forms/widgets/radio.html'
option_template_name = 'django/forms/widgets/radio_option.html'
模板指向django中template檔案夾下的html,
我們先查看radio.html如下:
{% include "django/forms/widgets/multiple_input.html" %}
multiple_input.html如下:
{% with id=widget.attrs.id %}<ul{% if id %} id="{{ id }}"{% endif %}{% if widget.attrs.class %} class="{{ widget.attrs.class }}"{% endif %}>{% for group, options, index in widget.optgroups %}{% if group %}
<li>{{ group }}<ul{% if id %} id="{{ id }}_{{ index }}"{% endif %}>{% endif %}{% for option in options %}
<li>{% include option.template_name with widget=option %}</li>{% endfor %}{% if group %}
</ul></li>{% endif %}{% endfor %}
</ul>{% endwith %}
這些都是django的模板標記語言,大概就是通過widget來生成ul和li標簽,如果我們要修改可以根據以上模板標記語言修改,
radio_option.html如下:
{% include "django/forms/widgets/input_option.html" %}
input_option.html如下:
{% if widget.wrap_label %}<label{% if widget.attrs.id %} for="{{ widget.attrs.id }}"{% endif %}>{% endif %}{% include "django/forms/widgets/input.html" %}{% if widget.wrap_label %} {{ widget.label }}</label>{% endif %}
大致就是這樣,我們現在開始重寫,
創建widgets.py如下:
from django.forms import RadioSelect
class ColorRadioSelect(RadioSelect):
# template_name = 'django/forms/widgets/radio.html'
# option_template_name = 'django/forms/widgets/radio_option.html'
template_name = 'widgets/color_radio/radio.html'
option_template_name = 'widgets/color_radio/radio_option.html'
此時在該專案中的template創建widgets/color_radio檔案夾下的兩個radio.html、radio_option.html用于重寫,
radio.html如下:
{% with id=widget.attrs.id %}
<div{% if id %} id="{{ id }}"{% endif %}{% if widget.attrs.class %} class="{{ widget.attrs.class }}"{% endif %}>
{% for group, options, index in widget.optgroups %}
{% for option in options %}
<label {% if option.attrs.id %} for="{{ option.attrs.id }}"{% endif %} >
{% include option.template_name with widget=option %}
</label>
{% endfor %}
{% endfor %}
</div>
{% endwith %}
這里將ul和li標簽改成了div和label 標簽,
radio_option.html如下:
{% include "django/forms/widgets/input.html" %}
<span class="cycle" style="background-color:{{ option.label }}"></span>
這里沒有進行修改,只是在原基礎上增加了一個span標簽,
自此radio的重寫完成,那么現在開始寫表單和視圖,
結合上面的ModelForm表單美化(BootStrapForm函式:通過bootstarp的樣式美化標簽),
project.py如下:
from django import forms
from web.form.bootstarp import BootStrapForm
from web import models
from .widgets import ColorRadioSelect
class ProjectModelForm(BootStrapForm, forms.ModelForm):
bootstrap_class_exclude = ['color']
def __init__(self, request, *args, **kwargs):
super().__init__(*args, **kwargs)
self.request = request
class Meta:
model = models.Project
fields = ["name","color","desc"]
widgets = {
'desc': forms.Textarea,
'color': ColorRadioSelect(attrs={'class': 'color-radio'}),
}
通過init函式可以看到,該函式也支持傳入request引數,并且這里排除了color(即radio標簽,我們用自己的方式),
view.py如下:
from web.form.project import ProjectModelForm
def radio(request):
form = ProjectModelForm(request)
return render(request, "radio.html", {"form": form})
radio.html如下:
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{% static 'plugin/bootstrap-3.3.7-dist/css/bootstrap.min.css' %} ">
</head>
<style>
.account {
width: 600px;
margin: 0 auto;
}
.color-radio label {
margin-left: 0;
padding-left: 0;
}
.color-radio input[type="radio"] {
display: none;
}
.color-radio input[type="radio"] + .cycle {
display: inline-block;
height: 25px;
width: 25px;
border-radius: 50%;
border: 2px solid #dddddd;
}
.color-radio input[type="radio"]:checked + .cycle {
border: 2px solid black;
}
</style>
<body>
<div class="account">
{% for field in form %}
<div class="form-group">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{{ field }}
<span class="error-msg"></span>
</div>
{% endfor %}
</div>
</body>
</html>
此時訪問重寫radio的路由如下:

2.自定義select標簽樣式
對于select標簽而言,我們不能通過樣式的形式去修改,所以需要其他庫bootstrap-select、font-awesome圖示庫、jquery,
下載這些庫的鏈接:https://gitee.com/miaojiaxi/s25day01/tree/master/web/static/
bootstrap-select官網:https://www.bootstrapselect.cn/
全部安裝完成后,我們進入django.forms生成的標簽函式Select查看美化select標簽的原始碼:
class Select(ChoiceWidget):
input_type = 'select'
template_name = 'django/forms/widgets/select.html'
option_template_name = 'django/forms/widgets/select_option.html'
add_id_index = False
checked_attribute = {'selected': True}
option_inherits_attrs = False
因為和radio一樣,且內部select.html不用重寫,只用將select中的option標簽,所以我們只用重寫option_template_name即可,那么我們先查看一下原始碼select_option.html如下:
<option value="{{ widget.value|stringformat:'s' }}"{% include "django/forms/widgets/attrs.html" %}>{{ widget.label }}</option>
在widgets/color_radio檔案夾下創建select.html用于重寫select_option.html如下:
<option value="{{ widget.value|stringformat:'s' }}" data-content="<i class='fa fa-circle text-{{ widget.value|stringformat:'s' }}'></i> {{ widget.label }}"
{% include "django/forms/widgets/attrs.html" %}>
</option>
通過bootstrap-select庫的幫助用data-content = “標簽(font-awesome圖示庫)”,實作了添加圖示,而圖示樣式則為資料庫中表欄位,
修改一下之前的widgets.pt如下:
from django.forms import RadioSelect, Select
class ColorRadioSelect(RadioSelect):
# template_name = 'django/forms/widgets/radio.html'
# option_template_name = 'django/forms/widgets/radio_option.html'
template_name = 'widgets/color_radio/radio.html'
option_template_name = 'widgets/color_radio/radio_option.html'
class ColorSelect(Select):
option_template_name = 'widgets/color_radio/select.html'
然后在修改project.py如下:
from django import forms
from web.form.bootstarp import BootStrapForm
from web import models
from .widgets import ColorRadioSelect, ColorSelect
class ProjectModelForm(BootStrapForm, forms.ModelForm):
# 排除color資料庫的標簽美化
bootstrap_class_exclude = ['color']
def __init__(self, request, *args, **kwargs):
super().__init__(*args, **kwargs)
# ModelForm可以通過重寫傳request引數
self.request = request
class Meta:
model = models.Project
fields = "__all__"
widgets = {
'desc': forms.Textarea,
# 自定義radio標簽美化
'color': ColorRadioSelect(attrs={'class': 'color-radio'}),
# 自定義select標簽美化
"priority": ColorSelect(attrs={'class': 'selectpicker', "data-live-search": "true"}),
}
最后將我們用到的庫匯入即可,
radio.html如下:
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{% static 'plugin/bootstrap-3.3.7-dist/css/bootstrap.min.css' %} ">
<script src="{% static 'js/jquery-3.5.1.js' %}"></script>
<script src="{% static 'plugin/bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
<script src="{% static 'plugin/bootstrap-select/js/bootstrap-select.min.js' %}"></script>
<link rel="stylesheet" href="{% static 'plugin/font-awesome-4.7.0/css/font-awesome.min.css' %}">
<link rel="stylesheet" href="{% static 'plugin/bootstrap-select/css/bootstrap-select.min.css' %}">
</head>
<style>
.account {
width: 600px;
margin: 0 auto;
}
.color-radio label {
margin-left: 0;
padding-left: 0;
}
.color-radio input[type="radio"] {
display: none;
}
.color-radio input[type="radio"] + .cycle {
display: inline-block;
height: 25px;
width: 25px;
border-radius: 50%;
border: 2px solid #dddddd;
}
.color-radio input[type="radio"]:checked + .cycle {
border: 2px solid black;
}
</style>
<body>
<div class="account">
{% for field in form %}
<div class="form-group">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{{ field }}
<span class="error-msg"></span>
</div>
{% endfor %}
</div>
</body>
</html>
此時訪問路由如下:

三、django離線腳本
概述:通過在django沒有啟動的情況下去執行某些操作,一般多用于爬蟲或其他需要離線呼叫操作,
示例:創建一個init_test.py測驗redis的連接,
import os
import sys
import django
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(base_dir)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "untitled7.settings")
django.setup()
# 注意這里匯入庫必須等django啟動了才行
import redis
# 直接連接redis
conn = redis.Redis(host='127.0.0.1', port=6379, password='密碼', encoding='utf-8')
# 設定鍵值:15131255089="9999" 且超時時間為10秒(值寫入到redis時會自動轉字串)
conn.set('15131255089', 9999, ex=10)
# 根據鍵獲取值:如果存在獲取值(獲取到的是位元組型別);不存在則回傳None
value = conn.get('15131255089')
print(value)
列印
b'9999'
四、pillow生成驗證碼
概述:用于檢查用戶是否為機器人而生成的驗證碼識別,
示例:創建image_code.py結合表單驗證實作用戶登錄驗證碼點擊切換,
Monaco.ttf字體(放到專案的根目錄下)訪問:https://gitee.com/miaojiaxi/s25day01/tree/master/utils
安裝pillow
pip3 install pillow
image_code.py如下:
import random
from PIL import Image, ImageDraw, ImageFont, ImageFilter
def check_code(width=120, height=30, char_length=5, font_file='Monaco.ttf', font_size=28):
code = []
img = Image.new(mode='RGB', size=(width, height), color=(255, 255, 255))
draw = ImageDraw.Draw(img, mode='RGB')
def rndChar():
"""
生成隨機字母
:return:
"""
return chr(random.randint(65, 90))
def rndColor():
"""
生成隨機顏色
:return:
"""
return (random.randint(0, 255), random.randint(10, 255), random.randint(64, 255))
# 寫文字
font = ImageFont.truetype(font_file, font_size)
for i in range(char_length):
char = rndChar()
code.append(char)
h = random.randint(0, 4)
draw.text([i * width / char_length, h], char, font=font, fill=rndColor())
# 寫干擾點
for i in range(40):
draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
# 寫干擾圓圈
for i in range(40):
draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
x = random.randint(0, width)
y = random.randint(0, height)
draw.arc((x, y, x + 4, y + 4), 0, 90, fill=rndColor())
# 畫干擾線
for i in range(5):
x1 = random.randint(0, width)
y1 = random.randint(0, height)
x2 = random.randint(0, width)
y2 = random.randint(0, height)
draw.line((x1, y1, x2, y2), fill=rndColor())
img = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
return img, ''.join(code)
if __name__ == '__main__':
image_object, code = check_code()
print(code)
with open('code.png', 'wb') as f:
image_object.save(f, format='png')
生成驗證碼視圖函式如下:
def image_code(request):
image_object, code = check_code()
# 通過session保存驗證碼進行驗證
request.session['image_code'] = code
# 超時時間
request.session.set_expiry(60)
# 保存在記憶體中
stream = BytesIO()
image_object.save(stream, 'png')
return HttpResponse(stream.getvalue())
用戶登錄(login)視圖函式如下:
class LoginForm(BootStrapForm, forms.ModelForm):
username = forms.CharField(label="用戶名")
password = forms.CharField(label="密碼", widget=forms.PasswordInput())
code = forms.CharField(label="圖片驗證碼")
class Meta:
model = models.UserInfo
fields = ["username", "password", "code"]
def login(request):
form = LoginForm()
return render(request, "login.html", {"form": form})
用戶渲染標簽login.html如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
</head>
<style>
.account {
width: 600px;
margin: 0 auto;
}
</style>
<body>
<div class="account">
<form action="{% url 'login' %}" method="post" novalidate>
{% csrf_token %}
{% for field in form %}
{% if field.name == 'code' %}
<div class="form-group">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
<div style="display: flex;justify-content: space-between">
<div class="col-xs-7">
{{ field }}
</div>
<div class="col-xs-5">
<img src="{% url 'image_code' %}" id="imageCode" title="點擊更換圖片">
</div>
</div>
</div>
{% else %}
<div class="form-group">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{{ field }}
</div>
{% endif %}
{% endfor %}
<div class="form-group">
<input id="btnSubmit" type="submit" class="btn btn-primary" value="登 錄">
</div>
</form>
</div>
</body>
<script>
(() => {
document.getElementById("imageCode").onclick = function () {
// 找到str屬性
var oldSrc = document.getElementById("imageCode")
// 每次執行這個屬性加上一個?(相當于重繪)
oldSrc.src += "?"
}
})()
</script>
</html>
此時訪問路由如下:

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/297121.html
標籤:其他
上一篇:PostMan詳細介紹
下一篇:Charles的使用
