最好有其他web框架基础,不推荐小白阅读,
1.视图函数
def login(req):
print(req.method)
# 判断请求方式 注意都是大写的
if req.method == "GET":
# 直接返回页面 这里是使用请求方式来区分同一个地址的 请求的目的
return render(req, "login.html")
elif req.method == "POST":
# 如果是post请求就获取数据
# print(req.POST) # POST 或GET 获取到的都是一个字典QueryDict类型
# print(req.POST.get("hobby")) # 每个值都是一个数组类型 直接get得到的是最后一个值
# print(req.POST.getlist("hobby")) # 获取所有值 以列表形式
# 获取用户名和密码:
user = req.POST.get("user")
pwd = req.POST.get("pwd")
# 查询数据库
pool = ZS_POOL.ConnectPool()
res = pool.execute_sql("select *from person where name = %s and password = %s",[user,pwd])
print(res)
if res[0]:
return HttpResponse("login success!")
return HttpResponse("login failed!")
return HttpResponse()
1.1视图函数的返回值
django要求视图函数必须返回一个HTTPResponse对象,render函数和 redirect 函数其实都是返回了一个特定的HTTPResponse对象
1.2 reder函数
render函数用于渲染一个模板文件,这里的渲染指的是将动态数据填充到页面文件中,
该函数接收一个request请求对象,一个模板文件,一个context,
其中context用于,向模板中传递数据,以字典形式,模板文件中可以使用模板语言从context中取出数据
案例:
def user_list(req):
if req.method == "GET":
return render(req,"users.html",context={"users":["jack","rose"]})
1.3 redirect函数
redirect函数用于重定向页面,返回值为HttpResonse,需要说明的是重定向的本质是让客户端重新发起新请求,请求另一个地址
案例:
return redirect("/userlist")
2.配置文件
2.1静态文件配置
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.2/howto/static-files/
STATIC_URL = '/static/' # 静态路由, 路径为根路径+/static时将返回下列路径中的静态文件
# 静态文件搜索路径 ,可以是列表
STATICFILES_DIRS = [
os.path.join(BASE_DIR,"static")
]
2.2模板路径配置
补充:pycharm链接数据库
3.ORM
3.1django链接数据库配置
3.2异常处理:
django2.2 版本时链接数据库报错:
LookupError: No installed app with label 'admin'.
查询资料后得到的办法是:更换版本到2.1.8
虽然解决了但是,2.1.8支持到2020年结束
更换长期版本225 没有上面的错误 但是出现了新的错误:
按照下列步骤一步一步搞定:
https://www.cnblogs.com/yangyuanhu/p/11526256.html
3.3 同步model到数据库
在app下的models中 创建对应的模型,模型需继承models.Model类
类中使用Field类对象表示字段
模型准备好后,在项目下执行命令:
python3 manager.py makemigrations # 用于创建迁移记录
python3 manager.py migrate # 用于将最新的记录迁移至数据库中
需要注意: migrate 在迁移时是根据makemigrations 产生的记录文件来进行数据库同步的
也就意味着 必须先执行makemigrations 才能执行migrate 来同步
创建的数据库名称以app名称作为前缀,如下:
注意2:数据库操作都是针对已经注册的app,所以需要先注册app到配置文件中
3.4针对已存在的model字段进行CUD
-
添加字段
执行makemigrations时会遇到提示信息要求为新的字段添加默认值 ,可以在命令行直接输入默认值
注意:上述方式添加是一次性的不会修改字段的默认值属性 依然是不可为空的
或者退出后,修改代码,如下:
-
删除 修改字段
如删除email字段:
修改代码后执行迁移命令(两条)即可
3.5利用ORM 对数据进行增删改查
-
简单查询
#关键字参数 会被作为 and链接 返回值为一个结果集合 first 是取出第一个 user = models.User.objects.filter(user=user,pwd=pwd).first() #查询所有数据 返回结果集 可迭代 users = models.User.objects.all()
添加数据
# ORM添加数据方式1 创建并存储到数据库 # user = models.User.objects.create(user=user,pwd=pwd,phone=phone) # print(user) # ORM添加数据方式2 创建对象 手动调用save方法来存储 user = models.User(user=user,pwd=pwd,phone=phone) user.save()
-
删除数据
id = req.GET.get("id") # 删除数据 返回值为执行影响的记录数量 可用于判断执行是否成功 需要注意的是如果有多条记录将全部删除 count = models.User.objects.filter(id=id).delete()
-
修改数据
# 从请求中取值 id = req.POST.get("id") # 找到对象后执行update来更新数据 返回更新数量 count = models.User.objects.filter(id=id).update(user=user,pwd=pwd,phone=phone) print(count)
3.6 ORM中的多表关联设计
-
班级表
class CLASS(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=20)
-
一对多
一个班级对应多个老师
class Teacher(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=20) # 多个老师对应同一个 班级 在老师表中保存班级表的id room = models.ForeignKey(to=CLASS,to_field="id",on_delete=models.CASCADE) # 注意 在2.* 中on_delete 没有默认值 必须手动指定 级联操作 # 外键字段 会自动添加_id作为后缀
-
多对多
一个学生对应多个老师 一个老师对应多个学生
class Student(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=20) teacher = models.ManyToManyField(to=Teacher)
4路由
4.1 提取路径中的参数
1.* 的url 函数 与2.* re_path 使用方式一致
第一个参数为正则表达式,第二个是要调用的函数名称
re_path下的配置以及参数捕获
先声明:不使用复杂的url配置直接将参数放在?后面也是可以完成所有需求的
那么使用复杂的配置从path中取值的目的是什么呢? 伪静态!
而伪静态是为了SEO优化
-
无名分组:
从path中使用re获取值然后当做位置参数传给视图函数
re_path('^book/(\d+)/$', views.book),
#视图函数
def book(request,any_name):
pass
-
有名分组:
从path中使用re获取值然后当做关键字参数传给视图函数
re_path('^book/(?P<id>\d+)/$', views.book),
#视图函数 参数名称必须与url配置中完全相同
def book(request,id):
pass
4.2 2.* 下的path
2.*版本下默认使用的是path,path其实就是老版本url的有名分组,捕获的参数都会以关键字的形式传给视图函数
- 用法:
path('gets/<page>/info', views.gets),
# <> 表示分组 括号中的page是参数名称
-
转换器
本质就是疯转的正则 最后在帮你做了类型转换
path('gets/<int:page>/info', views.gets),
-
自定义转换器
当你的规则比较复杂或是要转换为特殊的类型时可以自定义转换器,有以下要求
-
regex
类属性,字符串类型 -
to_python(self, value)
方法,value是由类属性regex
所匹配到的字符串,返回具体的Python变量值,以供Django传递到对应的视图函数中。 -
to_url(self, value)
方法,和to_python
相反,value是一个具体的Python变量值,返回其字符串,通常用于url反向引用。
案例:
class FourDigitYearConverter: regex = '[0-9]{4}' def to_python(self, value): return int(value) def to_url(self, value): return '%04d' % value # 该转换器用于匹配4位的整数 并转为int类型
使用:
# 注册 register_converter(converters.FourDigitYearConverter, 'yyyy') # 使用 urlpatterns = [ path('articles/2003/', views.special_case_2003), path('articles/<yyyy:year>/', views.year_archive),
-
4.3反向解析
何为反向,正常的请求流程是先走路由,在执行视图函数渲染模板,
当我们在模板或者视图函数中需要获取路由信息时就称之为反向解析
为什么要这样做呢?,目的是为了方便后续修改路由配置,反向解析可以获取请求路径信息,而避免直接写死路径带来的麻烦事
下例方法适用于1.* 中的url函数
首先需要在路由中为这个路由指定一个名称
- 不带分组
#路由
re_path('books', views.books,name="path1")
#视图函数取值
print(reverse("path1"))
#模板取值
<h1>{% url "path1" %}</h1>
- 无名分组
#路由
re_path('books/(\d+)', views.books2,name="path2"),
#视图函数取值
print(reverse("path2",args=("100",)))
#模板取值
<h1>{% url "path2" "1" %}</h1>
- 有名分组
#路由
re_path('books3/(?P<id>\d+)', views.books3,name="path3"),
#视图函数取值
print(reverse("path3", args=("100",)))
# or
print(reverse("path3", kwargs={"id": "100"}))
#模板取值
<h1>{% url "path3" "1" %}</h1>
# or
<h1>{% url "path3" id="1" %}</h1>
另外反向解析本质就是做字符串拼接,所以无论在什么位置只要存在就可以解析
4.4路由分发
当应用程序体积大 模块多时需要拆分多个不同APP,同时urls也不能全都写在主路由配置中
这就需要在主路由配置文件中引入其他app中的路由配置信息
- 引入案例:
主路由配置文件:
from django.urls import include, path
urlpatterns = [
# 可以是完整的模块路径
path('help/', include('apps.help.urls')),
# 可以是一个已经导入的模块名称
path('credit/', include(a_urls)),
]
当请求路径为 http:xxxxxxx:8000/help/test/ 是将请求交给apps.help.urls来进行匹配,
需要强调的是在apps.help.urls中拿到的路径是已经去除前缀的,也就是只有/test/部分
- 使用include来简化书写:
简化前
urlpatterns = [
path('<page_slug>-<page_id>/history/', views.history),
path('<page_slug>-<page_id>/edit/', views.edit),
path('<page_slug>-<page_id>/discuss/', views.discuss),
path('<page_slug>-<page_id>/permissions/', views.permissions),
]
简化后:
urlpatterns = [
path('<page_slug>-<page_id>/', include([
path('history/', views.history),
path('edit/', views.edit),
path('discuss/', views.discuss),
path('permissions/', views.permissions),
])),
]
路由分发中的名称空间
当多个app中出现了相同名称的路由时,反向解析将出现问题
- 解决方案1
手动给name添加别名
re_path('^books$', views.books,name="appname_path1"),
- 解决方案2
在include中指定namespace
path("app01/",include("app01.urls",namespace="app01"))
#视图函数取值
print(reverse("app01:path1"))
#模板取值
<h1>{% url "app01:path1" %}</h1>