Django基础用法+Demo演示

news2024/11/17 13:59:25

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 models

class 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")
    # POST
    username = 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")
    # POST
    title = 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})
    # POST
    title = 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.UserInfo
        fields = ["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})

    # POST
    user = 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})
    # POST
    pretty = 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) * 10
            end = page * 10
            prettys = 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.Admin
        fields = "__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.Admin
        fields = ["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})
    # POST
    form = 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})

        # 保存Session
        request.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, redirect

class AuthMiddleWare(MiddlewareMixin):
    def process_request(self, request):
        # 注意:对于无需登录就应该访问的页面,不要做鉴权,否则会循环重定向
        if request.path_info == "/login/":
            return

        info_dict = request.session.get("info")
        print(info_dict)
        if info_dict:
            return
        return redirect("/login/")
		
    def process_response(self,request, response):
        print('M1 gone')
        return response

settings.py

MIDDLEWARE = [
	'app01.middleware.auth.M1',
	'app01.middleware.auth.M2',
]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2242203.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

蓝桥杯-洛谷刷题-day3(C++)

目录 1.忽略回车的字符串输入 i.getline() ii.逐个字符的识别再输入 2.获取绝对值abs() 3.做题时的误区 4.多个变量的某一个到达判断条件 i.max() 5.[NOIP2016 提高组] 玩具谜题 i.代码 6.逻辑上的圆圈 i.有限个数n的数组 7.数组的定义 i.动态数组 1.忽略回车的字符串输…

Redis在高性能缓存中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 Redis在高性能缓存中的应用 Redis在高性能缓存中的应用 Redis在高性能缓存中的应用 引言 Redis 概述 定义与原理 发展历程 Redi…

AOP实现上下游泳道隔离RPC调用

在平时代码项目代码测试的过程中&#xff0c;“隔离”思想就经常被用上&#xff0c;比方说多个并行开发的需求都需要用到服务 A 的能力&#xff0c;但是又需要同时部署 A 不同的代码分支&#xff0c;这个时候“泳道隔离”机制就显得尤为重要了。“泳道隔离”即将相同代码仓库的…

TCP/IP--Socket套接字--JAVA

一、概念 Socket套接字&#xff0c;是由系统提供⽤于⽹络通信的技术&#xff0c;是基于TCP/IP协议的⽹络通信的基本操作单元。 基于Socket套接字的⽹络程序开发就是⽹络编程。 二、分类 1.流套接字 使用传输层TCP协议。TCP协议特点&#xff1a;有链接、可靠传输、面向字节流…

号卡分销系统,号卡系统,物联网卡系统源码安装教程

号卡分销系统&#xff0c;号卡系统&#xff0c;物联网卡系统&#xff0c;&#xff0c;实现的高性能(PHP协程、PHP微服务)、高灵活性、前后端分离(后台)&#xff0c;PHP 持久化框架&#xff0c;助力管理系统敏捷开发&#xff0c;长期持续更新中。 主要特性 基于Auth验证的权限…

平衡二叉搜索树之 红黑 树的模拟实现【C++】

文章目录 红黑树的简单介绍定义红黑树的特性红黑树的应用 全部的实现代码放在了文章末尾准备工作包含头文件类的成员变量和红黑树节点的定义 构造函数和拷贝构造swap和赋值运算符重载析构函数findinsert【重要】第一步&#xff1a;按照二叉搜索树的方式插入新节点第二步&#x…

线性数据结构

数组 数组&#xff08;Array&#xff09; 是一种很常见的数据结构。它由相同类型的元素&#xff08;element&#xff09;组成&#xff0c;并且是使用一块连续的内存来存储。 我们直接可以利用元素的索引&#xff08;index&#xff09;可以计算出该元素对应的存储地址。 数组…

GoFly框架使用vue flow流程图组件说明

Vue Flow组件库是个高度可定制化的流程图组件&#xff0c;可用于工作流设计、流程图及图表编辑器、系统架构展示。可以根据自己的需求&#xff0c;设计独特的节点和边&#xff0c;实现个性化的流程图展示。这不仅增强了应用的视觉效果&#xff0c;也使得用户交互更为直观和流畅…

MySQL数据库:SQL语言入门 【2】(学习笔记)

目录 2&#xff0c;DML —— 数据操作语言&#xff08;Data Manipulation Language&#xff09; &#xff08;1&#xff09;insert 增加 数据 &#xff08;2&#xff09;delete 删除 数据 truncate 删除表和数据&#xff0c;再创建一个新表 &#xff08;3&#xf…

