Django基础用法+Demo演示
Django快速上手
参考: Django快速上手
再写几个页面
编辑demo1/urls.py, 添加URL和视图函数映射
urlpatterns = [path('index/', views.index),path('user/list/', views.user_list),path('user/add/', views.user_add),
]
编辑app01/views.py,添加几个函数
from django.shortcuts import render, HttpResponse# Create your views here.
def index(request):return HttpResponse("Hello World")def user_list(request):return HttpResponse("User List")def user_add(request):return HttpResponse("User add")
templates模板的运用
编辑app01/views.py,使用render返回一个HTML页面
def user_list(request):return render(request, "user_list.html")
app01目录下创建templates/user_list.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><h1>User List</h1>
</body>
</html>
引用静态文件
在app目录下创建static目录,image、css、js都放在static目录下,static目录结构:
static
|- css
|- img
|- js
|- plugins
引用Bootstrap, JQuery, image, 编辑templates/user_list.html
{% load static %}<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1/css/bootstrap.css' %}">
</head>
<body><h1>User List</h1><input type="text" class="btn btn-primary" value="Create" /><img src="{% static 'img/1.png' %}" alt="" /><script src="{% static 'js/jquery-3.7.1.min.js' %}"></script><script src="{% static 'plugins/bootstrap-3.4.1/js/bootstrap.js' %}"></script>
</body>
</html>
Q: 为什么使用load static这种方式引入静态文件?/static/img/1.png不也行吗?
A: 如果静态文件移动到别的路径,只需要改settings.py的配置,不需要逐个修改每个页面的路径
Django模板语法
什么是Django模板: 在HTML中写一些占位符,由数据对占位符进行替换和处理
举例:
编辑app01/views.py
def tpl(request):name = 'Peter'roles = ['admin', 'guest']user_info = {'name': 'Tony', 'salary': 10000, 'role': 'CEO'}data_list = [{"name": "peter", "salary": 10000, "role": "CTO"},{"name": "tony", "salary": 5000, "role": "CFO"}]return render(request, 'tpl.html', {"n1": name, "n2": roles, "n3": user_info, "n4": data_list})
编辑demo1/urls.py
urlpatterns = [path('user/tpl/', views.tpl),
]
新增app01/templates/tpl.html
<body><div>{{ n1 }}</div><div>{{ n2 }}</div><div>{{ n2.0 }}</div><div>{{ n2.1 }}</div><div>{% for item in n2 %}<span>{{ item }}</span>{% endfor %}</div><hr/>{{ n3.name }}{{ n3.salary }}{{ n3.role }}{% for k,v in n3.items %}<li>{{ k }} == {{ v }} </li>{% endfor %}{% for k in n3.keys %}<li>{{ k }} </li>{% endfor %}{% for v in n3.values %}<li>{{ v }} </li>{% endfor %}<div>{{ n4 }}</div>{% for item in n4 %}<div>{{ item.name }}, {{ item.salary }}</div>{% endfor %}{% if n1 == 'Peter' %}<div>Peter!</div>{% else %}<div>Not Peter!</div>{% endif %}
</body>
curl localhost:8000/user/tpl/
Peter
['admin', 'guest']
admin
guest
admin guest
Tony 10000 CEO
name == Tony
salary == 10000
role == CEO
name
salary
role
Tony
10000
CEO
[{'name': 'peter', 'salary': 10000, 'role': 'CTO'}, {'name': 'tony', 'salary': 5000, 'role': 'CFO'}]
peter, 10000
tony, 5000
Peter!
案例:简单的用户登录(无数据库)
编辑demo1/urls.py, 添加映射
from app01 import views
urlpatterns = [path('login/', views.login),
]
编辑app01/views.py, 实现login函数
def login(request):if request.method == "GET":return render(request, "login.html")username = request.POST.get("user")password = request.POST.get("pwd")if username == "root" and password == "123":return redirect("https://www.baidu.com")return render(request, "login.html", {"error_msg": "Login Failed"})
新增app01/template/login.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><h1>User Login</h1><form method="post" action="/login/"><input type="text", name="user", placeholder="Username"/><input type="password", name="password", placeholder="Password"/><input type="submit" value="Submit"/></form>
</body>
</html>
提交表单后报错: CSRF verification failed, Forbidden(403)
解决方法: 在form表单里加{% csrf_token %}
<h1>User Login</h1><form method="post" action="/login/">{% csrf_token %}<input type="text", name="user", placeholder="Username"/><input type="password", name="password", placeholder="Password"/><input type="submit" value="Submit"/></form>
Django连接MySQL数据库
框架:业务代码 -> ORM -> (pymysql,MySQLdb,mysqlclient) -> Database
安装MySQL
参考: https://pcj600.github.io/2024/0916144756.html
安装mysqlclient
参考: https://pcj600.github.io/2024/0916170317.html
ORM
- 支持创建、修改、删除表(不用你写SQL语句), 但无法创建数据库
- 操作表中的数据(不用你写SQL语句)
创建数据库
mysql -u root -p
create database gx_day15 DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
- DEFAULT CHARSET utf8: 指定了数据库的默认字符集。
- COLLATE utf8_general_ci: 表示使用 utf8 字符集的不区分大小写的校对规则(ci 表示 case-insensitive)s
连接数据库
https://docs.djangoproject.com/en/5.1/ref/databases/#mysql-notes
编辑demo1/settings.py
DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql','NAME': 'gx_day15','USER': 'root','PASSWORD': 'XXX','HOST': 'localhost','PORT': 3306,}
}
创建、修改表
创建表不需要写SQL语句,只需在app01/models.py里定义一个类
class UserInfo(models.Model):name = models.CharField(max_length=32)password = models.CharField(max_length=64)age = models.IntergerField(default=2)
相当于创建了一个表,表名: app01_userinfo
create table app01_userinfo(id bigint auto_increment primary key,name varchar[32],password varchar[64],age int
)
执行命令,让Django真正创建表。
先确认APP已经注册:demo1/settings.py
INSTALLED_APPS = ['app01.apps.App01Config',
]
在项目根目录执行:
python3 manage.py makemigrations
python3 manage.py migrate
查看表
mysql -u root -p
mysql> use gx_day15;
mysql> desc app01_userinfo;
+----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+----------------+
| id | bigint | NO | PRI | NULL | auto_increment |
| name | varchar(32) | NO | | NULL | |
| password | varchar(64) | NO | | NULL | |
| age | int | NO | | NULL | |
+----------+-------------+------+-----+---------+----------------+
4 rows in set (0.01 sec)
表中新增列时,由于已存在列中可能已有数据,所以新增列必须要指定新增列对应的数据:
- 手动输入一个值
- 设置默认值
删除表: 在models.py里删掉对应的类,再执行
python3 manage.py makemigrations
python3 manage.py migrate
创建表中的数据
app01/models.py
class Department(models.Model):title = models.CharField(max_length=16)
app01/views.py
from app01.models import Department,UserInfo
def orm(request):Department.objects.create(title='sales')return HttpResponse('ORM OK')
删除表中数据
app01/views.py
from app01.models import Department,UserInfo
def orm(request):Department.objects.filter(title='sales').delete() # 删掉所有title=sales的数据Department.objects.all().delete() # 所有数据都删掉return HttpResponse('ORM OK')
更新表中数据
data_list = UserInfo.objects.all()
for obj in data_list:print(obj.id, obj.name, obj.password)# data_list = UserInfo.objects.filter(id=1)o = UserInfo.objects.filter(id=1).first()print(o.id, o.name, o.password)# 更新所有行的数据UserInfo.objects.all().update(password='123456')UserInfo.objects.filter(name='peter').update(password='123456')
- objects.all()返回queryset类型,每个元素是一个对象
- UserInfo.objects.filter(id=1).first() 返回符合筛选条件的第一条数据
数据库操作的案例 —— 用户管理
显示用户
app01/models.py
from django.db import modelsclass UserInfo(models.Model):name = models.CharField(max_length=32)password = models.CharField(max_length=64)age = models.IntegerField(default=18)
查看数据库
mysql> desc app01_userinfo;
+----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+----------------+
| id | bigint | NO | PRI | NULL | auto_increment |
| name | varchar(32) | NO | | NULL | |
| password | varchar(64) | NO | | NULL | |
| age | int | NO | | NULL | |
+----------+-------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)mysql> select * from app01_userinfo;
+----+-------+----------+-----+
| id | name | password | age |
+----+-------+----------+-----+
| 1 | peter | 123 | 18 |
| 2 | jack | 123 | 18 |
+----+-------+----------+-----+
2 rows in set (0.00 sec)
显示用户列表
demo1/urls.py
from app01 import views
urlpatterns = [path('user/info/', views.user_info),
]
app01/views.py
def user_info(request):user_list = UserInfo.objects.all()return render(request, "user_info.html", {"user_list": user_list})
app01/templates/user_info.html
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title></head>
<body><table border="1"><thead><tr><th>ID</th><th>Name</th><th>Password</th><th>Age</th></tr></thead><tbody>{% for user in user_list %}<tr><td>{{ user.id }}</td><td>{{ user.name }}</td><td>{{ user.password }}</td><td>{{ user.age }}</td></tr>{% endfor %}</tbody></table>
</body>
</html>
添加用户
用户在页面的表单上输入用户信息, 再通过POST请求提交
demo1/urls.py
urlpatterns = [# ...path('info/add/', views.user_add),
]
app01/views.py
from app01.models import Department,UserInfo
def user_add(request):if request.method == "GET":return render(request, "user_add.html")username = request.POST.get("user")password = request.POST.get("password")age = request.POST.get("age")UserInfo.objects.create(name=username, password=password, age=age)return HttpResponse("ADD USER {} pwd: {} age: {} Done".format(username, password, age))
app01/templates/user_add.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>User Add</title></head>
<body><form method="post"> <!-- action可以省略 -->{% csrf_token %}<input type="text" name="user", placeholder="username" /><input type="text" name="password", placeholder="password" /><input type="text" name="age", placeholder="age" /><input type="submit" value="submit" /></form>
</body>
</html>
注:如果POST提交地址和当前页面地址一样,可以省略action=“/user/add/”
添加成功后自动跳转到用户页面
app01/views.py
def user_add(request):# ...return redirect("/user/info")
在用户页面中支持新增用户的功能
<a href="/user/add">Add User</a>
删除用户
demo1/urls.py
from app01 import views
urlpatterns = [path('user/delete/', views.user_delete),
]
app01/views.py
def user_delete(request):if request.method == "GET":return render(request, "user_delete.html")# POSTusername = request.POST.get("user")UserInfo.objects.filter(name=username).delete()return redirect("/user/info")
app01/templates/user_delete.html
{% load static %}
<html lang="en">
<head><meta charset="UTF-8"><title>User Delete</title></head>
<body><form method="post">{% csrf_token %}<input type="text" name="user", placeholder="username" /><input type="submit" value="submit" /></form>
</body>
</html>
Demo: 员工管理系统
创建项目
创建Django项目和APP
django-admin startproject webproj
python3 manage.py startapp app01
注册APP
demo1/settings.py
INSTALLED_APPS = ['django.contrib.admin',# ...'app01.apps.App01Config', # Add your app config here !
]
运行
python3 manage.py runserver 0.0.0.0:8000
设计表结构
# 部门表
id title
1 研发
2 销售# 员工表
id name password age account create_time depart_id
1 Tony 123 18
2
思考题: 如果部门删除,员工表怎么处理?
- 如果部门删除,员工也要裁掉 (级联删除)
- 员工不裁掉,可以置空
实际开发中为什么大公司要禁用外键约束?https://developer.aliyun.com/article/1171702
models.py
class Department(models.Model):""" 部门表 """title = models.CharField(max_length=32)
class UserInfo(models.Model):""" 员工表 """name = models.CharField(max_length=16)password = models.CharField(max_length=64)age = models.CharField()account = models.DecimalField(max_digits=10,decimal_places=2, default=0)create_time = models.DateTimeField()# 部门ID, 外键, 级联删除, 允许部门为空depart = models.ForeignKey(to="Department", to_field="id",null=True, blank=True, on_delete=models.CASCADE)gender_choices = ((1, "男"),(2, "女"),)gender = models.SmallIntegerField(verbose_name="gender", choices=gender_choices)
MySQL生成数据库
mysql> create database gx_day16 DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
settings.py
DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql','NAME': 'gx_day16','USER': 'root','PASSWORD': 'XXX','HOST': 'localhost','PORT': 3306,}
}
根目录执行
python3 manage.py makemigrations
python3 manage.py migrate
创建静态文件和模板文件
app目录下创建static, templates, 引入bootstrap, js
static/
├── js
│ └── jquery-3.7.1.min.js
└── plugins└── bootstrap-3.4.1
新增页面 —— 部门列表
webproj/urls.py
from app01 import views
urlpatterns = [path('depart/list/', views.depart_list),
]
app01/views.py
def depart_list(request):return render(request, 'depart_list.html')
app01/templates/depart_list.html
{% load static %}<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1/css/bootstrap.css' %}">
</head>
<body><!-- 导航 --><nav class="navbar navbar-default"><div class="container-fluid"><!-- Brand and toggle get grouped for better mobile display --><div class="navbar-header"><button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"><span class="sr-only">Toggle navigation</span><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></button><a class="navbar-brand" href="#">用户管理系统</a></div><!-- Collect the nav links, forms, and other content for toggling --><div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"><ul class="nav navbar-nav"><li><a href="#">部门管理</a></li><li><a href="#">用户管理</a></li></ul><ul class="nav navbar-nav navbar-right"><li><a href="#">登录</a></li><li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">当前用户<span class="caret"></span></a><ul class="dropdown-menu"><li><a href="#">个人资料</a></li><li><a href="#">我的信息</a></li><li><a href="#">注销</a></li><li role="separator" class="divider"></li><li><a href="#">Separated link</a></li></ul></li></ul></div></div></nav><!-- 内容 --><div class="container-fluid"><div style="margin-bottom: 18px"><a class="btn btn-primary" href="#">新建部门</a></div></div><div class="panel panel-default"><!-- Default panel contents --><div class="panel-heading">部门列表</div><!-- Table --><table class="table table-bordered"><thead><tr><th>ID</th><th>Name</th><th>Operation</th></tr></thead><tbody>{% for d in departs %}<tr><td>{{ d.id }}</td><td>{{ d.title }}</td><td><a class="btn btn-primary">Edit</a><a class="btn btn-danger">Delete</a></td></tr>{% endfor %}</tbody></table></div><script src="{% static 'js/jquery-3.7.1.min.js' %}"></script><script src="{% static 'plugins/bootstrap-3.4.1/js/bootstrap.js' %}"></script>
</body>
</html>
页面效果:

