Django
# 安装virtualenv(windows)
pip install virtualenv virtualenvwrapper-win
# worken 查看虚拟环境
workon
# mkvirtualenv 创建新的虚拟环境
mkvirtualenv env
# rmvirtualenv 删除虚拟环境
# rmvirtualenv env
# 进入虚拟环境
workon env
# 退出虚拟环境
deactivate
1. 创建虚拟环境
# 创建虚拟环境
mkvirtualenv djangoenv
# 进入虚拟环境
workon djangoenv
(djangoenv) C:\Users\28911>
2. 安装Django
# 4.2是LTS长期支持版本
pip install Django==4.2 -i https://pypi.tuna.tsinghua.edu.cn/simple
# 测试Django是否安装成功
pip show django
# 成功
(djangoenv) C:\Users\28911>pip show django
Name: Django
Version: 4.2 # 版本
Summary: A high-level Python web framework that encourages rapid development and clean, pragmatic design.
Home-page: https://www.djangoproject.com/
Author: Django Software Foundation
Author-email: foundation@djangoproject.com
License: BSD-3-Clause
Location: D:\Virtualenvs\djangoenv\Lib\site-packages
Requires: asgiref, sqlparse, tzdata # 依赖包
Required-by:
# pip freeze
(djangoenv) C:\Users\28911>pip freeze
asgiref==3.8.1
Django==4.2
sqlparse==0.5.0
tzdata==2024.1
# pip list :查看所有的包
(djangoenv) C:\Users\28911>pip list
Package Version
-------- -------
asgiref 3.8.1
Django 4.2
pip 24.1.2
sqlparse 0.5.0
tzdata 2024.1
3. 创建一个Django项目
- 方式 1:进入到指定要存放项目的目录,执行django-admin startproject DjangoPro1来创建一个名字为DjangoPro1的工程
- 方式 2:使用Pycharm专业版创建DJango项目
4. 测试服务器的启动
python manage.py runserver [ip:port]
# 默认端口8000
# 也可以自己指定ip和端口:
# 1. 监听机器所有可用 IP(电脑可能有多个内网IP或多个外网IP)
python manage.py runserver 0.0.0.0:8000
# 2. 同时在settings.py中将
ALLOWED_HOSTS=['*']
# 3. 在其他局域网电脑上可以通过在浏览器中输入 Django项目所在电脑 IP:8000 访问
5. 数据迁移
迁移的概念:就是将模型映射到数据库的过程
生成迁移文件:
python manage.py makemigrations
执行迁移:
python manage.py migrate
不需要初始化迁移文件夹,每个应用默认有迁移文件夹migrations
6. 创建应用
python manage.py startapp App
创建名称为App的应用
使用应用前需要应用配置到项目中,在settings.py中将应用加入到INSTALLED_APPS选项中
应用目录介绍:
_ init_.py:
其中暂无内容,使得app成为一个包
admin.py:
管理站点模型的声明文件,默认为空
apps.py:
应用信息定义文件,在其中生成了AppConfig,该类用于定义应用名等数据
models.py:
添加模型层数据类文件
views.py:
定义URL相应函数,视图函数
migrations包:
自动生成,生成迁移文件的
test.py:
测试代码文件
7. 基本视图
视图函数
8. 基本模板
模板实际上就是我们用HTML写好的页面
创建模板文件夹templates,在模板文件夹中创建模板文件
在views中去加载渲染模板,使用render函数:return render(request, ‘index.html’)
9. 定义模型
在models.py中引入models
from django.db import models
创建自己的模型类,但切记要继承自 models.Model
class UserModel(models.Model):
name = models.CharField(max_length=30, unique=True) # 对应的SQL:name varchar(30)
age = models.IntegerField(default=18) # 对应的SQL:age int default 18
sex = models.CharField(max_length=20) # 对应的SQL:sex varchar(20)
is_delete = models.BooleanField(default=False) # 对应的SQL:is_delete Boolean
10. Admin后台管理
在admin.py中将model加入后台管理:
admin.site.register(UserModel)
创建超级用户:python manage.py createsuperuser
访问admin后台:http://127.0.0.1:8000/admin/
Django路由
路由的分发:主路由转发到各个应用路由的过程
1. 路由匹配
# 使用url给视图函数传参数
path('index/', index)
path('detail/<int:id>/', detail)
# 给url取别名,那么在使用此url的地方可以使用别名
path('index/', index, name='index')
path('detail/<int:id>/', detail, name='detail')
reverse('index') <==> 'index/'
2. 命名空间
为了防止路由冲突,Django提供了命名空间的概念:命名空间是一种将路由命名为层次结构的方式,使得在查询路由时可以限定在该命名空间内。
# 使用命名空间
path('user/', include(('App.urls', 'App'), namespace='App'))
3. 反向解析
Django路由反向解析是一个非常重要的功能,它可以让我们在代码中使用路由别名替代URL路径,在修改URL时避免代码中的硬编码依赖,同时也可以提高可读性和可维护性。
#在视图函数中反向解析url
from django.shortcuts import render, redirect, reverse
# 重定向
def my_redirect(request):
# return redirect('https://www.baidu.com')
# return redirect('/user/userlist/')
# return redirect('/user/detail/2/')
# 反向解析 带命名空间
# return redirect(reverse('App:userdetail', args=(1,))) # 位置参数传参
return redirect(reverse('App:userdetail', kwargs={'uid': 1})) # 关键字传参
# 不带命名空间
# return redirect(reverse('userdetail', kwargs={'uid': 1}))
4. 传参
path('detail/<int:uid>/', user_detail, name='userdetail'),
def user_detail(request, uid):
user = UserModel.objects.get(pk=uid)
return render(request, 'user_detail.html', {'user': user})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户详情</title>
</head>
<body>
<h2>用户详情</h2>
<hr>
<h3>{{ user.name }} - {{ user.age }}</h3>
</body>
</html>
Django模板
模板Template
在Django框架中,模板是可以帮助开发者快速生成呈现给用户页面的工具
模板的设计方式实现了我们 MVT 中 VT 的解耦**(M:Model,V:View,T:Template)**,VT有着 N : M 的关系,一个V可以调用任意个T,一个T可以被任意个V使用。
模板处理分为两个过程
-
加载HTML
-
渲染数据
模板主要有两个部分
-
HTML静态代码
-
模板语言,动态插入的代码段
模板中的动态代码段除了做基本的静态填充,还可以实现一些基本的运算,转换和逻辑
静态页面:页面数据是本地固定的
动态页面:页面数据来源于后台服务器
模板中的变量:视图传递给模板的数据,遵守标识符规则
语法:{{ var }}
如果变量不存在,则插入空字符串
方法不能有参数
- {{ str }}
- {{ str.upper }}
- {{ str.isdigit }}
- {{ dict.key }}
列表,使用索引,不允许负索引
items = [‘apples’, ‘bananas’, ‘carrots’]
{{ items.2 }}
模板中的标签
语法:{{% tag %}}
作用:
- 加载外部传入的变量
- 在输出中创建文本
- 控制循环或逻辑
if 语句
if单分支:
{% if 表达式 %}
语句
{% endif %}
if双分支:
{% if 表达式 %}
语句
{% else %}
语句
{% endif %}
if多分枝:
{% if 表达式 %}
语句
{% elif %}
语句
{% else %}
语句
{% endif %}
判断true或false:
{% if today_is_weekend %}
<p>Welcome to the weekend!</p>
{% endif %}
使用 and or not
使用 in和not in
{% if "bc" in "abcdefg" %}
语句
{% endif %}
for 语句
{% for 变量 in 列表 %}
语句
{% empty %}
语句
{% endfor %}
当列表为空或不存在时,执行empty之后的语句
{{ forloop.counter }} 表示当前是第几次循环,从1开始
{% for item in todo_list %}
<p>{{ forloop.counter }}:{{ item }}</p>
{% endfor %}
{{ forloop.counter0 }} 表示当前是第几次循环,从0开始
{{ forloop.revcounter }} 表示当前是第几次循环,倒着数,到1停
{{ forloop.revcounter0 }} 表示当前是第几次循环,倒着数,到0停
{{ forloop.first }} 是否是第一个,返回布尔值
{{ forloop.last }} 是否是最后一个,返回布尔值
{{ forloop.parentloop }} 如果有多个循环嵌套,那么这个属性代表的是上一级的for循环
多行注释
{% comment %}
内容
{% endcomment %}
过滤器
{{ var|过滤器 }}
作用:在变量显示前修改
add
{{ value|add:2 }}
没有减法过滤器,但是可以加负数
{{ value|add:-2 }}
lower
{{ name|lower }}
upper
{{ my_list|upper }}
截断(从第10个字符开始显示...)(只显示前9个字符):
{{ bio|truncatechars:10 }}
过滤器可以传递参数,参数需要使用引号引起来
比如:join: {{ students|join:"="}}
默认值:default,格式{{ var|default:value }}
如果变量值没有被提供或者为false,空,会使用默认值
根据指定格式转换日期为字符串,针对date进行转换
{{ dateVal | date:'y-m-d' }}
解析html
'code': '<b>I am a good man!</b>'
{{ code|safe }}
I am a good man!
# 模板中开启自动转义(默认开启),那么就会显示成一个普通的字符串
{% autoescape on %}
<a href='www.baidu.com'>百度</a>
{% endautoescape %}
# 如果把on成off,那么就会显示百度的一个超链接
{% autoescape off %}
<a href='www.baidu.com'>百度</a>
{% endautoescape %}
模板继承
block:
{% block xxx %}
代码
{% endblock %}
extends继承(写在开头位置):
{% extends '父模板路径' %}
include:加载模板进行渲染
{% include '模板文件' %}
{{ block。supper }}:获取父模板中block中的内容
在Django项目中使用Jinja2
Jinja2是Flask框架中的模板引擎,是模仿Django默认模板引擎基础上开发的,比Django模板引擎性能好,功能更全。
1. 安装jinja2模块
pip install jinja2
检查是否已经安装Jinja2
pip freeze
2. 创建jinja2_env.py文件
在settings.py所在目录中创建jinja2_env.py文件,并写入以下内容
from django.templatetags.static import static
from django.urls import reverse
from jinja2 import Environment
def environment(**options):
env = Environment(**options)
env.globals.update({
'static': static,
'url': reverse,
})
return env
settings.py
TEMPLATES = [
# 使用jinja2模板引擎
{
'BACKEND': 'django.template.backends.jinja2.Jinja2'
,
'DIRS': [BASE_DIR / 'templates']
,
'APP_DIRS': True,
'OPTIONS': {
# 这里要添加environment,并且指定到jinja2_env文件中的environment
'environment': 'DjangoPro2.jinja2_env.environment',
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates']
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h2>Jinja2模板引擎</h2>
<p>{{ name }}</p>
<hr>
{% for n in name %}
<div>
{{ loop.index }}:{{ n }}
</div>
{% endfor %}
{# Jinja2 可以调用函数 #}
{% for i in range(1,5) %}
<div>
{{ i }}
</div>
{% endfor %}
</body>
</html>
Django配置MySQL
settings.py
DATABASES = {
# 配置MySQL
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django_mysql',
'USER': 'root',
'PASSWORD': '1234',
'HOST': '127.0.0.1',
'PORT': '3306',
}
}
SQLalchemy
SQLAlchemy是Python SQL工具包和对象关系映射器,是python中最著名的ORM(Object Relationship Mapping)框架,它简化了应用程序开发人员在原生SQL上的操作,使开发人员将主要精力都放在程序逻辑上,从而提高开发效率。它提供了一整套著名的企业级持久性模式,设计用于高效和高性能的数据库访问。
使用ORM操作数据库:
优势 :代码易读,隐藏底层原生SQL语句,提高了开发效率。
劣势 :执行效率低 ,将方法转换为原生SQL后 原生SQL不一定是最优的
连接数据库
from sqlalchemy import create_engine
# 连接数据库
# create_engine方法用于创建一个数据库连接对象
# 数据库类型+数据库驱动://用户名:密码@主机名:端口号/数据库名
engine = create_engine('mysql://root:1234@localhost:3306/sql_test')
原生SQL查询
import sqlalchemy
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import *
engine = create_engine('mysql://root:1234@localhost:3306/mp')
conn = engine.connect()
query = sqlalchemy.text('SELECT * FROM user limit 5')
result_set = conn.execute(query)
for row in result_set:
print(row)
conn.close()
engine.dispose()
创建表
import sqlalchemy
engine = sqlalchemy.create_engine('mysql://root:1234@localhost:3306/mp', echo=True)
meta_data = sqlalchemy.MetaData()
person = sqlalchemy.Table(
'person', meta_data,
sqlalchemy.Column('id', sqlalchemy.Integer, primary_key=True),
sqlalchemy.Column('name', sqlalchemy.String(20), nullable=False),
sqlalchemy.Column('age', sqlalchemy.Boolean, default=False, nullable=False)
)
meta_data.create_all(engine)
插入数据
插入单条记录
import sqlalchemy
engine = sqlalchemy.create_engine('mysql://root:1234@localhost:3306/mp', echo=True)
meta_data = sqlalchemy.MetaData()
person = sqlalchemy.Table(
'person', meta_data,
sqlalchemy.Column('id', sqlalchemy.Integer, primary_key=True),
sqlalchemy.Column('name', sqlalchemy.String(20), nullable=False),
sqlalchemy.Column('age', sqlalchemy.String(3), default=18, nullable=False)
)
meta_data.create_all(engine)
# insert a record
person_insert = person.insert()
print(person_insert)
insert_sql = person_insert.values(name='John', age=20)
with engine.connect() as conn:
conn.execute(insert_sql)
conn.commit()
engine.dispose()
插入多条记录
import sqlalchemy
engine = sqlalchemy.create_engine('mysql://root:1234@localhost:3306/mp', echo=True)
meta_data = sqlalchemy.MetaData()
person = sqlalchemy.Table(
'person', meta_data,
sqlalchemy.Column('id', sqlalchemy.Integer, primary_key=True),
sqlalchemy.Column('name', sqlalchemy.String(20), nullable=False),
sqlalchemy.Column('age', sqlalchemy.String(3), default=18, nullable=False)
)
meta_data.create_all(engine)
person_insert = person.insert()
with engine.connect() as conn:
conn.execute(person_insert, [
{'name': 'Jack', 'age': 23},
{'name': 'rous', 'age': 20},
{'name': 'Yohan', 'age': 21},
])
conn.commit()
engine.dispose()
映射
from sqlalchemy import create_engine, Column, Integer, String, Date
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
engine = create_engine('mysql://root:1234@localhost:3306/testdb?charset=utf8', echo=True)
Base = declarative_base()
class Person(Base):
__tablename__ = 'person'
id = Column(Integer, primary_key=True)
name = Column(String(20), unique=True, nullable=False)
birthday = Column(Date, nullable=False)
address = Column(String(50), nullable=False)
def __str__(self):
return f'{{Person: id:{self.id}, name:{self.name}, birthday:{self.birthday}, address:{self.address}}}'
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
新的映射
from datetime import date, datetime
from typing import Annotated
from sqlalchemy import create_engine, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Mapped, mapped_column
from sqlalchemy.sql import func
engine = create_engine('mysql://root:1234@localhost:3306/testdb?charset=utf8', echo=True)
Base = declarative_base()
# 避免代码重复 对部分进行抽象提取
int_pk = Annotated[int, mapped_column(primary_key=True)]
required_unique_name = Annotated[str, mapped_column(String(20), unique=True, nullable=False)]
timestamp_default = Annotated[datetime, mapped_column(nullable=False, server_default=func.now())]
class Customer(Base):
__tablename__ = 'customer'
# id: Mapped[int] = mapped_column(primary_key=True)
# name: Mapped[str] = mapped_column(String(20), unique=True, nullable=False)
# birthday: Mapped[date]
id: Mapped[int_pk]
name: Mapped[required_unique_name]
birthday: Mapped[date]
city: Mapped[str] = mapped_column(String(20), nullable=True)
create_time: Mapped[timestamp_default]
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
ORM映射
from datetime import datetime, date
from typing import List
from sqlalchemy import create_engine, String, func, ForeignKey
from sqlalchemy.orm import declarative_base, Mapped, mapped_column, sessionmaker, relationship
from typing_extensions import Annotated
engine = create_engine('mysql://root:1234@localhost:3306/testdb?charset=utf8', echo=True)
Base = declarative_base()
int_pk = Annotated[int, mapped_column(primary_key=True)]
required_unique_name = Annotated[str, mapped_column(String(20), unique=True, nullable=False)]
timestamp_not_null = Annotated[datetime, mapped_column(server_default=func.now(), nullable=False)]
class Department(Base):
__tablename__ = 'department'
id: Mapped[int_pk]
name: Mapped[required_unique_name]
create_time: Mapped[timestamp_not_null]
# 一对多关系用懒惰,避免查一个部门连带查出很多员工的情况降低查询效率
employees: Mapped[List["Employee"]] = relationship(back_populates="department")
def __repr__(self):
return f'{{department: id: {self.id}, name: {self.name}, create_time: {self.create_time}}}'
class Employee(Base):
__tablename__ = 'employee'
id: Mapped[int_pk]
dep_id: Mapped[int] = mapped_column(ForeignKey("department.id"))
name: Mapped[required_unique_name]
birthday: Mapped[date] = mapped_column(nullable=False)
# 定义一个属性 将该属性指向Department对象(relationship():关联关系字段)
# 并不是指向数据库的某个字段 而是指向内存中的对象
# 默认 lazy=True:懒惰的,分开查询。lazy=False:利用join一次查询,效率高
# backref="employees":在department中隐藏(隐式定义关联)
# back_populates="employees":显示定义关联关系,department中也需要写出关联语句与
department: Mapped[Department] = relationship(lazy=False, back_populates="employees")
def __repr__(self):
return f'{{employee: id: {self.id}, dep_id: {self.dep_id}, name: {self.name}, birthday: {self.birthday}}}'
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)