ⅠDjango链接数据库
- 默认的Django数据库是 sqlite3
- 链接MySQL数据库 ---> 电脑上则会运行MySQL
【一】下载数据库
【二】在settings.py设置定义参数
# 链接MySQL数据库
DATABASES = {
'default': {
# 指定我们使用的引擎是 mysql 数据库的引擎
'ENGINE': 'django.db.backends.mysql',
# 我们需要配置MySQL数据库的参数
# NAME 就是你要链接的数据库名字
# 'NAME': BASE_DIR / 'db.sqlite3',
# MySQL服务器的IP - HOST
"HOST": "127.0.0.1",
# MySQL服务器的PORT
"PORT": 3306,
# MySQL服务器的USERNAME
"USER": "root",
# MySQL服务器的PASSWORD
"PASSWORD": "123456",
# MySQL服务器的 数据库名字 NAME
# create database django001;
"NAME": "django001",
# MySQL服务器的CHARSET
"CHARSET": "utf8mb4"
}
}
【三】一启动就会报错
# 【遇到报错】
# django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module.
# Did you install mysqlclient?
【1】解决办法一:打猴子补丁
# 将下面的代码放在任意文件夹 下的 __init__.py 文件中
import pymysql
pymysql.install_as_MySQLdb()
【2】解决办法二:借助第三方模块 mysqlclient
pip install mysqlclient
- 具体看上一篇文章最后
Ⅱ ORM迁移数据库
【一】什么是ORM
- ORM是一种将对象与关系型数据库之间的映射的技术,主要实现了以下三个方面的功能:
- 数据库中的表映射为Python中的类
- 数据库中的字段映射为Python中的属性
- 数据库中的记录映射为Python中的实例
- ORM的主要优点是可以减少开发人员编写重复的SQL语句的时间和工作量,并且可以减少由于SQL语句的调整和更改所带来的错误。
【二】Django ORM的优点
- 与其他ORM框架相比,Django ORM拥有以下优点:
- 简单易用:Django ORM的API非常简单,易于掌握和使用。
- 丰富的API:Django ORM提供了丰富的API来完成常见的数据库操作,如增删改查等,同时也支持高级查询和聚合查询等操作。
- 具有良好的扩展性:Django ORM可以与其他第三方库进行无缝集成,如Django REST framework、Django-Oscar等。
- 自动映射:Django ORM支持自动映射,开发者只需要定义数据库表的结构,就可以自动生成相应的Python类,从而减少开发过程中的重复代码量。
【三】创建数据库模型表
【1】定义模型表
- 在每个 app 下面的 models.py 中定义模型表字段 --- MySQL 表
- 每一个变量 对应 MySQL中的字段
from django.db import models
# Create your models here.
# 定义模型类 类名默认即表名,但是后面可以自定义表名
class User(models.Model):
# 定义表字段,当前字段名为 username , 当前字段类型为字符串类型 , 当前字段约束为最多20个字符
username = models.CharField(max_length=20)
# 定义表字段,当前字段名为 password , 当前字段类型为字符串类型 , 当前字段约束为最多20个字符
password = models.CharField(max_length=20)
from django.db import models
# 详细
# 定义模型表的类名
# 类名不一定是你的数据库中的表名
# 创建一个用户表
# 用户名 varchar 字符串 32
# 密码 varchar 字符串 28
# 年龄 int 数字类型 4
# 创建一个类 继承 models.Model
class UserInfo(models.Model):
# 定义每一个字段 以及 字段类型
# max_length 字符串的最大长度
# verbose_name 注解
username = models.CharField(max_length=32, verbose_name="用户名")
password = models.CharField(max_length=28, verbose_name="密码")
age = models.IntegerField(verbose_name="年龄")
【2】数据库迁移
- 创建表
(1)生成迁移文件
- 将操作记录记录在migrations文件夹
- 在你的 app 下面的 migrations 里面就会出现文件 initial.py
- 虽然文件夹内有相关文件,但是此时并没有同步到数据库中,所以数据库是没有数据的
- manage.py 执行相关命令
- 将你定义的Django模型表转换为 SQL 语句
- 方式有两种
- 一种是 task 任务里面
- 一种是命令行
python manage.py makemigrations
(2)迁移记录生效
- 将操作同步到真正的数据库
- SQL 语句 写入到数据库中
python manage.py migrate
(3)提醒
- 只要修改了models中有关数据库相关的代码,就必须执行上面的数据库迁移命令
【3】数据库数据错乱
# 你发现数据库中的某个表数据错乱了!
# 错乱就把数据库删了 ---> 重新建库 ---> 但是库里面的所有数据就都没了
# 把你 migrations 下面的所有迁移记录删掉
# __init__.py 千万别删
# 重新执行 两条命令
# 数据库中的表就出来了
【四】数据库字段及属性
【1】没有创建ID 但是迁移有ID
- 在settings.py文件最下方
- DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
- Django的默认机制就是如果你的表没有创建ID字段,默认帮你加一个 ID 字段
- 如果自己创建了ID字段 那就用你自己的ID字段
【2】CharField 字符串类型字段
# max_length 字符串的最大长度
# verbose_name 注解
username = models.CharField(max_length=32, verbose_name="用户名")
【3】IntegerField 数字类型字段
# verbose_name 注解
age = models.IntegerField(verbose_name="年龄")
【4】加约束条件
(1)允许为空
- 在定义模型类的相应字段时,可以为该字段添加 null=True 属性以允许其值为 None 或空字符串。
# null=False 不允许为空 (默认)
# null=True 允许为空
class UserInfo(models.Model):
# 定义每一个字段 以及 字段类型
# max_length 字符串的最大长度
# verbose_name 注解
username = models.CharField(max_length=32, verbose_name="用户名")
password = models.CharField(max_length=28, verbose_name="密码", null=True)
age = models.IntegerField(verbose_name="年龄") # 允许password字段为空
每次修改关于数据库字段的操作时,都要执行数据库的迁移相关操作
python manage.py makemigrations
python manage.py migrate
(2)指定默认值
- 设置字段的默认值可通过在字段定义时附加 default 参数实现。例如,给字段 gender设置默认性别为1代表男生
from django.db import models
# 创建一个用户表
# 用户名 varchar 字符串 32
# 密码 varchar 字符串 28
# 年龄 int 数字类型 4
# 创建一个类 继承 models.Model
class UserInfo(models.Model):
# 定义每一个字段 以及 字段类型
# max_length 字符串的最大长度
# verbose_name 注解
username = models.CharField(max_length=32, verbose_name="用户名")
password = models.CharField(max_length=28, verbose_name="密码", null=True)
age = models.IntegerField(verbose_name="年龄")
gender = models.BooleanField(verbose_name="男或女",default=1) # 默认性别为1代表男生
每次修改关于数据库字段的操作时,都要执行数据库的迁移相关操作
python manage.py makemigrations
python manage.py migrate
【5】字段增加
- 要在 Django 模型表中增加新的字段,只需在相应的 Model 类中添加新字段及其类型和所需属性。
- 直接在原本的模型表上增加 BooleanField 字段
from django.db import models
# 创建一个用户表
# 用户名 varchar 字符串 32
# 密码 varchar 字符串 28
# 年龄 int 数字类型 4
# 创建一个类 继承 models.Model
class UserInfo(models.Model):
# 定义每一个字段 以及 字段类型
# max_length 字符串的最大长度
# verbose_name 注解
username = models.CharField(max_length=32, verbose_name="用户名")
password = models.CharField(max_length=28, verbose_name="密码", null=True)
age = models.IntegerField(verbose_name="年龄")
gender = models.BooleanField(verbose_name="男或女",default=1)
每次修改关于数据库字段的操作时,都要执行数据库的迁移相关操作
python manage.py makemigrations
python manage.py migrate
【6】字段删除
- 要从模型表中删除字段,请直接在 Model 类中注释掉该字段或者将其完全移除。
- 不过,在生产环境中删除字段前请确保不会影响现有数据,因为这可能导致数据丢失或结构不一致。
from django.db import models
# 创建一个用户表
# 用户名 varchar 字符串 32
# 密码 varchar 字符串 28
# 年龄 int 数字类型 4
# 创建一个类 继承 models.Model
class UserInfo(models.Model):
# 定义每一个字段 以及 字段类型
# max_length 字符串的最大长度
# verbose_name 注解
username = models.CharField(max_length=32, verbose_name="用户名")
password = models.CharField(max_length=28, verbose_name="密码", null=True)
age = models.IntegerField(verbose_name="年龄")
# gender = models.BooleanField(verbose_name="男或女",default=1)
# 注释掉该字段或者将其完全移除
每次修改关于数据库字段的操作时,都要执行数据库的迁移相关操作
python manage.py makemigrations
python manage.py migrate
【8】重点补充
- 每次修改关于数据库字段的操作时,都要执行数据库的迁移相关操作
python manage.py makemigrations
python manage.py migrate
Ⅲ ORM操作之数据操作
- 在Django框架中 ,Django必须启动起来才能使用Django的ORM 语句
- 很显然不想启动Django ,额外的操作
import os
if __name__ == '__main__':
# 找到 manage.py 复制 main 下面的第一行代码
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'DjangoProjectThree.settings')
# 引入Django模块
import django
# 启动Django项目 --- 一次性的启动项目
# 这里启动Django后我可以通过路由访问到前端页面吗? 不能 因为是一次性启动项目 访问前端页面需要一直保持
django.setup()
# 使用Django的模型表
from user.models import UserInfo
【一】查看数据
【1】获取当前表中的所有数据
- 先在表中增加了一条数据
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'second.settings')
import django
django.setup()
# 使用Django的模型表
from user.models import UserInfo
res_one = UserInfo.objects.all()
print(f'res_one:>>>{res_one}')
# res_one:>>><QuerySet [<UserInfo: UserInfo object (1)>]>
# 返回的是一个列表套对象
【2】获取到指定的数据
(1)一个条件的时候
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'second.settings')
import django
django.setup()
# 使用Django的模型表
from user.models import UserInfo
res_one = UserInfo.objects.filter(username='silence')
print(f'res_one:>>>{res_one}')
# res_one:>>><QuerySet [<UserInfo: UserInfo object (1)>]>
(2)多个条件
- 再增加一条信息
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'second.settings')
import django
django.setup()
# 使用Django的模型表
from user.models import UserInfo
res_one = UserInfo.objects.filter(username='silence', password='741')
print(f'res_one:>>>{res_one}')
# 再增加一个寻找条件
# res_one:>>><QuerySet [<UserInfo: UserInfo object (1)>]>
res_two = UserInfo.objects.filter(username='silence')
print(f'res_one:>>>{res_two}')
# 满足条件的信息有几个拿出来几个
# res_one:>>><QuerySet [<UserInfo: UserInfo object (1)>, <UserInfo: UserInfo object (2)>]>
(3)获取结果
- 再添加一条数据
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'second.settings')
import django
django.setup()
# 使用Django的模型表
from user.models import UserInfo
res_one = UserInfo.objects.filter(username='silence').first()
print(f'res_one:>>>{res_one}')
# res_one:>>>UserInfo object (1)
res_two = UserInfo.objects.filter(username='silence').last()
print(f'res_one:>>>{res_two}')
# res_one:>>>UserInfo object (2)
# 根据username='silence'.first/last条件 判断第一个和在后一个在哪
(4)获取当前用户的数据
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'second.settings')
import django
django.setup()
# 使用Django的模型表
from user.models import UserInfo
res_one = UserInfo.objects.filter(username='silence').first()
print(f'res_one:>>>{res_one}')
print(res_one.username)
print(res_one.password)
print(res_one.age)
# silence
# 741
# 18
【二】增加数据
- Django中操作数据是没有事务这个东西的
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'second.settings')
import django
django.setup()
# 使用Django的模型表
from user.models import UserInfo
res = UserInfo.objects.create(username="silence_01", password="999", age=19)
print(res)
# UserInfo object (4) 返回的是信息插入位置
【三】删除数据
【1】获取到指定的对象后直接删除
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'second.settings')
import django
django.setup()
# 使用Django的模型表
from user.models import UserInfo
# res = UserInfo.objects.create(username="silence_01", password="999", age=19)
# print(res)
# UserInfo object (4) 返回的是信息插入位置
UserInfo.objects.filter(username="silence_01", password="999").delete()
【2】先获取到对象,对象属性在删除
res = UserInfo.objects.get(username="silence_01")
如果这个数据不存在会直接报错 如果存在则直接获取到对象
# UserInfo matching query does not exist.
如果一个条件对应多个数据? get 不出来的
# returned more than one UserInfo -- it returned 2!
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'second.settings')
import django
django.setup()
# 使用Django的模型表
from user.models import UserInfo
# res = UserInfo.objects.create(username="silence_01", password="999", age=19)
# print(res)
# UserInfo object (4) 返回的是信息插入位置
res = UserInfo.objects.get(username="silence_01")
print(res) # UserInfo object (5)
res.delete()
【四】修改数据
【1】先获取对象再删除
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'second.settings')
import django
django.setup()
# 使用Django的模型表
from user.models import UserInfo
user_obj = UserInfo.objects.get(id=2)
print(user_obj) # UserInfo object (2)
user_obj.username = 'jjjjjjjjjjj'
user_obj.age= 999999
# 修改后提交事务!!!
# 修改后提交事务!!!
# 修改后提交事务!!!
user_obj.save()
【2】直接获取或然后删除
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'second.settings')
import django
django.setup()
# 使用Django的模型表
from user.models import UserInfo
res = UserInfo.objects.filter(id=1).update(age=888)
print(res) # 1
Ⅳ Django框架之生命周期流程图
# Django生命周期请求流程图
# 【一】wsgiref 模块 请求周期
# 前端发起请求 ---> wsgiref 模块的 Request 上 ---> 获取 路径 --- urls.py 中映射视图函数
# --- 进入到视图函数中 --- 读取前端模版 / 读取数据库数据 ---- 经过 wsgiref 模块的 response 对象封装
# --- 交给前端页面 渲染数据
# 【二】Django请求声明周期
# 【1】从前端入手 前端发送请求
# 【2】wsgiref 模块上对 Request 进行分装
# 【3】Django框架上 中间件 (相当于你的公司的保安 你的第一道防线)
# 【4】Django框架上的 路由映射 urls.py 去根据路径映射制定的视图函数
# 【5】Django框架上的 视图函数 views.py 中
# (1)获取前端页面 (模版语法渲染)
# (2)读取数据库数据 (增删改查)
# (3)记录你的操作日志 (记录日志)
# 返回 response对象
# 【6】Django框架上的 urls.py 根据制定路径回去
# 【7】回到了 wsgiref 模块上 对Django的 response 对象进行封装
# 【8】回到前端解包渲染
Ⅴ Django框架之路由层
【一】Django的路由系统
【1】什么是URL配置(URLconf)
- URL调度器 | Django 文档 | Django (djangoproject.com)
- URL配置(URLconf)就像Django 所支撑网站的目录。
- 它的本质是URL与要为该URL调用的视图函数之间的映射表。
- 你就是以这种方式告诉Django,对于这个URL调用这段代码,对于那个URL调用那段代码。
【2】基本格式
(1)Django1.x版本语法
from django.conf.urls import url
urlpatterns = [
url(正则表达式, views视图函数,参数,别名),
]
# 自己去书写正则表达式
urlpatterns = [
url(r'^login/', login),
]
(2)Django2.x+版本语法
urlpatterns = [
path('路径', 视图函数),
re_path('正则表达式', 视图函数),
]
- 示例
from django.urls import path
from . import views
urlpatterns = [
path('articles/2003/', views.special_case_2003),
path('articles/<int:year>/', views.year_archive),
path('articles/<int:year>/<int:month>/', views.month_archive),
path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),
]
(3)参数说明
from django.conf.urls import url
urlpatterns = [
path(路径名, views视图函数,参数,别名),
]
- 路径名:
- 在浏览器端口后请求的路径名
- views视图函数:
- 一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
- 参数:
- 可选的要传递给视图函数的默认参数(字典形式)
- 别名:
- 一个可选的name参数
【二】路由匹配 路径参数相似及解决方案
【1】用 path 语法写接口
aaaa 匹配到的是 bbb
- 直接根据路径参数匹配制定的视图函数
# 做了两个视图函数
'''
def aaa(request):
return HttpResponse("aaa")
def bbb(request):
return HttpResponse("bbb")
'''
# 做了两个路由
'''
path('aaa/', aaa),
path('aaaa/',bbb),
'''
# aaaa 匹配到的是 bbb
【2】用正则规则写
'''
re_path(r'^aaa', aaa),
re_path(r'^aaaa', bbb),
'''
'''
路由匹配 http://localhost:8000/aaaa/
# aaa
# 正常的结果应该是 bbb
'''
'''
# 解决办法 /
# / 是路径的结束符 只有遇到 / 才认为当前的请求路径结束
re_path(r'^aaa/', aaa),
re_path(r'^aaaa/', bbb),
'''
【3】 补充Django默认会给你加 /
# http://localhost:8000/aaaa
# 当在浏览器地址结尾没有 加 / 的时候
# 访问指定路径会匹配两次 第一次 不带 /
# 访问指定路径会匹配两次 第二次 带 /
# 如果上面两个都找不到 --- 黄色的报错页面 page not found
Ⅵ 有名分组和无名分组
- 有名分组和无名分组是你在定义 url 匹配规则的时候让最后的路径参数又没有名字而定的
# get 请求
# http://127.0.0.1:8000/?username=silence ---> 有名分组
# http://127.0.0.1:8000/?silence ---> 无名分组
【1】无名分组
- 分组就是将某段正则表达式用()括起来
# 无名分组
re_path(r'^text/(\d+)/', views.test),
re_path(r"^no_name/(\d+)/",no_name)
def no_name(request):
return HttpResponse("no_name")
# no_name() takes 1 positional argument but 2 were given
http://localhost:8000/you_name/1/
def no_name(request, pk, *args, **kwargs):
print(pk) # 1
print(args) # ()
print(kwargs)# {}
return HttpResponse("no_name")
- 无名分组就是将括号内正则表达式匹配到的内容当做位置参数传给后面的视图函数
【2】有名分组
- 可以给正则表达式起一个别名
# 有名分组
re_path(r'^testadd/(?P<year>\d+)', views.testadd),
# (?P 有名分组 <名字> 正则规则)
re_path(r"^you_name/(?P<id>\d+)/",you_name)
def you_name(request, *args, **kwargs):
print(args) # ()
print(kwargs) # {'id': '1'}
return HttpResponse("you_name")
http://localhost:8000/you_name/1/
- 有名分组就是将括号内正则表达式匹配到的内容当做关键字参数传给后面的视图函数
【3】Django 2 + 取消了无名分组 只有有名分组
# 有一个路径参数 是int 类型 后端接受的时候必须交 pk
path("you_name/<int:pk>/",you_name),
def you_name(request, *args, **kwargs):
print(args) # ()
print(kwargs) # {'id': '1'}
return HttpResponse("you_name")
【4】无名有名混用
- 无名分组和有名分组不能混用
# 无名有名混合使用
re_path(r'^index/(\d+)/(?P<year>\d+)/', views.index),
# 访问路由获取不到 (\d+) 的内容
- 但是同一个分组可以使用多次
re_path(r'^test/(\d+)/(\d+)/',views.test),
re_path(r'^test/(?P<xxx>\d+)/(?P<year>\d+)/',views(r'^test/(?P<xxx>\d+)/(?P<year>\d+)/',viewsre_path.test),
def index(request,args,year):
return HttpResponse("index")
标签:__,name,models,res,Django,ORM,分组,import
From: https://www.cnblogs.com/zyb123/p/18257406