新增页面 —— 添加部门
app01/templates/depart_list.html
<div class="container-fluid"><div style="margin-bottom: 18px"><a class="btn btn-success" href="/depart/add/"><span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span>新建部门</a></div></div>
webproj/urls.py
urlpatterns = [path('depart/add/', views.depart_add),
]
depart_add.html
<!-- 带标题的面板 --><div class="panel panel-default"><div class="panel-heading"><h3 class="panel-title">添加部门</h3></div><div class="panel-body"><!-- 水平排列的表单 --><form method="post">{% csrf_token %}<div class="form-group"><label>部门标题</label><input type="text" class="form-control" name="title" placeholder="title"></div><button type="submit" class="btn btn-default">Submit</button></form></div></div>
app01/views.py
from django.shortcuts import render, HttpResponse, redirect
def depart_add(request):if request.method == "GET":return render(request, "depart_add.html")# POSTtitle = request.POST.get("title")models.Department.objects.create(title="title")return redirect("/depart/list/")
页面效果:

删除部门
webproj/urls.py
urlpatterns = [path('depart/delete/', views.depart_delete),
]
app01/views.py
def depart_delete(request):nid = request.GET.get("nid")models.Department.objects.filter(title=nid).delete()return redirect("/depart/list/")
app01/templates/depart_list.html
<tbody>{% for d in departs %}<tr><td>{{ d.id }}</td><td>{{ d.title }}</td><td><a class="btn btn-primary">Edit</a><a class="btn btn-danger" href="/depart/delete/?nid={{ d.id }}">Delete</a></td></tr>{% endfor %}</tbody>
修改部门
效果: 点击Edit后,把部门的title带到输入框里。
webproj/urls.py
urlpatterns = [# http://127.0.0.1:80000/depart/1/edit/path('depart/<int:nid>/edit/', views.depart_edit),
]
app01/views.py
def depart_edit(request, nid):if request.method == "GET":depart = models.Department.objects.filter(id=nid).first()return render(request, "depart_edit.html", {"depart": depart})# POSTtitle = request.POST.get('title')models.Department.objects.filter(id=nid).update(title=title)return redirect("/depart/list/")
depart_list.html
{% for d in departs %}<tr><td>{{ d.id }}</td><td>{{ d.title }}</td><td><a class="btn btn-primary" href="/depart/{{ obj.id }}/edit/">Edit</a></td></tr>{% endfor %}
depart_edit.html
<div class="panel panel-default"><div class="panel-heading"><h3 class="panel-title">编辑部门</h3></div><div class="panel-body"><!-- 水平排列的表单 --><form method="post">{% csrf_token %}<div class="form-group"><label>部门标题</label><input type="text" class="form-control" name="title" value="{{ depart.title }}"></div><button type="submit" class="btn btn-default">Submit</button></form></div></div>
页面效果

