day19 Django开发
知识点的回顾:
- 安装Django
pip install django
- 创建Django项目
>>> django-admin startproject mysite
注意:Pycharm可以创建。如果用Pycharm创建,记得settings.py中的DIR templates 删除。
- 创建app & 注册
>>>python manage.py startapp app01
>>>python manage.py startapp app02
>>>python manage.py startapp app03
INSTALLED_APPS = [
……
'app01.apps.App01Config'
]
注意:否则app下的models.py写类时,无法在数据库中创建表。
- 配置 静态文件路径 & 模板的路径(放在app目录下)。
- 配置数据库相关操作(MySQL)
- 第三方模块(django3版本)
pip install mysqlclient
- 自己先去MySQL创建一个数据库。
- 配置数据库连接settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'gx_day16', # 数据库名字
'USER': 'root',
'PASSWORD': 'root123',
'HOST': '127.0.0.1', # 那台机器安装了MySQL
'PORT': 3306,
}
}
- 在app下的models.py中编写
from django.db import models
class Admin(models.Model):
""" 管理员 """
username = models.CharField(verbose_name="用户名", max_length=32)
password = models.CharField(verbose_name="密码", max_length=64)
def __str__(self):
return self.username
class Department(models.Model):
""" 部门表 """
title = models.CharField(verbose_name='标题', max_length=32)
def __str__(self):
return self.title
- 执行两个命令:将models.py中的表在数据库中进行创建
>>>python manange.py makemigrations
>>>python manange.py migrate
- 在 urls.py ,路由 ( URL 和 函数的对应关系)。
- 在views.py,视图函数,编写业务逻辑。
- templates目录,编写HTML模板(含有模板语法、继承、
{% static 'xx'%}
) - ModelForm & Form组件,在我们开发增删改查功能。
- 生成HTML标签(生成默认值)
- 请求数据进行校验。 - clean_data, 手机号,非空等
- 保存到数据库(ModelForm)
- 获取错误信息。
- Cookie和Session,用户登录信息保存起来。
- 中间件,基于中间件实现用户认证 ,基于:
process_request
。 – 页面都需要先登录的认证校验 - ORM操作
models.User.objects.filter(id="xxx")
models.User.objects.filter(id="xxx").order_by("-id")
- 分页组件。
1.Ajax请求
2.订单
class Order(models.Model):
""" 订单 """
oid = models.CharField(verbose_name="订单号", max_length=64)
title = models.CharField(verbose_name="名称", max_length=32)
price = models.IntegerField(verbose_name="价格")
status_choices = (
(1, "待支付"),
(2, "已支付"),
)
status = models.SmallIntegerField(verbose_name="状态", choices=status_choices, default=1)
admin = models.ForeignKey(verbose_name="管理员", to="Admin", on_delete=models.CASCADE)
想要去数据库中获取数据时:对象/字典
# 对象,当前行的所有数据。
row_object = models.Order.objects.filter(id=uid).first()
row_object.id
row_object.title
# 字典,{"id":1,"title":"xx"}
row_dict = models.Order.objects.filter(id=uid).values("id","title").first() # 从数据库中获取数据,1-对象;2-字段(values)
# queryset = [obj,obj,obj,]
queryset = models.Order.objects.all() # 对象
# queryset = [ {'id':1,'title':"xx"},{'id':2,'title':"xx"}, ]
queryset = models.Order.objects.all().values("id","title") # values: 字段对象
# queryset = [ (1,"xx"),(2,"xxx"), ]
queryset = models.Order.objects.all().values_list("id","title") # values_list直接元素的元组
三种方式: 对象、字典、元组
小结
至此,基于Ajax + 对话框的形式实现的页面的增删改查。
- 表单,实现增删改查。
- Ajax,实现增删改查。
3.图表
- highchart,国外工具。
- echarts,国内百度开源工具。
更多参考文档:https://echarts.apache.org/handbook/zh/get-started
echarts模块
highchart模块
4.文件基本操作
4.1 基本操作
<form method="post" enctype="multipart/form-data">
<!-- enctype="multipart/form-data" 实现上传真正的图片,如果不添加的话,就只上传的文件名-->
{% csrf_token %}
<input type="text" name="username">
<input type="file" name="avatar">
<input type="submit" value="提交">
</form>
from django.shortcuts import render, HttpResponse
def upload_list(request):
if request.method == "GET":
return render(request, 'upload_list.html')
# # 'username': ['big666']
# print(request.POST) # 请求体中数据
# # {'avatar': [<InMemoryUploadedFile: 图片 1.png (image/png)>]}> 这是一个文件对象
# print(request.FILES) # 请求发过来的文件 {}
file_object = request.FILES.get("avatar")
# print(file_object.name) # 上传的文件名:WX20211117-222041@2x.png,文件是一个对象
f = open(file_object.name, mode='wb')
for chunk in file_object.chunks(): # 数据是一块一块的
f.write(chunk)
f.close()
return HttpResponse("...")
4.2 案例:批量上传数据
目标: 在部门管理模块,增加一个面板,支持用户上传文件,并进行下游消费使用。
def depart_multi(request):
""" 批量删除(Excel文件)"""
from openpyxl import load_workbook
# 1.获取用户上传的文件对象
file_object = request.FILES.get("exc")
# 2.对象传递给openpyxl,由openpyxl读取文件的内容
wb = load_workbook(file_object)
sheet = wb.worksheets[0]
# 3.循环获取每一行数据
for row in sheet.iter_rows(min_row=2):
text = row[0].value
exists = models.Department.objects.filter(title=text).exists()
if not exists:
models.Department.objects.create(title=text)
return redirect('/depart/list/')
{% extends 'layout.html' %}
{% block content %}
<div class="container">
<div class="panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading">
<span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>
批量上传
</div>
<div class="panel-body">
<form method="post" enctype="multipart/form-data" action="/depart/multi/">
{% csrf_token %}
<div class="form-group">
<input type="file" name="exc">
</div>
<input type="submit" value="上传" class="btn btn-info btn-sm">
</form>
</div>
</div>
<div style="margin-bottom: 10px">
<a class="btn btn-success" href="/depart/add/">
<span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span>
新建部门
</a>
</div>
<div class="panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading">
<span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>
部门列表
</div>
<!-- Table -->
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>名称</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for obj in queryset %}
<tr>
<th>{{ obj.id }}</th>
<td>{{ obj.title }}</td>
<td>
<a class="btn btn-primary btn-xs" href="/depart/{{ obj.id }}/edit/">编辑</a>
<a class="btn btn-danger btn-xs" href="/depart/delete/?nid={{ obj.id }}">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}
4.3 案例:混合数据
提交页面时: 用户输入数据+文件(输入不能为空,报错)
- form生成html标签: type = file
- 表单的验证
- form.cleaned_data 获取数据 + 文件对象
import os
from django.conf import settings
from django.shortcuts import render, HttpResponse
from app01 import models
def upload_list(request):
if request.method == "GET":
return render(request, 'upload_list.html')
# # 'username': ['big666']
# print(request.POST) # 请求体中数据
# # {'avatar': [<InMemoryUploadedFile: 图片 1.png (image/png)>]}> 这是一个文件对象
# print(request.FILES) # 请求发过来的文件 {}
file_object = request.FILES.get("avatar")
# print(file_object.name) # 上传的文件名:WX20211117-222041@2x.png,文件是一个对象
f = open(file_object.name, mode='wb')
for chunk in file_object.chunks(): # 数据是
f.write(chunk)
f.close()
return HttpResponse("...")
from django import forms
from app01.utils.bootstrap import BootStrapForm, BootStrapModelForm
class UpForm(BootStrapForm):
bootstrap_exclude_fields = ['img']
name = forms.CharField(label="姓名")
age = forms.IntegerField(label="年龄")
img = forms.FileField(label="头像")
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)
if form.is_valid():
# {'name': '武沛齐', 'age': 123, 'img': <InMemoryUploadedFile: 图片 1.png (image/png)>}
# 1.读取图片内容,写入到文件夹中并获取文件的路径。
image_object = form.cleaned_data.get("img")
# media_path = os.path.join(settings.MEDIA_ROOT, image_object.name)
media_path = os.path.join("media", image_object.name)
f = open(media_path, mode='wb')
for chunk in image_object.chunks():
f.write(chunk)
f.close()
# 2.将图片文件路径写入到数据库
models.Boss.objects.create(
name=form.cleaned_data['name'],
age=form.cleaned_data['age'],
img=media_path,
)
return HttpResponse("...")
return render(request, 'upload_form.html', {"form": form, "title": title})
from django import forms
from app01.utils.bootstrap import BootStrapModelForm
class UpModelForm(BootStrapModelForm):
bootstrap_exclude_fields = ['img']
class Meta:
model = models.City
fields = "__all__"
def upload_modal_form(request):
""" 上传文件和数据(modelForm)"""
title = "ModelForm上传文件"
if request.method == "GET":
form = UpModelForm()
return render(request, 'upload_form.html', {"form": form, 'title': title})
form = UpModelForm(data=request.POST, files=request.FILES)
if form.is_valid():
# 对于文件:自动保存;
# 字段 + 上传路径写入到数据库
form.save()
return HttpResponse("成功")
return render(request, 'upload_form.html', {"form": form, 'title': title})
{% extends 'layout.html' %}
{% block content %}
<div class="container">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"> {{ title }} </h3>
</div>
<div class="panel-body">
<form method="post" enctype="multipart/form-data" novalidate >
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label>{{ field.label }}</label>
{{ field }}
<span style="color: red;">{{ field.errors.0 }}</span>
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">提 交</button>
</form>
</div>
</div>
</div>
{% endblock %}
注意: 就目前而言,目前的静态文件都只能放在static目录下;类似用户上传的这种动态文件放在media目录下。
在django开发过程中,有两个特殊的文件夹:
- static: 存放静态文件的路径,包括: css/js/项目图片
- media: 用户上传数据的目录
4.4 启用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中进行配置
import os
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
MEDIA_URL = "/media/"
- 第三步: 直接在浏览器上进行访问
修改之后的py代码
import os
from django.conf import settings
from django.shortcuts import render, HttpResponse
from app01 import models
def upload_list(request):
if request.method == "GET":
return render(request, 'upload_list.html')
# # 'username': ['big666']
# print(request.POST) # 请求体中数据
# # {'avatar': [<InMemoryUploadedFile: 图片 1.png (image/png)>]}> 这是一个文件对象
# print(request.FILES) # 请求发过来的文件 {}
file_object = request.FILES.get("avatar")
# print(file_object.name) # 上传的文件名:WX20211117-222041@2x.png,文件是一个对象
f = open(file_object.name, mode='wb')
for chunk in file_object.chunks(): # 数据是
f.write(chunk)
f.close()
return HttpResponse("...")
from django import forms
from app01.utils.bootstrap import BootStrapForm, BootStrapModelForm
class UpForm(BootStrapForm):
bootstrap_exclude_fields = ['img']
name = forms.CharField(label="姓名")
age = forms.IntegerField(label="年龄")
img = forms.FileField(label="头像")
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)
if form.is_valid():
# {'name': '武沛齐', 'age': 123, 'img': <InMemoryUploadedFile: 图片 1.png (image/png)>}
# 1.读取图片内容,写入到文件夹中并获取文件的路径。
image_object = form.cleaned_data.get("img")
# media_path = os.path.join(settings.MEDIA_ROOT, image_object.name) # 绝对路径
media_path = os.path.join("media", image_object.name) # 相对路径
f = open(media_path, mode='wb')
for chunk in image_object.chunks():
f.write(chunk)
f.close()
# 2.将图片文件路径写入到数据库
models.Boss.objects.create(
name=form.cleaned_data['name'],
age=form.cleaned_data['age'],
img=media_path,
)
return HttpResponse("...")
return render(request, 'upload_form.html', {"form": form, "title": title})
4.5 用modalform实现混合数据新增
- models.py中新增函数
class City(models.Model):
""" 城市 """
name = models.CharField(verbose_name="名称", max_length=32)
count = models.IntegerField(verbose_name="人口")
# 本质上数据库也是CharField,自动保存数据。
img = models.FileField(verbose_name="Logo", max_length=128, upload_to='city/')
- 定义modalform
from django import forms
from app01.utils.bootstrap import BootStrapModelForm
class UpModelForm(BootStrapModelForm):
bootstrap_exclude_fields = ['img']
class Meta:
model = models.City
fields = "__all__"
def upload_modal_form(request):
""" 上传文件和数据(modelForm)"""
title = "ModelForm上传文件"
if request.method == "GET":
form = UpModelForm()
return render(request, 'upload_form.html', {"form": form, 'title': title})
form = UpModelForm(data=request.POST, files=request.FILES) # 文件上传。
if form.is_valid():
# 对于文件:自动保存;
# 字段 + 上传路径写入到数据库
form.save()
return HttpResponse("成功")
return render(request, 'upload_form.html', {"form": form, 'title': title})
小结
- 第一种方式:上传文件,自己手动写
- 第二种方式: form组件,具体文件还是得自己手动写
- 第三种方式: moelform(表单验证 + 自动保存数据库 + 自动保存文件)
– media文件夹
– models.py文件要素
img = models.FileField(verbose_name=“Logo”, max_length=128, upload_to=‘city/’)