1.查看效果图
2.创建表,在models.py中进行操作
建好表之后使用python manage.py makemigrations,python manage.py migrate进行数据库迁移
3.登录及注册的实现,效果图及完整代码如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
{% load static %}
<link rel="stylesheet" href='{% static "bootstrap/css/bootstrap.min.css" %}'>
<link rel="stylesheet" type="text/css" href='{% static "admin/css/login2.css" %}'>
<title>环保公司</title>
<style>
.centered {
position: absolute; /* 使用绝对定位 */
top: 50%; /* 使元素上边缘距离页面顶部的距离为屏幕高度的一半 */
left: 46%; /* 使元素左边缘距离页面左边的距离为屏幕宽度的一半 */
transform: translate(-50%, -50%); /* 通过transform属性使元素的中心点与页面的中心点对齐 */
text-align: center; /* 设置文本居中 */
}
</style>
</head>
<body style="background: linear-gradient(to right, #d3aff5, #8fd38f);">
<h1 class="centered">后台管理系统</h1>
<div class="content">
<div class="login">
<span class="title">
登录
</span>
<form class="form-horizontal" action="{% url 'user:login' %}" method="POST">
{% csrf_token %}
<div class="form-group">
<div class="col-sm-12">
<input class="form-control" id="username" name="username" placeholder="用户名">
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<input class="form-control" id="password" name="password" type="password" placeholder="密码">
</div>
</div>
{% if messages %}
{% for message in messages %}
<div style="color:red;padding-left:15px">{{ message }}</div>
{% endfor %}
{% endif %}
<button type="submit" style="width: 100%; background-color: #64af5f; margin-top: 15px; color: #ffffff"
class="btn btn-default">登录
</button>
<a style="width: 100%; background-color: #64af5f; margin-top: 15px; color: #ffffff"
class="btn btn-default" href="{% url 'user:register' %}">注册
</a>
</form>
</div>
</div>
<footer style="width: 100%; position: absolute; bottom: 0; font-size: 12px; display: flex; justify-content: center">
Copyright©️2016-2021 环保公司 All Rights Reserved. | 蜀ICP备2020029736号
</footer>
</body>
</html>
4.实现某一页面(案例页面)的增删改查的前后端完整代码
import datetime
import json
from django.core.paginator import Paginator
from django.shortcuts import render
from django.views.decorators.http import require_GET
from django.db.models import Q
from envapp.models import Case
from django.http import JsonResponse
from django.views.decorators.http import require_POST
from django.views.decorators.http import require_http_methods
from django.shortcuts import get_object_or_404
@require_GET
def index_case(request):
page = request.GET.get("page", 1)
limit = request.GET.get("limit", 10) # 获取每页条数
key = request.GET.get("key")
page_obj = Case.objects.all().order_by("-id")
if key:
page_obj = page_obj.filter(Q(content__contains=key))
paginator = Paginator(page_obj, limit)
if page:
page_obj = paginator.get_page(page)
# 将日期时间字段转换为指定格式
for item in page_obj.object_list:
item.time = item.time.strftime('%Y-%m-%d')
data = {
'code': 0,
'msg': '信息查询成功',
'count': paginator.count,
'data': list(page_obj.object_list.values()) # 获取当前页对象列表,并转换为字典列表
}
response = JsonResponse(data)
response['Access-Control-Allow-Origin'] = '*' # 允许所有域名进行跨域访问
response['Content-Security-Policy'] = "frame-ancestors https://m.wo.cn" # 添加 Content-Security-Policy 头部
return response
def case(request):
return render(request, 'case/case_index.html')
def case_add(request):
return render(request, 'case/case_add.html')
@require_POST
def case_post(request):
try:
js = request.body.decode('utf8')
data = json.loads(js)
# 将日期字符串转换为 datetime 对象
data['time'] = datetime.datetime.strptime(data['time'], '%Y-%m-%d')
# 创建 Case 对象并保存
new = Case(**data)
new.save()
return JsonResponse({
'code': 0,
'msg': '新增数据成功'
})
except Exception as e:
return JsonResponse({
'code': -1,
'msg': '新增数据失败: {}'.format(str(e))
})
@require_http_methods(["PUT"])
def case_update(request, sid):
if request.method == 'PUT':
data = json.loads(request.body)
data['time'] = datetime.datetime.strptime(data['time'], '%Y-%m-%d')
new = get_object_or_404(Case, id=sid)
try:
# 使用点操作符为对象的属性赋值
new.title = data['title']
new.content = data['content']
new.time = data['time']
new.category = data['category']
new.image_link = data['image_link']
# 保存对象更改
new.save()
return JsonResponse({
'code': 0,
'msg': '修改数据成功'
})
except Exception as e:
return JsonResponse({
'code': -1,
'msg': '修改数据失败: {}'.format(str(e))
})
@require_http_methods(["DELETE"])
def case_del(request, sid):
new = get_object_or_404(Case, id=sid)
try:
new.delete()
return JsonResponse({
'code': 0,
'msg': '删除数据成功'
})
except Exception as e:
return JsonResponse({
'code': -1,
'msg': '删除数据失败: {}'.format(str(e))
})
案例页面的首页(前端代码)
{% extends 'layout.html' %}
{% block content %}
<script type="text/html" id="toolbar">
<div class="layui-btn-container">
<button class="layui-btn layui-btn-sm" lay-event="add">添加</button>
<button class="layui-btn layui-btn-sm" lay-event="delete_many">删除</button>
</div>
</script>
<!-- 表头某列 templet 属性指向的模板 -->
<script type="text/html" id="tools">
<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
</script>
<form class="layui-form" action="" id="form_edit" lay-filter="form_edit" style="margin-top: 20px;display: none">
<div class="layui-form-item" style="display: none">
<label class="layui-form-label">ID</label>
<div class="layui-input-block">
<input type="text" name="id" lay-verify="required" autocomplete="off" placeholder="请输入"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">标题</label>
<div class="layui-input-block">
<input type="text" name="title" lay-verify="required" autocomplete="off" placeholder="请输入"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">内容</label>
<div class="layui-input-block">
<textarea name="content" class="layui-textarea" placeholder="请输入内容"></textarea>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">时间</label>
<div class="layui-input-inline">
<input type="text" class="layui-input" name="time" id="time"
placeholder="" autocomplete="off" lay-verify="required">
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">分类</label>
<div class="layui-input-block">
<textarea name="category" class="layui-textarea" placeholder="请输入"></textarea>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">图片链接</label>
<div class="layui-input-block">
<textarea name="image_link" class="layui-textarea" placeholder="请输入"></textarea>
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button type="submit" class="layui-btn" lay-submit lay-filter="edit-commit">立即提交</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</form>
<table class="layui-hide" id="ID-table-demo-page"></table>
<script type="text/html" id="ID-table-demo-page-pagebar">
</script>
{% endblock %}
{% block js %}
<script>
// 编辑提交的方法
const change_case = async (id, data) => {
const options = {
method: 'PUT',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(data)
}
const response = await fetch(`/web/case_update/${id}/`, options)
return await response.json()
}
layui.use('table', function () {
var table = layui.table;
var $ = layui.$;
var form = layui.form;
var laydate = layui.laydate;
// 创建渲染实例
table.render({
elem: '#ID-table-demo-page',
url: '/web/index_case/', // 此处为静态模拟数据,实际使用时需换成真实接口
page: {
layout: ['limit', 'count', 'prev', 'page', 'next', 'skip'], //自定义分页布局
//curr: 5, //设定初始在第 5 页
groups: 1, //只显示 1 个连续页码
first: false, //不显示首页
last: false //不显示尾页
},
pagebar: '#ID-table-demo-page-pagebar', // 分页栏模板
toolbar: '#toolbar',
cols: [[
{field: 'id', title: 'ID', width: 60, sort: true},
{field: 'title', title: '标题', width: 100},
{field: 'content', title: '内容', minWidth: 160},
{field: 'category', title: '分类', minWidth: 160},
{field: 'time', title: '时间', width: 200},
{field: 'image_link', title: '图片链接', width: 120},
{title: '操作', width: 120, templet: '#tools'},
]]
});
// 底部分页栏事件
table.on('toolbar(ID-table-demo-page)', function (obj) {
var options = obj.config;
var checkStatus = table.checkStatus(options.id);
switch (obj.event) {
case 'add':
window.show_add()
break;
case 'delete_many':
window.delete_many(obj)
break;
}
});
window.show_add = function () {
{#layer.msg('添加')#}
layer.open(({
type: 2,
title: '新增新闻',
shadeClose: true,
maxmin: true,
area: ['900px', '600px'],
content: '/web/case_add/'
}))
}
window.delete_many = function () {
layer.msg('批量删除')
}
// 单元格工具事件
table.on('tool(ID-table-demo-page)', function (obj) {
var layEvent = obj.event; // 获得元素对应的 lay-event 属性值
if (layEvent === 'edit') { //编辑
window.show_edit(obj)
} else if (layEvent === 'del') { //删除
layer.confirm('确定删除吗?', function (index) {
layer.close(index);
window.del_case(obj)
});
}
});
// 日期时间选择器
laydate.render({
elem: '#time',
type: 'date',
format: 'yyyy-MM-dd'
});
window.show_edit = (obj) => {
console.log(obj.data)
form.val('form_edit', obj.data);
layer.open({
type: 1,
area: ['900px', '600px'],
content: $('#form_edit'), // 捕获的元素
shade: 0.0
});
}
const del_case_api = async (id) => {
const options = {
method: 'DELETE',
headers: {'Content-Type': 'application/json'},
}
const response = await fetch(`/web/case_del/${id}/`, options)
return await response.json()
}
window.del_case = (obj) => {
// console.log(obj)
del_case_api(obj.data.id).then(function (ret) {
// 提交成功之后的回调
if (!ret.code) {
layer.msg(ret.msg, {
icon: 1,
time: 1000,
}, function () {
table.reload('ID-table-demo-page');
});
} else {
layer.msg(ret.msg, {
icon: 2,
time: 1000,
});
}
})
}
// 提交事件
form.on('submit(edit-commit)', function (data) {
var field = data.field; // 获取表单字段值
change_case(field.id, field).then(function (ret) {
// 提交成功之后的回调
if (!ret.code) {
layer.msg(ret.msg, {
icon: 1,
time: 1000,
}, function () {
layer.closeAll('page');
table.reload('ID-table-demo-page');
});
} else {
layer.msg(ret.msg, {
icon: 2,
time: 1000,
});
}
})
return false; // 阻止默认 form 跳转
});
});
</script>
{% endblock js %}
案例页面的增加及编辑代码
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>新增</title>
<link rel="stylesheet" href="{% static 'css/layui.css' %}">
</head>
<body>
<form class="layui-form" action="" lay-filter="form_add" style="margin-top: 20px">
<div class="layui-form-item">
<label class="layui-form-label">标题</label>
<div class="layui-input-block">
<input type="text" name="title" lay-verify="required" autocomplete="off" placeholder="请输入"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">内容</label>
<div class="layui-input-block">
<textarea name="content" class="layui-textarea" placeholder="请输入内容"></textarea>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">时间</label>
<div class="layui-input-inline">
<input type="text" class="layui-input" name="time" id="time"
placeholder="" autocomplete="off" lay-verify="required">
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">分类</label>
<div class="layui-input-block">
<textarea name="category" class="layui-textarea" placeholder="请输入"></textarea>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">图片链接</label>
<div class="layui-input-block">
<textarea name="image_link" class="layui-textarea" placeholder="请输入"></textarea>
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button type="submit" class="layui-btn" lay-submit lay-filter="add-commit">立即提交</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</form>
<script src="{% static 'layui.js' %}"></script>
<script>
// 新增提交的方法
const add_news = async (data) => {
const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(data)
}
const response = await fetch('/web/case_post/', options)
return await response.json()
}
layui.use(function () {
var $ = layui.$
var form = layui.form
var laydate = layui.laydate;
// 日期时间选择器
laydate.render({
elem: '#time',
type: 'date',
format:'yyyy-MM-dd'
});
// 提交事件
form.on('submit(add-commit)', function (data) {
var field = data.field; // 获取表单字段值
console.log(field)
// 此处可执行 Ajax 等操作
add_news(field).then(function (ret) {
// 提交成功之后的回调
if (!ret.code) {
layer.msg(ret.msg, {
icon: 1,
time: 1000,
}, function () {
parent.layer.close(parent.layer.getFrameIndex(window.name)); //关闭当前页
parent.layui.table.reload('case/');
});
} else {
layer.msg(ret.msg, {
icon: 2,
time: 1000,
});
}
})
return false; // 阻止默认 form 跳转
});
})
</script>
</body>
</html>
5.配置主路由及子路由
主路由是在跟setting同级的urls中,子路由在注册的app中的urls中,没有则自己创建
6.配置setting
配置数据库,可以使用mysql,也可以使用自带的sqlite3
配置static和跨域问题
APPEND_SLASH = False
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
# 允许所有的请求头
CORS_ALLOW_HEADERS = ('*')
7.目录结构