当前位置: 首页 > news >正文

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&#xff0c;添加几个函数 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 标签需要被一个父元素包裹&#xff1f; JSX 虽然看起来很像 HTML&#xff0c;但在底层其实被转化为了 JavaScript 对象&#xff0c;你不能在一个函数中返回多个对象&#xff0c;除非用一个数组把他们包装起来。这就是为什么多个 JSX 标签必须要用一个父元素或者…...

记录日志中logback和log4j2不能共存的问题

本文章记录设置两个日志时候&#xff0c;控制台直接报错 标黄处就是错误原因&#xff1a;1. SLF4J(W)&#xff1a;类路径包含多个SLF4J提供程序。 SLF4J(W)&#xff1a;找到提供程序[org.apache.logging.slf4j. net]。 SLF4J(W)&#xff1a;找到提供程序[ch.qos.log .classi…...

第5章: 图像变换与仿射操作

图像变换和仿射操作是图像处理中常用的技术&#xff0c;通过旋转、缩放、平移、剪裁等操作&#xff0c;可以实现多种视觉效果以及数据增强。 1.1 图像旋转 1.1.1 基础旋转操作 使用 rotate() 方法可以对图像进行旋转操作&#xff0c;指定旋转的角度&#xff08;以度为单位&am…...

【计算机网络】【网络层】【习题】

计算机网络-传输层-习题 文章目录 13. 图 4-69 给出了距离-向量协议工作过程&#xff0c;表&#xff08;a&#xff09;是路由表 R1 初始的路由表&#xff0c;表&#xff08;b&#xff09;是相邻路由器 R2 传送来的路由表。请写出 R1 更新后的路由表&#xff08;c&#xff09;。…...

Scala的不可变Map常用操作

//类型&#xff1a;不可变&#xff0c;可变 //操作&#xff1a;添加元素&#xff0c;删除元素&#xff0c;查询元素&#xff0c;删除元素&#xff0c;遍历 object map {def main(args: Array[String]): Unit {//不可变Mapval map1 Map("鄂"->"湖北省"…...

nginx配置负载均衡详解

在现代的 web 应用中&#xff0c;负载均衡是确保高可用性、可扩展性和稳定性的关键技术之一。Nginx 是一个非常流行的反向代理服务器和负载均衡器&#xff0c;它支持多种负载均衡策略&#xff0c;能够帮助将客户端的请求分发到多个后端服务器&#xff0c;以提高系统的整体性能和…...

传奇996_19——龙岭总结

功能&#xff1a; 切割 切割属性&#xff1a; 即人物属性&#xff0c;可以设置临时属性或者永久属性&#xff0c;龙岭使用的是临时属性&#xff0c;所谓临时就是存在有效期&#xff0c;龙岭设置的有效期是123456789秒&#xff0c;即1428.89802天。 龙岭写法&#xff08;倒叙…...

el-table 行列文字悬浮超出屏幕宽度不换行的问题

修改前的效果 修改后的效果 ui框架 element-plus 在网上找了很多例子都没找到合适的 然后这个东西鼠标挪走就不显示 控制台也不好调试 看了一下El-table的源码 他这个悬浮文字用的el-prpper 包着的 所以直接改 .el-table .el-propper 设置为max-width:1000px 就可以了 吐槽一…...

鸿蒙HarmonyOS 网络请求获取数据Http

注意的是;要为接口返回值指定类型 &#xff0c;以及定义接口数据类型 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技巧之跨服务器数据查询&#xff1a;高级篇-先调用A数据库的MySql存储过程再复制到B数据库的表中 基础篇已经描述&#xff1a;借用微软的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…...

【分布式】万字图文解析——深入七大分布式事务解决方案

分布式事务 分布式事务是指跨多个独立服务或系统的事务管理&#xff0c;以确保这些服务中的数据变更要么全部成功&#xff0c;要么全部回滚&#xff0c;从而保证数据的一致性。在微服务架构和分布式系统中&#xff0c;由于业务逻辑往往会跨多个服务&#xff0c;传统的单体事务…...

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段&#xff0c;指定不同的ServerName、DocumentRoot等参数 <VirtualHost *:80>…...

基于PyQt Python的深度学习图像处理界面开发(一)

Python标准库更多的适合处理后台任务&#xff0c;唯一的图形库tkinter使用起来很不方便&#xff0c;所以后来出现了针对Python图形界面开发的扩展库&#xff0c;例如PyQt。 在介绍PyQt之前&#xff0c;必须先简单介绍一下Qt。Qt是一个C可视化开发平台&#xff0c;是一个跨平台的…...

【Linux网络】Linux网络编程套接字,UDP与TCP

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ ⏩收录专栏⏪&#xff1a;Linux “ 登神长阶 ” &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀Linux网络编程套接字 &#x1f4d2;1. 端口号&#x1f4dc;2. 初识TCP协议与UDP协议&#x1…...

Vue3 -- 强制统一包管理器工具【企业级项目配置保姆级教程6】

