[!tip]
创建 Django 项目
django-admin.exe startproject 项目名称
Pycharm 创建
特殊说明:
- 命令行,创建的项目是标准的。
- pycharm, 在标准的基础上默认给咱们加了点东西。
- 创建了一个 templates 目录(删除)
- settings. py 中(删除)
默认项目文件介绍
mysite
├─manage.py 【项目的管理,启动项目、创建app、数据管理】【不要动】【常常用】
└─mysite
├─init.py
├─settings.py 【项目配置】【常常修改】
├─urls.py 【URL和函数对应关系】【常常修改】
├─asgi.py 【接收网络请求】【不要动】【异步】
└─wsqi.Dy 【接收网络请求】【不要动】【同步】
app
[!tip]
模块化管理
[!note]
创建 app
python manage.py startapp app01
app01
├─init.Py
├─admin.py 【固定,不用动】django默认提供了admin后台管理。
├─apps.py 【固定,不用动】
├─migrations 【固定,不用动】数据库字段变更记录
├─initpy
├─models.py 【重要】对数据库进行操作
├─tests.py 【固定,不用动】单元测试
└─views.py 【重要】函数
快速上手
- 确保 app 注册
-
编写 URL 和视图函数对应关系
-
编写视图函数【views. py】
-
启动 Django
- 命令行启动
python manage.py runserver [端口]
- pycharm 启动
templates 模板
[!warning]
如果在 settings. py 中设置了 DIRS:[os. path. join (BASE_DIR,'templates')],就在项目根目录中优先查找
静态文件
在开发中一般将:
- css
- js
- 图片
都会当作静态文件处理。
全部放在 static 中
模板语法加载文件
模板语法
[!note]
单个传参
name = '张三'
return render(request, 'tpl.html', {'name': name})
<h2>{{ name }}</h2>
[!note]
列表传参
roles = ['管理员', '经理', '总监', 'CEO']
return render(request, 'tpl.html', {'name': name, 'roles': roles})
<h2>{{ roles.0 }}</h2>
<h2>{{ roles.1 }}</h2>
<h2>{{ roles.2 }}</h2>
<h2>{{ roles.3 }}</h2>
[!note]
循环模板
{% for role in roles %}
<h2>{{ role }}</h2>
{% endfor %}
[!note]
字典传参
user_info = {'name': '李四', 'age': 20, 'salary': 10000}
return render(request, 'tpl.html', {user_info': user_info})
<h2>{{ user_info.name }}</h2>
<h2>{{ user_info.age }}</h2>
<h2>{{ user_info.salary }}</h2>
<!-- 获取键值 -->
{% for k, v in user_info.items %}
<h2>{{ k }}: {{ v }}</h2>
{% endfor %}
<!-- 获取键 -->
{% for key in user_info.keys %}
<h2>{{ key }}</h2>
{% endfor %}
<!-- 获取值 -->
{% for value in user_info.values %}
<h2>{{ value }}</h2>
{% endfor %}
[!note]
if 模板
{% if name == '张三' %}
<h2>name是张三</h2>
{% elif name=='小七' %}
<h2>name是小七</h2>
{% else %}
<h2>没人</h2>
{% endif %}
获取请求参数
[!note]
获取 GET 请求参数
request.GET
[!note]
获取 POST 请求参数
request.POST
username = request.POST.get('username')
password = request.POST.get('password')
[!note]
返回响应
from django.shortcuts import render, HttpResponse, redirect
return HttpResponse("返回内容")
return render(request,'something.html')
return redirect('url') #重定向
[!note]
csrf_token 校验
<form action="/login/" method="post">
{% csrf_token %}
<input type="text" name="username" placeholder="用户名">
<input type="password" name="password" placeholder="密码">
<input type="submit" value="登录">
</form>
[!note]
重定向
from django.shortcuts import render, HttpResponse, redirect
return redirect('/info/list/')
[!note]
Json 序列化
from django.http import JsonResponse
return JsonResponse(data_dict)
orm 操作数据库
[!note]
连接数据库
在 settings. py 文件进行配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django_db',
'USER': 'root',
'PASSWORD': '105105',
'HOST': '127.0.0.1',
'PORT': 3306,
}
}
[!note]
创建表【verbose_name 列名注解】
from django.db import models
class UserInfo(models.Model):
username = models.CharField(【verbose_name】,max_length=32)
password = models.CharField(max_length=64)
age = models.IntegerField()
"""
create table app01_userinfo (
id int primary key auto_increment,
username varchar(32),
password varchar(64),
age int
)
"""
执行命令
python manage.py makemigrations
python manage.py migrate
如果再次想要创建表就再次创建函数,不要的表进行注释。完成动作后执行命令。
[!note]
在已有表中添加列
class UserInfo(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=64)
# 新建列
age = models.IntegerField(【default='值'】【null=True,blank=True】)
进行选项:
- 1 为输入值
- 2 为退出
- 也可以在括号内进行 default 设置默认值
- null=True, blank=True 允许为空
[!note]
添加约束
# 外键关联部门表 to_field='id' 指定关联的列 on_delete=models.CASCADE 级联删除 to 指定关联的表 depart列名自动变成depart_id
depart = models.ForeignKey(to='Department',to_field='id',on_delete=models.CASCADE)
[!note]
级联删除
depart = models.ForeignKey(to='Department',to_field='id',on_delete=models.CASCADE)
[!note]
置空
depart = models.ForeignKey(to='Department', to_field='id', null=True, blank=True, on_delete=models.SET_NULL)
[!note]
选择数据
gender_choices = (
(1, '男'),
(2, '女'),
)
gender = models.SmallIntegerField(verbose_name='性别',choices=gender_choices)
[!note]
获取数据排序
models.表.objects.all().order_by('-列') # 降序
[!note]
获取字典
row_dict = models.order.objects.filter(id=uid).values("id","title").first()
[!note]
获取元组
queryset = models.order.objects.all().values_list("id","title")
[!note]
操作表
class Department(models.Model):
title = models.CharField(max_length=16)
# 新建数据 insert into app01_department (title) values ("销售部")
Department.objects.create(title="销售部")
在 views 操作
from app01 import models
def orm(request):
# 新建
models.Department.objects.create(title='销售部')
models.Department.objects.create(title='IT部')
models.Department.objects.create(title='运营部')
models.UserInfo.objects.create(username='张三', password='123', age=20)
# 删除
models.Department.objects.filter(title='销售部').delete()
# 删除全部
models.Department.objects.all(title='销售部').delete()
# 获取数据 queryset类型
data_list = models.Department.objects.all()
for obj in data_list:
print(obj.id, obj.title)
# 获取一行数据,但也是列表
data = models.UserInfo.objects.filter(id=1)
# 直接获取对象
data = models.UserInfo.objects.filter(id=1),first()
# 更新数据,id=1的age更新为18
models.UserInfo.objects.filter(id=1).update(age=18)
# 更新所有数据,age更新为18
models.UserInfo.objects.all().update(age=18)
return HttpResponse('成功')
[!note]
HTML 模板继承【只需要编写占位符所在位置】
{% extends 'layout.html' %}
{% block content %}
内容
{% endblock %}
<div>
<div class="container">
{% block content %}{% endblock %}
</div>
</div>
[!note]
获取数字对应字符
gender_choices = (
(1, '男'),
(2, '女'),
)
obj.get_gender_display() #get_字段名称_display(),在模板语法中没括号
[!note]
关联外键,跨表查询
obj.deaprt.属性
#根据id自动去关联的表中获取哪一行数据depart对象。
[!note]
搜索数据
models.PrettyNum.objects.filter(mobile=txt_mobile,id=2)
# 等同于
data_dict = {"mobile":txt_mobile,"id":2}
models.PrettyNum.objects.filter(**data_dict) # 空字典获取所有
# 数字条件判断
models.PrettyNum.objects.filter(mobile=txt_mobile,id=2) # 等于2
models.PrettyNum.objects.filter(mobile=txt_mobile,id__gt=2) # 大于2
models.PrettyNum.objects.filter(mobile=txt_mobile,id__gte=2) # 大于等于2
models.PrettyNum.objects.filter(mobile=txt_mobile,id__lt=2) # 小于2
models.PrettyNum.objects.filter(mobile=txt_mobile,id__lte=2) # 小于等于2
data_dict = {"id__gte":2}
models.PrettyNum.objects.filter(**data_dict) # 空字典获取所有
# 字符串条件判断
models.PrettyNum.objects.filter(mobile__startwith="1999",id=2) # 以1999开头
models.PrettyNum.objects.filter(mobile__endwith="1999",id=2) # 以1999结尾
models.PrettyNum.objects.filter(mobile__contains="1999",id=2) # 包含1999
data_dict = {"mobile__contains":"1999"}
models.PrettyNum.objects.filter(**data_dict) # 空字典获取所有
[!note]
分页截取
model.PrettyNum.objects.all()[start:end]
[!note]
后端文本转化 html
from django.utils.safestring import mark_safe
page_str_list = []
for i in range(1,21):
ele = '<li><a href="?page={}">{}</a></li>'.format(i,i)
page_str_list.append(ele)
page_string = mark_safe("".join(page_str_list))
组件
Form 组件
- view. py
class MyForm(Form): user = forms.CharField(widget=forms.Input) pwd = form.CharFiled(widget=forms.Input) email = form.CharFiled(widget=forms.Input) def user_add(request): """新建用户""" if request.method == "GET":
# 获取所有部门列表供选择
return render(request, "user_add.html", {"from":from})
```
2. user_add. html
<pre data-language=HTML><code class="language-markup line-numbers"><from method="post">
{% for field in form %}
{ field }
{% endfor %}
<from>
```
```html
<from method="post">
{{ from.user }}
{{ from.pwd }}
{{ from.email }}
<from>
```
### ModelForm 组件
1. models. py
```python
class UserInfo(models.Model):
"""员工表"""
name = models.CharField(verbose_name='姓名', max_length=16)
password = models.CharField(verbose_name='密码', max_length=64)
age = models.IntegerField(verbose_name='年龄')
account = models.DecimalField(verbose_name='账户余额', max_digits=10, decimal_places=2, default=0)
create_time = models.DateTimeField(verbose_name='入职时间')
# 外键关联部门表 to_field='id' 指定关联的列 on_delete=models.CASCADE 级联删除 to 指定关联的表 depart列名自动变成depart_id
depart = models.ForeignKey(to='Department', to_field='id', on_delete=models.CASCADE)
gender_choices = (
(1, '男'),
(2, '女'),
)
gender = models.SmallIntegerField(verbose_name='性别', choices=gender_choices)
</code></pre>
<ol start="2">
<li>view. py
<pre><code class="language-python line-numbers">from django import forms
class MyForm(forms.ModelForm):
class Meta:
model = UserInfo
fields = ["name", "password", "age"]
# fields = "__all__" 所有字段
# exclude ['level'] 排除某字段,其他都带
widgets = {
# 定义生成插件类名
"name": forms.TextInput(attrs={"class":"form-control"}),
"password": forms.TextInput(attrs={"class":"form-control"}),
}
################## 高级加类名 ########################
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 循环找到所有插件class添加form-control
for name, field in self.field.items():
# 跳过指定字段
#if name=="password":
# continue
field.widget.attrs = {"class":"form-control","placeholder":"field.label"}
def user_add(request):
"""新建用户"""
if request.method == "GET":
</code></pre></li>
</ol>
# 获取所有部门列表供选择
return render(request, "user_add.html", {"from":from})
```
3. user_add. html
<from method="post">
{% for field in form %}
{ field.lable } { field }
{% endfor %}
<from>
```
```html
<from method="post">
{{form.user.Label}} {{ from.user }} #关联model中字段
{{form.password.Label}} {{ from.pwd }}
{{form.email.Label}} {{ from.email }}
<from>
```
魔法方法定制返回内容

获取 POST 请求表单
```python
form = UserModelForm(data=request.POST)
if form.is_valid():
print(form.cleaned_data) # 输出表单数据
form.save() # 表单存储到表
else:
print(form.errors)
{{field.errors.0}} # 错误信息
设置中文错误提示
显示默认值
form = UserModelForm(instance=row_object)
修改数据
row_object = models.UserInfo.objects.filter(id=nid).first()
form = UserModelForm(data=request.POST, instance=row_object)
if form.is_valid():
# 默认保存的是用户输入的所有数据,如果想要再用户输入以外增加一点值
# form.instance.字段名 = 值
form.save()
表单数据不可修改
mobile = forms.CharField(
label='手机号',
disabled=True
)
去除浏览器表单自带验证
<form novalidate>
<!-- 表单内容 -->
</form>
浏览器自动填充
<label for="email">Email:</label>
<input name="email" id="email" type="email" autocomplete="off" />
<label for="firstName">First Name:</label>
<input name="firstName" id="firstName" type="text" autocomplete="on" />
利用正则判断
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
# 方式一
class PrettyModelForm(forms.ModelForm):
# 定义字段验证规则
mobile = forms.CharField(
label='手机号',
validators=[], # 自定义验证器列表
widget=forms.TextInput(attrs={
'class': 'form-input',
'placeholder': '请输入11位手机号',
'validators': [RegexValidator(r'^1[3-9]\d{9}$', '手机号格式不正确')]
})
)
# 方式二
def clean_mobile(self):
txt_mobile = self.cleaned_data["mobile"] # 获取用户传入值
if len(txt_mobile) != 11:
raise ValidationError("格式错误")
return txt_mobile
判断值是否重复
# 添加页面
def clean_mobile(self):
txt_mobile = self.cleaned_data["mobile"] # 获取用户传入值
model.PrettyNum.objects.filter(mobile=text_mobile).exists() # 判断是否存在
if exists:
raise ValidationError("手机号已存在")
return txt_mobile
# 编辑页面
def clean_mobile(self):
txt_mobile = self.cleaned_data["mobile"] # 获取用户传入值
# 排除id=2,手机号是否重复
model.PrettyNum.objects.filter(mobile=text_mobile).exclude(id=2)
获取当前 id
def clean_mobile(self):
print(self.instance.pk)
获取验证过的所有值
if form.is_valid():
print(form.cleaned_data)
##########################################
# 验证密码
from django.core.exceptions import ValidationError
def clean_confirm_password(self):
pwd = self.cleaned_data.get("password")
confirm = self.cleaned_data.get("confirm_password")
if confirm != pwd:
raise ValidationError("密码不一致")
return confirm
报错保留值
widgets = {
"password":forms.PasswordInput(render_value=True)
}
分页类
class Pagination:
def __init__(self, request, queryset, page_size=10, page_param="page", plus=2):
"""
初始化分页类
:param request: 请求对象
:param queryset: 查询集合
:param page_size: 每页显示数量
:param page_param: URL中传递的分页参数,例如 ?page=1 中的 page
:param plus: 显示当前页码前后的页码个数
"""
# 获取页码参数
page = request.GET.get(page_param, "1")
if page.isdecimal():
page = int(page)
else:
page = 1
self.page = page
self.page_size = page_size
# 计算起始位置
self.start = (page - 1) * page_size
self.end = page * page_size
# 切片查询
self.page_queryset = queryset[self.start:self.end]
# 计算总页数
total_count = queryset.count()
total_page_count, div = divmod(total_count, page_size)
if div:
total_page_count += 1
self.total_page_count = total_page_count
self.plus = plus
# 保存request对象,用于构建URL
self.request = request
def html(self):
"""生成分页HTML"""
# 基础样式定义
base_style = "display:inline-flex; align-items:center; justify-content:center; min-width:32px; height:32px; padding:0 12px; margin:0 2px; font-size:13px; border-radius:4px; cursor:pointer; text-decoration:none; transition:all 0.3s;"
normal_style = f"{base_style} background:#f4f4f5; color:#606266; border:none;"
active_style = f"{base_style} background:#409eff; color:white; font-weight:500; border:none;"
disabled_style = f"{base_style} background:#f4f4f5; color:#c0c4cc; cursor:not-allowed; border:none;"
# 计算页码范围
if self.total_page_count <= 2 * self.plus + 1:
start_page = 1
end_page = self.total_page_count
else:
if self.page <= self.plus:
start_page = 1
end_page = 2 * self.plus + 1
else:
if (self.page + self.plus) > self.total_page_count:
start_page = self.total_page_count - 2 * self.plus
end_page = self.total_page_count
else:
start_page = self.page - self.plus
end_page = self.page + self.plus
def build_url(page_num):
params = self.request.GET.copy()
params['page'] = page_num
return '?' + params.urlencode()
page_str_list = []
# 容器样式
container_style = "display:flex; align-items:center; justify-content:center; margin:20px 0; padding:8px 0;"
page_str_list.append(f'<div style="{container_style}">')
# 首页
page_str_list.append(
f'<a href="{build_url(1)}" style="{normal_style}">首页</a>'
)
# 上一页
if self.page > 1:
page_str_list.append(
f'<a href="{build_url(self.page - 1)}" style="{normal_style}">上一页</a>'
)
else:
page_str_list.append(
f'<span style="{disabled_style}">上一页</span>'
)
# 页码
for i in range(start_page, end_page + 1):
if i == self.page:
page_str_list.append(
f'<span style="{active_style}">{i}</span>'
)
else:
page_str_list.append(
f'<a href="{build_url(i)}" style="{normal_style}">{i}</a>'
)
# 下一页
if self.page < self.total_page_count:
page_str_list.append(
f'<a href="{build_url(self.page + 1)}" style="{normal_style}">下一页</a>'
)
else:
page_str_list.append(
f'<span style="{disabled_style}">下一页</span>'
)
# 尾页
page_str_list.append(
f'<a href="{build_url(self.total_page_count)}" style="{normal_style}">尾页</a>'
)
page_str_list.append('</div>')
return ''.join(page_str_list)
拼接 url 参数
def build_url(page_num):
# 复制当前请求的GET参数
params = self.request.GET.copy()
# 设置或更新page参数
params['page'] = page_num
# 将参数转换为URL查询字符串,例如:'q=123&page=2'
return '?' + params.urlencode()
#################################################################
import copy
query_dict = copy.deepcopy(request.GET)
query_dict._mutable = True
query_dict.setlist('page',[11])
print(query_dict.urlencode())
加密
md 5
import hashlib
def md5(data_string):
obj = hashlib.md5(settings.SECRET_KEY.encode('utf-8')) # 加盐
obj.update(data_string.encode('utf-8'))
return obj.hexdigest()
Cookie 和 Session
[!tip]
网站生成随机字符串;写到用户浏览器的 cookie 中;在写入到 session 中
request.session["info"]="value"
[!note]
信息存放在 django_session 数据库
内部自动加密
[!note]
判断是否登录
info = request.session.get("info")
if not info:
return redirect('/login/')
[!note]
注销账号
def logout(request):
request.session.clear()
return redirect('/login/')
[!note]
模板获取 session 信息
{ request.session.info.id }
{ request.session.info.name }
[!note]
保存验证码验证
# 调用oillow函数,生成图片
img,code_string = check_code()
# 写入到自己的session中(以便于后续获取验证码再进行校验)
request.session['image_code'] = code_string
# 给Session设置60s超时
request.session.set_expiry(60)
中间件
[!tip]
应用中间件
[!note]
中间件统一判断是否登录
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse, redirect
class AuthMiddleware(MiddlewareMixin):
def process_request(self, request):
# 排除不需要登录的页面
if request.path_info == "/login/":
return None
info = request.session.get("info")
if not info:
# 如果方法中没有返回值(返回None),继续向后走
return redirect('/login/')
def process_response(self, request, response):
print("中间件响应")
return response
图片验证码
[!note]
生成图片
from PIL import Image
img = Image.new(name='RGB', size=(120,30), color=(255,255,255))
# 保存本地
with open('code.png','wb') as f:
img.save(f,format='png')
[!note]
创建画笔绘画
from PIL import Image, ImageDraw, ImageFont
# 创建画布
img = Image.new('RGB', (120,30), color=(255,255,255))
# 创建画笔
draw = ImageDraw.Draw(img)
# 画线
draw.line((0,0, 120,30), fill=(255,0,0), width=2)
# 画点
draw.point((50,50), fill=(0,0,255))
# 画矩形
draw.rectangle((10,10, 110,20), outline=(0,255,0))
# 写文字
font = ImageFont.truetype('arial.ttf', size=16)
draw.text((10,10), "验证码", font=font, fill=(0,0,0))
# 保存图片
img.save('code.png')
[!note]
图片处理操作
from PIL import Image
# 打开图片
img = Image.open('code.png')
# 调整大小
img = img.resize((200, 100))
# 旋转图片
img = img.rotate(45)
# 裁剪图片
img = img.crop((0, 0, 100, 100)) # (left, top, right, bottom)
# 图片格式转换
img = img.convert('L') # 转为灰度图
# 保存修改后的图片
img.save('new_code.png')
[!note]
验证码干扰
from PIL import Image, ImageDraw
import random
def create_lines(draw, width, height):
"""绘制干扰线"""
for i in range(5): # 画5条干扰线
begin = (random.randint(0, width), random.randint(0, height))
end = (random.randint(0, width), random.randint(0, height))
draw.line([begin, end], fill=(0,0,0), width=2)
def create_points(draw, width, height, point_chance=5):
"""绘制干扰点"""
# point_chance: 噪点比例
chance = min(100, max(0, point_chance))
for w in range(width):
for h in range(height):
if random.randint(0, 100) < chance:
draw.point((w, h), fill=(0,0,0))
def distort_image(image):
"""图片扭曲变形"""
width, height = image.size
new_image = Image.new('RGB', (width, height), (255,255,255))
# 横向扭曲
for i in range(width):
for j in range(height):
offset_x = int(random.uniform(0, 4))
offset_y = int(random.uniform(0, 2))
# 确保偏移后的坐标不越界
new_x = i + offset_x if i + offset_x < width else width - 1
new_y = j + offset_y if j + offset_y < height else height - 1
pixel = image.getpixel((i,j))
new_image.putpixel((new_x,new_y), pixel)
return new_image
[!note]
完整验证码示例
from PIL import Image, ImageDraw, ImageFont
import random
import string
def generate_verify_code():
# 创建画布
width = 120
height = 40
image = Image.new('RGB', (width, height), (255,255,255))
draw = ImageDraw.Draw(image)
# 生成随机字符
chars = ''.join(random.choices(string.ascii_uppercase + string.digits, k=4))
# 添加文字
font = ImageFont.truetype('arial.ttf', size=30)
for i, char in enumerate(chars):
x = 20 + i * 25
y = random.randint(2, 8)
# 每个字符颜色随机
color = (random.randint(0,150), random.randint(0,150), random.randint(0,150))
draw.text((x, y), char, font=font, fill=color)
# 添加干扰线
create_lines(draw, width, height)
# 添加噪点
create_points(draw, width, height)
# 图片扭曲
image = distort_image(image)
return image, chars
# 生成验证码
image, code = generate_verify_code()
image.save('verify_code.png')
print(f"验证码内容: {code}")
[!note]
服务器内存验证
from io import BytesIo
import random
def check_code(width=120, height=30, char_length=5, font_file='kumo.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)
def image_code(request):
"""生成图片验证码"""
#调用pillow函数,生成图片
img,code_string = check_code()
print(code_string)
stream = BytesIo()
img.save(stream,'png')
return HttpResponse(stream.getvalue())
Ajax
- 通过 jQuery 发送 Ajax
-
编写 Ajax
$.ajax({ url:"发送的地址", typr:"get|post" data:{ n1:123, n2:456 }, success:function(res){ console.log(res); } })
[!note]
发送 post 免除 csrf
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def task_ajax(request):
print(request.POST)
return HttpResponse("成功了")
[!note]
反序列化 json
$.ajax({
url:"发送的地址",
typr:"get|post"
data:{
n1:123,
n2:456
},
dataType:"JSON",
success:function(res){
console.log(res.status);
console.log(res.data);
}
})
[!note]
自动获取表单数据并打包
$.ajax({
url:"发送的地址",
typr:"get|post"
data:$("#form3").serialize(), //自动获取打包
dataType:"JSON",
success:function(res){
console.log(res.status);
console.log(res.data);
}
})
[!note]
js 实现刷新页面
location.reload();
[!note]
显示模态框
$("#btnAdd").click(function ()
$('#myModal').modal('show')
});
[!note]
关闭模态框
$("#btnAdd").click(function ()
$('#myModal').modal('hide')
});
[!note]
循环错误信息
$.each(res.error,function (name,errorlist){
$("#id_"+name).next() //错误信息栏在下一个标签
})
[!note]
清空表单
// 清空表单 $("#formAdd")是jQuery对象->$("#formAdd")[0]DOM对象
$("#formAdd")[0].reset()
[!note]
获取当前行 id
/获取当前行的ID并赋值给全部变量」
DELETE_ID = $(this).attr("uid");
图表
- highchart
- echarts
[!note]
cdn 引入
<script src="https://cdn.jsdelivr.net/npm/echarts@5.5.1/dist/echarts.min.js"></script>
[!tip]
分类
pie : 饼图
bar : 柱形图
[!note]
绘制柱形图
<body>
<!-- 为 ECharts 准备一个定义了宽高的 DOM -->
<div id="main" style="width: 600px;height:400px;"></div>
<script type="text/javascript">
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main')); //指定dom
// 指定图表的配置项和数据
var option = {
title: {
text: 'ECharts 入门示例'
},
tooltip: {},
legend: {
data: ['销量','业绩']
},
xAxis: {
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
},
yAxis: {},
series: [
{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
},
{
name: '业绩',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}
]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
</script>
</body>
[!note]
绘制饼图
option = {
series: [
{
type: 'pie',
data: [
{
value: 335,
name: '直接访问'
},
{
value: 234,
name: '联盟广告'
},
{
value: 1548,
name: '搜索引擎'
}
]
}
]
};
[!note]
绘制折线图
option = {
xAxis: {
type: 'category',
data: ['A', 'B', 'C']
},
yAxis: {
type: 'value'
},
series: [
{
data: [120, 200, 150],
type: 'line'
}
]
};
文件上传
[!note]
获取发过来的文件
<form method="post"enctype="multipart/form-data">
{% csrf_token %}
<input type="text"name="username">
<input type="file"name="avatar">
<input type="submit"value="提交")
</form>
def upload_list(request):
if request.method =="GET":
return render(request,'upload_list.html')
# print(request.POST) #请求体中数据
# print(request.FILES) #请求发过来的文件
file_object request.FILES.get("avatar")
print(file_object.name) # 获取文件名
# 读取文件
f open('a1.png',mode='wb')
for chunk in file_object.chunks():
f.write(chunk)
f.close()
[!note]
获取传参
def upload_form(request):
title="Form上传"
if request.method =="GET":
form = UpForm()
return render(request,'upload_form.html',{"form":form,"title":title})
form = UpForm(data=request.POST,files=request.FILES)
[!note]
启用 media 目录【在 urls. py 中配置】
from django.urls import path,re_path
from django.views.static import serve
from django.conf import settings
re_path(r'media/(?P<path>.*)$',serve,{'document_root'settings.MEDIA_ROOT},name='media'),
# settings.py
impoct os
MEDIA_ROOT = os.path.join(BASE_DR,"media")
MEDIA_URL = "/media/"
# upload.py
media_path os.path.join(settings.MEDIA_ROOT,image_object.name) # 绝对路径
media_path os.path.join ("media", image_object. name) # 相对路径
[!note]
modelForm 写法
# 上传到 media/city/
img = models.FileField (verbose_name="Logo", max_length=128, upload_to='city/')
Comments NOTHING