“南海明珠”-黄岩岛(民主礁)领海基线WebGIS绘制实战

目录 前言 一、关于岛屿的基点位置 1、领海基点 二、基点坐标的转换 1、最底层的左边转换 2、单个经纬度坐标点转换 3、完整的转换 三、基于天地图进行WebGIS展示 1、领海基点的可视化 2、重要城市距离计算 四、总结 前言 南海明珠黄岩岛&#xff0c;这座位于南海的…

19.UE5道具掉落

2-21 道具掉落&#xff0c;回血、回蓝、升级提升伤害_哔哩哔哩_bilibili 目录 1.道具的创建&#xff0c;道具功能的实现 2.随机掉落 1.道具的创建&#xff0c;道具功能的实现 新建Actor蓝图&#xff0c;并命名为道具总类&#xff0c;添加一个Niagara粒子组件和一个碰撞箱bo…

Cartographer激光雷达slam -20241116

Cartographer Cartographer代码结构 cartographer&#xff1a;负责处理来自雷达、IMU和里程计的数据并基于这些数据进行地图的构建&#xff0c;是cartographer理论的底层实现cartographer_ros&#xff1a;基于ros的通信机制获取传感器的数据并将它们转换成cartographer中定义…

node.js学习笔记-Window下MongoDB数据库安装(二)

一、介绍 MongoDB 是一个基于分布式文件存储的开源数据库系统&#xff0c;在当前的软件开发和数据存储领域中应用广泛&#xff0c;以下是对 MongoDB 的详细介绍&#xff1a; 文档型数据库&#xff1a;MongoDB 以 BSON&#xff08;Binary JSON&#xff09;格式存储数据&#x…

STM32G4的数模转换器(DAC)的应用

目录 概述 1 DAC模块介绍 2 STM32Cube配置参数 2.1 参数配置 2.2 项目架构 3 代码实现 3.1 接口函数 3.2 功能函数 3.3 波形源代码 4 DAC功能测试 4.1 测试方法介绍 4.2 波形测试 概述 本文主要介绍如何使用STM32G4的DAC模块功能&#xff0c;笔者使用STM32Cube工具…

【论文复现】轻松利用自适应特征融合实现去雾

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀ 智慧医疗 介绍创新点网络结构特征提取阶段自适应融合阶段图像重建阶段上下文增强模块CEM特征融合模块AFM 结果分析 提示 论文题目&#xff1…

常用在汽车PKE无钥匙进入系统的高度集成SOC芯片:CSM2433

CSM2433是一款集成2.4GHz频段发射器、125KHz接收器和8位RISC&#xff08;精简指令集&#xff09;MCU的SOC芯片&#xff0c;用在汽车PKE无钥匙进入系统里。 什么是汽车PKE无钥匙进入系统&#xff1f; 无钥匙进入系统具有无钥匙进入并且启动的功能&#xff0c;英文名称是PKE&…

《TCP/IP网络编程》学习笔记 | Chapter 11:进程间通信

《TCP/IP网络编程》学习笔记 | Chapter 11&#xff1a;进程间通信 《TCP/IP网络编程》学习笔记 | Chapter 11&#xff1a;进程间通信进程间通信的基本概念通过管道实现进程间通信通过管道进行进程间双向通信 运用进程间通信习题&#xff08;1&#xff09;什么是进程间通信&…

计算机网络各层设备总结归纳(更新ing)

计算机网络按照OSI&#xff08;开放式系统互联&#xff09;模型分为七层&#xff0c;每一层都有其特定的功能和对应的网络设备。以下是各层对应的设备&#xff1a; 1. 物理层&#xff08;Physical Layer) 设备&#xff1a;中继器&#xff08;Repeater&#xff09;、集线器…

在kile 5中一个新工程的创建

这两天博主学习到了在kile5中创建一个工程&#xff0c;当然博主不会忘了小伙伴们的&#xff0c;这就和你们分享。 本次创建以STM32F103C8为例 创建过程&#xff1a; 1首先创建文件 名字随意&#xff0c;但也不要太随意&#xff0c;因为是外国软件&#xff0c;所以多少对中文…

AI写作(十)发展趋势与展望(10/10)

一、AI 写作的崛起之势 在当今科技飞速发展的时代&#xff0c;AI 写作如同一颗耀眼的新星&#xff0c;迅速崛起并在多个领域展现出强大的力量。 随着人工智能技术的不断进步&#xff0c;AI 写作在内容创作领域发挥着越来越重要的作用。据统计&#xff0c;目前已有众多企业开始…