引言: 团队开发项目的时候,需要统一包管理器工具,因为不同包管理器工具下载同一个依赖,可能版本不一样,导致项目出现bug问题,因此包管理器工具需要统一管理!!所以就需要我们强制统一包管理器工具。 创建scripts目录和preinstall.js文件: 在根目录创建scritps/preinstal…...

Winform实现自制浏览器JavaScript注入

让我们一起走向未来 &#x1f393;作者简介&#xff1a;全栈领域优质创作者 &#x1f310;个人主页&#xff1a;百锦再新空间代码工作室 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[1504566…...

【工具插件类教学】在 Unity 中使用 iTextSharp 实现 PDF 文件生成与导出

目录 一、准备工作 1. 安装 iTextSharp 2. 准备资源文件 二、创建 ExportPDFTool 脚本 1、初始化 PDF 文件,设置字体 2、添加标题、内容、表格和图片 三、使用工具类生成 PDF 四、源码地址 在 Unity 项目中,我们有时会需要生成带有文本、表格和图片的 PDF 文件,以便…...

javascript用来干嘛的?赋予网站灵魂的语言

javascript用来干嘛的&#xff1f;赋予网站灵魂的语言 在互联网世界中&#xff0c;你所浏览的每一个网页&#xff0c;背后都有一群默默工作的代码在支撑着。而其中&#xff0c;JavaScript就像是一位技艺精湛的魔术师&#xff0c;它赋予了网页生命力&#xff0c;让原本静态的页…...

Flutter Getx状态管理

在 Flutter 开发中&#xff0c;状态管理是一个非常重要的话题。随着应用变得更加复杂&#xff0c;状态管理的方式也变得越来越多。Flutter 提供了多种状态管理的解决方案&#xff0c;如 Provider、Riverpod、BLoC 等&#xff0c;而在这些选项中&#xff0c;GetX 作为一个轻量级…...

《成法》读书笔记

稻盛和夫的《成法》是一部关于个人和企业成功哲学的作品&#xff0c;结合了他在经营京瓷和KDDI&#xff0c;以及重建日航&#xff08;JAL&#xff09;过程中的经验和智慧。 以下是这本书的读书笔记&#xff0c;涵盖其核心思想和重要概念&#xff1a; 1. 以“心”为本 内容概…...

TensorFlow 2.0 环境配置

官方文档&#xff1a;CUDA Installation Guide for Windows 官方文档有坑&#xff0c;windows的安装指南直接复制了linux的指南内容&#xff1a;忽略这些离谱的信息即可。 可以从官方文档知悉&#xff0c;cuda依赖特定版本的C编译器。但是我懒得为了一个编译器就下载整个visua…...

Ekman理论回归

Scientific reportsEkman revisited: Surface currents to the left of the winds in the Northern HemisphereVagn Walfrid Ekman1905年的理论描述了地球旋转受到风的作用&#xff0c;摩擦边界层中的流场&#xff0c;北半球总是在海表风的右侧&#xff0c;南半球总是在海表风的…...

算法演练----24点游戏

给定4个整数&#xff0c;数字范围在1~13之间任意使用-*/&#xff08;&#xff09;&#xff0c;构造出一个表达式&#xff0c;使得最终结果为24&#xff0c; 方法一 算法分析&#xff1a;加括号和取出重复表达式 # 导入精确除法模块&#xff0c;使得在Python2中除法运算的行为更…...

【学习心得】Python好库推荐——tiktoken

一、tiktoken是什么&#xff1f; tiktoken是一个快速BPE分词器&#xff0c;是由 OpenAI 开发的一个用于文本处理的 Python 库&#xff0c;主要用于将文本编码为数字序列&#xff08;称为 "tokens"&#xff09;&#xff0c;或将数字序列解码为文本。这一过程被称为 &q…...

MacBook不额外安装软件,怎样投屏到安卓手机上?

提起iPhone或MacBook的投屏&#xff0c;人们总会想到airplay功能。但离开了苹果生态&#xff0c;其他品牌的手机电脑就未必配备airplay功能了。 如果想要将MacBook的电脑屏幕共享到安卓手机或平板上&#xff0c;到底要怎样做&#xff1f;需要安装什么软件吗&#xff1f; 不需要…...

flink sql + kafka + mysql 如何构建实时数仓

构建一个基于 Flink SQL、Kafka 和 MySQL 的实时数据仓库(Data Warehouse)架构,可以通过流处理的方式实现高效、实时的数据集成与分析。以下是如何利用这三者构建实时数仓的步骤与实现: 架构概述 Kafka:作为流数据平台,负责接收和传输来自不同源系统(如应用日志、传感器…...

Go语言开发基于SQLite数据库实现用户表查询详情接口(三)

背景 上一章 Go语言开发基于SQLite数据库实现用户表新增接口(二) 这一章我们实现用户表的查询详情接口 代码实现 mapper层 type UserMapper interface {GetById(id uint64) (*model.User, error)}type userMapper struct { }func (m *userMapper) GetById(id uint64) (*mod…...