显示用户列表
多个HTML页面都用到了相同的导航栏,可以把相同的组件抽成模板(layout.html)
{% block content %}-{% endblock %}
在新页面引用layout.html
{% extends 'layout.html' %}{% block content %}<h1>首页</h1>
{% endblock %}
显示用户列表
urls.py
urlpatterns = [path('user/list/', views.user_list),
]
MySQL里加几条用户数据
mysql> desc app01_userinfo;
+-------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------+------+-----+---------+----------------+
| id | bigint | NO | PRI | NULL | auto_increment |
| name | varchar(16) | NO | | NULL | |
| password | varchar(64) | NO | | NULL | |
| age | int | NO | | NULL | |
| account | decimal(10,2) | NO | | NULL | |
| create_time | datetime(6) | NO | | NULL | |
| gender | smallint | NO | | NULL | |
| depart_id | bigint | NO | MUL | NULL | |
+-------------+---------------+------+-----+---------+----------------+
mysql> insert into app01_userinfo values(1, 'peter', '123456', 18, 100, '2024-09-21 11:31:00', 0, 1);
mysql> insert into app01_userinfo(name,password,age,account,create_time,gender,depart_id)
values('peter', '123456', 18, 100, '2024-09-21 11:31:00', 0, 1);
views.py
def user_list(request):if request.method == "GET":users = models.UserInfo.objects.all()for user in users:print(user.id, user.name, user.account, user.create_time.strftime("%Y-%m-%d"), user.gender)print(user.get_gender_display)print(user.depart) # 自动关联查询return render(request, "user_list.html", {"users": users})
templates/user_list.html
{% load static %}<table class="table table-bordered"><thead><tr><th>ID</th><th>Name</th><th>Password</th><th>Age</th><th>Account</th><th>Createtime</th><th>Gender</th><th>Depart</th><th>Operation</th></tr></thead><tbody>{% for u in users %}<tr><td>{{ u.id }}</td><td>{{ u.name }}</td><td>{{ u.password }}</td><td>{{ u.age }}</td><td>{{ u.account}}</td><td>{{ u.create_time | date:"Y-m-d H:i:s" }}</td><td>{{ u.get_gender_display }}</td><td>{{ u.depart.title }}</td><td><a class="btn btn-primary">Edit</a><a class="btn btn-danger">Delete</a></td></tr>{% endfor %}</tbody></table>
- 模板中解析datetime
<td>{{ u.create_time | date:"Y-m-d H:i:s" }}</td> - 模板中解析性别:
<td>{{ u.get_gender_display }}</td> - 关联查询部门:
<td>{{ u.depart.title }}</td>
添加用户
原始方式存在的问题:
- 用户数据未做校验
- 如果输入错误,也没有错误提示
- 页面上,每一个字段都有重新写一遍
- 关联数据,需要手动获取传参,再展示到页面
为了解决以上问题,Django提供了ModelForm组件
urls.py
urlpatterns = [path('user/add/', views.user_add),
]
views.py
from django import forms
class UserModelForm(forms.ModelForm):class Meta:model = models.UserInfofields = ["name", "password", "age", "account", "create_time", "gender", "depart"]def __init__(self, *args, **kwargs):super().__init__(*args, **kwargs)for name, field in self.fields.items():field.widget.attrs = {"class": "form-control"}def user_add(request):if request.method == "GET":form = UserModelForm()return render(request, "user_add.html", {"form": form})# POST:form = UserModelForm(data=request.POST)if form.is_valid():form.save()return redirect("/user/list/")else:return HttpResponse(form.errors)
user_add.html
<div class="panel-body"><!-- 水平排列的表单 --><form method="post">{% csrf_token %}{% for field in form %}{{ field }}{% endfor %}</form>
</div>
编辑用户
urls.py
urlpatterns = [path('user/<int:nid>/edit/', views.user_edit),
]
views.py
def user_edit(request, nid):if request.method == "GET":obj = models.UserInfo.objects.filter(id=nid).first()form = UserModelForm(instance=obj)return render(request, "user_edit.html", {"form": form})# POSTuser = models.UserInfo.objects.filter(id=nid).first()form = UserModelForm(data=request.POST, instance=user)if form.is_valid():form.save()return redirect("/user/list/")else:return HttpResponse(form.errors)
删除用户
urls.py
urlpatterns = [path('user/<int:nid>/edit/', views.user_delete),
]
views.py
def user_delete(request, nid):obj = models.UserInfo.objects.filter(id=nid).delete()return redirect("/user/list/")
靓号管理
表结构
desc app01_prettynum;
+--------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+----------------+
| id | bigint | NO | PRI | NULL | auto_increment |
| mobile | varchar(11) | NO | | NULL | |
| price | int | NO | | NULL | |
| level | smallint | NO | | NULL | |
| status | smallint | NO | | NULL | |
+--------+-------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
展示靓号
models.py
class PrettyNum(models.Model):""" 靓号表 """mobile = models.CharField(verbose_name="手机号", max_length=11)price = models.IntegerField(verbose_name="价格", default=0)level_choices = ((1, "1级"),(2, "2级"),(3, "3级"),(4, "4级"),)level = models.SmallIntegerField(verbose_name="级别", choices=level_choices, default=1)status_choices = ((1, "已占用"),(2, "未占用"),)status = models.SmallIntegerField(verbose_name="状态", choices=status_choices, default=2)
urls.py
urlpatterns = [path('pretty/list/', views.pretty_list),
]
views.py
from app01 import models
def pretty_list(request):prettys = models.PrettyNum.objects.all().order_by("-level")return render(request, "pretty_list.html", {"prettys": prettys})
新建靓号
urls.py
urlpatterns = [path('pretty/add/', views.pretty_add),
]
views.py
class PrettyModelForm(forms.ModelForm):class Meta:model = models.PrettyNum# fields = "__all__"# fields = ["mobile", "price", "level", "status"]exclude = ["level"]def pretty_add(request):if request.method == "GET":form = PrettyModelForm()return render(request, "pretty_add.html", {"form": form})form = PrettyModelForm(data=request.POST)if form.is_valid():form.save()return redirect("/pretty/list/")else:return HttpResponse(form.errors)
对用户输入的格式做校验
编辑靓号
- path: /pretty/数字/edit/
- 使用ModelForm
urls.py
urlpatterns = [path('pretty/<int:nid>/edit/', views.pretty_edit),
]
views.py
def pretty_edit(request, nid):if request.method == "GET":pretty = models.PrettyNum.objects.filter(id=nid).first()form = PrettyModelForm(instance=pretty)return render(request, "pretty_edit.html", {"form": form})# POSTpretty = models.PrettyNum.objects.filter(id=nid).first()form = PrettyModelForm(data=request.POST, instance=pretty)if form.is_valid():form.save()return redirect("/pretty/list/")else:return HttpResponse(form.errors)
pretty_edit.html
{% extends 'layout.html' %}{% block content %}<div class="container-fluid"><div style="margin-bottom: 18px"><a class="btn btn-success" href="/pretty/add/"><span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span>编辑靓号</a></div></div><div class="panel panel-default"><!-- Default panel contents --><div class="panel-heading">编辑靓号</div><form method="post">{% csrf_token %}{% for field in form %}{{ field }}{% endfor %}<input type="submit" value="提交" /></form></div>
{% endblock %}
查询手机号
数值搜索
models.PrettyNum.objects.filter(id=12)
models.PrettyNum.objects.filter(id__gt=12) # 大于12
models.PrettyNum.objects.filter(id__gte=12) # 大于等于12
models.PrettyNum.objects.filter(id__lt=12) # 小于12
models.PrettyNum.objects.filter(id__lte=12) # 小于等于12
字符串搜索
models.PrettyNum.objects.filter(mobile__startswith="1999") # 开头
models.PrettyNum.objects.filter(mobile__endswith="999") # 结尾
models.PrettyNum.objects.filter(mobile__contains="999") # 包含
案例:加一个搜索框,显示所有匹配的手机号
<div style="float: right;width: 300px;"><form method="get"><div class="input-group">{% csrf_token %}<input type="text" class="form-control" name="search" placeholder="Search for..."><span class="input-group-btn"><input class="btn btn-default" type="submit">Go!</input></span></div></form></div>
views.py
def pretty_list(request):if request.method == "GET":if request.GET.get("search"):search_mobile = request.GET.get("search")print(search_mobile)prettys = models.PrettyNum.objects.filter(mobile__contains=search_mobile)return render(request, "pretty_list.html", {"prettys": prettys})prettys = models.PrettyNum.objects.all()return render(request, "pretty_list.html", {"prettys": prettys})
分页显示靓号
效果:GET /pretty/list/?page=1 显示前10条记录
用切片
def pretty_list(request):if request.method == "GET":if request.GET.get("page"):page = int(request.GET.get("page"))begin = (page - 1) * 10end = page * 10prettys = models.PrettyNum.objects.all()[begin:end]return render(request, "pretty_list.html", {"prettys": prettys})
bootstrap上找一个分页组件
<nav aria-label="Page navigation"><ul class="pagination"><li><a href="/pretty/list/?page=1">1</a></li><li><a href="/pretty/list/?page=2">2</a></li><li><a href="/pretty/list/?page=3">3</a></li></ul>
</nav>
管理员操作
class Admin(models.Model):""" 管理员 """username = models.CharField(verbose_name="username", max_length=32)password = models.CharField(verbose_name="password", max_length=64)
urls.py
from app01 import views
urlpatterns = [path('admin/list/', views.admin_list),path('admin/add/', views.admin_add),
]
views.py
def admin_list(request):if request.method == "GET":admins = models.Admin.objects.all()return render(request, "admin_list.html", {"admins": admins})class AdminModelForm(forms.ModelForm):class Meta:model = models.Adminfields = "__all__"def admin_add(request):if request.method == "GET":form = AdminModelForm()return render(request, "admin_add.html", {"form": form})
admin_list.html
<div class="panel panel-default"><!-- Default panel contents --><div class="panel-heading">管理员列表</div><!-- Table --><table class="table table-bordered"><thead><tr><th>ID</th><th>AdminUser</th><th>Password</th><th>Operation</th></tr></thead><tbody>{% for obj in admins %}<tr><td>{{ obj.id }}</td><td>{{ obj.username }}</td><td>{{ obj.password }}</td><td><a class="btn btn-primary" href="">Edit</a><a class="btn btn-danger" href="">Delete</a></td></tr>{% endfor %}</tbody></table></div>
admin_add.html
{% extends 'layout.html' %}{% block content %}
<!-- 带标题的面板 --><div class="panel panel-default"><div class="panel-heading"><h3 class="panel-title">添加管理员</h3></div><div class="panel-body"><!-- 水平排列的表单 --><form method="post">{% csrf_token %}{% for field in form %}<div class="form-group"><label>{{ field.label }}</label>{{ field }}</div>{% endfor %}<button type="submit" class="btn btn-primary">Submit</button></form></div></div>
{% endblock %}
表单中添加确认密码, 判断两次密码输入一致
from django.core.exceptions import ValidationError
class AdminModelForm(forms.ModelForm):confirm_password = forms.CharField(label="确认密码", widget=forms.PasswordInput)class Meta:model = models.Adminfields = ["username", "password", "confirm_password"]widgets = {"password": forms.PasswordInput}def clean_confirm_password(self):pwd = self.cleaned_data.get("password")confirm = self.cleaned_data.get("confirm_password")if confirm != pwd:raise ValidationError("Password Wrong")return confirm
编辑管理员
urls.py
urlpatterns = [path('admin/<int:nid>/edit/', views.admin_edit),
]
views.py
def admin_edit(request, nid):if request.method == "GET":admin = models.Admin.objects.filter(id=nid).first()form = AdminModelForm(instance=admin)return render(request, "admin_edit.html", {"form": form})admin = models.Admin.objects.filter(id=nid).first()form = AdminModelForm(data=request.POST, instance=admin)if form.is_valid():form.save()return redirect("/admin/list/")else:return HttpResponse(form.errors)
删除管理员
urlpatterns = [path('admin/<int:nid>/delete/', views.admin_delete),
]
views.py
def admin_delete(request, nid):if request.method == "GET":models.Admin.objects.filter(id=nid).delete()return redirect("/admin/list/")
用户认证(Session+Cookie认证)
Django默认把Session存到MySQL数据库中的django_session表里
先写一个登录页面,创建一个表单,包括username和password
校验用户名和密码输入正确,生成session到数据库, 跳转到/admin/list/页面
views.py
def login(request):if request.method == "GET":form = LoginForm()return render(request, "login.html", {"form": form})# POSTform = LoginForm(data=request.POST)if form.is_valid():admin_obj = models.Admin.objects.filter(**form.cleaned_data).first()if not admin_obj:form.add_error("password", "password or user error")return render(request, "login.html", {"form": form})# 保存Sessionrequest.session["info"] = {"id": admin_obj.id, "name": admin_obj.username}return redirect("/admin/list/")return HttpResponse(form.errors)
login.html
<body>
<div class="account"><form method="post">{% csrf_token %}<div class="form-group"><label>Username</label>{{ form.username }}<span>{{ form.username.errors.0 }}</span></div><div class="form-group"><label>Password</label>{{ form.password }}<span>{{ form.password.errors.0 }}</span></div><input type="submit" value="login" class="btn btn-primary"></form>
</body>
数据库中查看Session
mysql> select * from django_session;
+----------------------------------+------------------------------------------------------------------------------------------------+----------------------------+
| session_key | session_data | expire_date |
+----------------------------------+------------------------------------------------------------------------------------------------+----------------------------+
| o4ltz9wfdlh7w9p761wmyoedlwtk73t9 | eyJpbmZvIjp7ImlkIjoyLCJuYW1lIjoiSGVsbG8ifX0:1st6E1:wZE1TBMjag4FZ3dt-RA-9ObJPBs_G_j0vYsj6ixTA9Y | 2024-10-08 14:09:09.853533 |
+----------------------------------+------------------------------------------------------------------------------------------------+----------------------------+
鉴权操作(只有认证成功,才可以访问其他页面)
朴素的实现方式:
def admin_list(request):# 如果没有session,跳转到登录页面info = request.session.get("info")if not info:return redirect("/login/")admins = models.Admin.objects.all()return render(request, "admin_list.html", {"admins": admins})
问题:所有视图都需要session认证,上面的实现太麻烦!
用Django中间件实现鉴权
app01/middleware/auth.py
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse, redirectclass AuthMiddleWare(MiddlewareMixin):def process_request(self, request):# 注意:对于无需登录就应该访问的页面,不要做鉴权,否则会循环重定向if request.path_info == "/login/":returninfo_dict = request.session.get("info")print(info_dict)if info_dict:returnreturn redirect("/login/")def process_response(self,request, response):print('M1 gone')return response
settings.py
MIDDLEWARE = ['app01.middleware.auth.M1','app01.middleware.auth.M2',
]
相关文章:
Django基础用法+Demo演示
Django快速上手 参考: Django快速上手 再写几个页面 编辑demo1/urls.py, 添加URL和视图函数映射 urlpatterns [path(index/, views.index),path(user/list/, views.user_list),path(user/add/, views.user_add), ]编辑app01/views.py,添加几个函数 from djang…...
【webrtc】 RTP 中的 MID(Media Stream Identifier)
RTP 中的 MID(Media Stream Identifier) RID及其与MID的区别 cname与mid的对比【webrtc】CNAME 是rtprtcp中的Canonical Name(规范化名称) 同样都是RTP头部扩展: 基于mediasoup的最新的代码,学习,发现mid在创建RtpSendStream时是必须传递的参数: 例如 D:\XTRANS\soup\…...
React 中 为什么多个 JSX 标签需要被一个父元素包裹?
为什么多个 JSX 标签需要被一个父元素包裹? JSX 虽然看起来很像 HTML,但在底层其实被转化为了 JavaScript 对象,你不能在一个函数中返回多个对象,除非用一个数组把他们包装起来。这就是为什么多个 JSX 标签必须要用一个父元素或者…...
记录日志中logback和log4j2不能共存的问题
本文章记录设置两个日志时候,控制台直接报错 标黄处就是错误原因:1. SLF4J(W):类路径包含多个SLF4J提供程序。 SLF4J(W):找到提供程序[org.apache.logging.slf4j. net]。 SLF4J(W):找到提供程序[ch.qos.log .classi…...
第5章: 图像变换与仿射操作
图像变换和仿射操作是图像处理中常用的技术,通过旋转、缩放、平移、剪裁等操作,可以实现多种视觉效果以及数据增强。 1.1 图像旋转 1.1.1 基础旋转操作 使用 rotate() 方法可以对图像进行旋转操作,指定旋转的角度(以度为单位&am…...
【计算机网络】【网络层】【习题】
计算机网络-传输层-习题 文章目录 13. 图 4-69 给出了距离-向量协议工作过程,表(a)是路由表 R1 初始的路由表,表(b)是相邻路由器 R2 传送来的路由表。请写出 R1 更新后的路由表(c)。…...
Scala的不可变Map常用操作
//类型:不可变,可变 //操作:添加元素,删除元素,查询元素,删除元素,遍历 object map {def main(args: Array[String]): Unit {//不可变Mapval map1 Map("鄂"->"湖北省"…...
nginx配置负载均衡详解
在现代的 web 应用中,负载均衡是确保高可用性、可扩展性和稳定性的关键技术之一。Nginx 是一个非常流行的反向代理服务器和负载均衡器,它支持多种负载均衡策略,能够帮助将客户端的请求分发到多个后端服务器,以提高系统的整体性能和…...
传奇996_19——龙岭总结
功能: 切割 切割属性: 即人物属性,可以设置临时属性或者永久属性,龙岭使用的是临时属性,所谓临时就是存在有效期,龙岭设置的有效期是123456789秒,即1428.89802天。 龙岭写法(倒叙…...
el-table 行列文字悬浮超出屏幕宽度不换行的问题
修改前的效果 修改后的效果 ui框架 element-plus 在网上找了很多例子都没找到合适的 然后这个东西鼠标挪走就不显示 控制台也不好调试 看了一下El-table的源码 他这个悬浮文字用的el-prpper 包着的 所以直接改 .el-table .el-propper 设置为max-width:1000px 就可以了 吐槽一…...
鸿蒙HarmonyOS 网络请求获取数据Http
注意的是;要为接口返回值指定类型 ,以及定义接口数据类型 index.ets import { http } from kit.NetworkKit;interface createAtType {date: number,}interface dataListType {createAt: createAtType;imgUrl: }Component export default struct TabBar {State dat…...
MySQL技巧之跨服务器数据查询:高级篇-先调用A数据库的MySql存储过程再复制到B数据库的表中
MySQL技巧之跨服务器数据查询:高级篇-先调用A数据库的MySql存储过程再复制到B数据库的表中 基础篇已经描述:借用微软的SQL Server ODBC 即可实现MySQL跨服务器间的数据查询。 而且还介绍了如何获得一个在MS SQL Server 可以连接指定实例的MySQL数据库的…...
JavaScript逆向爬虫教程-------基础篇之JavaScript密码学以及CryptoJS各种常用算法的实现
目录 一、密码学介绍 1.1 为什么要学密码学?1.2 密码学里面学哪一些 二、字符编码三、位运算四、Hex 编码与 Base64 编码 4.1 Hex 编码4.2 Base64 编码 五、消息摘要算法 5.1 简介5.2 JS中的MD5、SHA、HMAC、SM3 六、对称加密算法 6.1 介绍6.2 加密模式和填充方式6.3 CryptoJ…...
【分布式】万字图文解析——深入七大分布式事务解决方案
分布式事务 分布式事务是指跨多个独立服务或系统的事务管理,以确保这些服务中的数据变更要么全部成功,要么全部回滚,从而保证数据的一致性。在微服务架构和分布式系统中,由于业务逻辑往往会跨多个服务,传统的单体事务…...
apache2配置多站点
环境 ubuntu 14.04 apache2 Server version: Apache/2.4.7 (Ubuntu) Server built: Apr 3 2019 18:04:25 步骤 修改/etc/apache2/sites-enabled/000-default.conf 增加VirtualHost段,指定不同的ServerName、DocumentRoot等参数 <VirtualHost *:80>…...
基于PyQt Python的深度学习图像处理界面开发(一)
Python标准库更多的适合处理后台任务,唯一的图形库tkinter使用起来很不方便,所以后来出现了针对Python图形界面开发的扩展库,例如PyQt。 在介绍PyQt之前,必须先简单介绍一下Qt。Qt是一个C可视化开发平台,是一个跨平台的…...
【Linux网络】Linux网络编程套接字,UDP与TCP
📝个人主页🌹:Eternity._ ⏩收录专栏⏪:Linux “ 登神长阶 ” 🌹🌹期待您的关注 🌹🌹 ❀Linux网络编程套接字 📒1. 端口号📜2. 初识TCP协议与UDP协议…...
Vue3 -- 强制统一包管理器工具【企业级项目配置保姆级教程6】
引言: 团队开发项目的时候,需要统一包管理器工具,因为不同包管理器工具下载同一个依赖,可能版本不一样,导致项目出现bug问题,因此包管理器工具需要统一管理!!所以就需要我们强制统一包管理器工具。 创建scripts目录和preinstall.js文件: 在根目录创建scritps/preinstal…...
Winform实现自制浏览器JavaScript注入
让我们一起走向未来 🎓作者简介:全栈领域优质创作者 🌐个人主页:百锦再新空间代码工作室 📞工作室:新空间代码工作室(提供各种软件服务) 💌个人邮箱:[1504566…...
【工具插件类教学】在 Unity 中使用 iTextSharp 实现 PDF 文件生成与导出
目录 一、准备工作 1. 安装 iTextSharp 2. 准备资源文件 二、创建 ExportPDFTool 脚本 1、初始化 PDF 文件,设置字体 2、添加标题、内容、表格和图片 三、使用工具类生成 PDF 四、源码地址 在 Unity 项目中,我们有时会需要生成带有文本、表格和图片的 PDF 文件,以便…...
Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...
【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
