Tiny_Lu
不忘初心

Day 51 ORM建立表关系/Django路由层

ORM表关系如何建立

我们利用一个简单的图书管理系统来说明ORM中表与表之间多对多,一对多和一对一的关系建立

我们先假设需要四张表,图书表,出版社表和作者表,为了更好的说明一对一的关系,我们再多建立一张作者的详情表

多对多

不难分析,图书表和作者表存在着多对多的关系,一个作者可以创作出多本书籍,同一本书也可以用多个作者,而图书表和出版社表存在一对多的关系,一个出版社会出版各种不同的书籍,现在我们利用之前建表的方法来创建图书表,并利用ORM中建立外键的方式来连接作者表

from django.db import models

# Create your models here.
# 先不要考虑外间关系 建创建基表
class Book(models.Model):
    title = models.CharField(max_length=32)
    # 小数总共八位,小数占两位
    price = models.DecimalField(max_digits=8, decimal_places=2)
    # 图书表和作者表存在着多对多的关系
    author = models.ManyToManyField(to='Author')
    # 图书表和出版社表存在一对多的关系
    publish = models.ForeignKey(to='Publish')
    
class Publish(models.Model):
    name = models.CharField(max_length=32)
    email = models.EmailField()

class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    
class Author_detail(models.Model):
    phone = models.BigIntegerField()
    addr - models.CharField(max_length=64)

注意:

无论是一对一还是一对多关系,在外键字段创建后同步到数据库中时,表字段会自动加_id后缀

Django请求生命周期流程图

Django路由层

路由匹配

urlpatterns = [
    url(regex, view, kwargs=None, name=None),  # url本质就是一个函数
]
# 函数url关键参数介绍
# regex: 正则表达式,用来匹配url地址的路径部分,
# 例如url地址为: http://127.0.0.1:8000/index/,正则表达式要匹配的部分是index/
# view: 通常为一个视图函数,用来处理业务逻辑

注意:

在配置文件settings.py中有一个参数APPEND_SLASH,该参数有两个值True或False,默认为True

当为True时,例如url地址为http://127.0.0.1:8000/index/, Django会先拿着路径部分(即index)去路由表中匹配正则表达式,发现匹配不成功,那么Django会在路径后加/(即index/)再去路由表中匹配,如果匹配失败则会返回路径未找到,如果匹配成功,则会返回重定向给浏览器,要求浏览器重新向http://127.0.0.1:8000/index/ 地址发送请求

当为False时,则不会执行上述过程

无名分组

urls.py文件

from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'test/(\d+)', view.test)
]

views.py文件

from django.shortcuts import render
from django.shortcuts import HttpResponse

# 当你的路由中有分组的正则表达式,那么在匹配到内容执行函数视图的时候,会将分组内正则表达式匹配到的内容当做位置参数传递给视图函数,test(request, 分组内正则表达式匹配到的内容)
def test(request, test_id):
    return HttpResponse(test_id)

有名分组

urls.py文件

from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpattern = [
    url(r'^admin/', admin.site.urls),
    
    # 该正则会匹配url地址的路径部分为:test/数字/, 匹配成功的分组会以关键字参数(year=数字)的形式传给视图函数,有几个有名函数就会传几个关键字参数
    url(r'^test/(?P<year>\d+)', views.test)
]

views.py文件

from django.shortcuts import render
from django.shortcuts import HttpResponse

def test(request, year):
    return HttpResponse(year)

总结: 有名分组和无名分组都是为了获取路径中的参数,并传递给视图函数,区别在于无名分组是以位置参数的形式传递,有名分组是以关键字参数的形式传递

注意: 无名分组和有名分组不能混合使用

反向解析

from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpattern = [
    url(r'^admin/', admin.site.urls),
    url(r'^login/&', views.login, name='login_page'),  # 路径login/的别名login_page
    url(r'^index/$', views.index, name='index_page')
]

在views.py中

from django.shortcuts import render, redirect, HttpResponse
from django.shortcuts import reverse  # 用于反向解析
def login(request):
    if request.method == 'GET':
        return render(reqeust, 'login.html')
    
    name = request.POST.get('name')
    pwd = request.POST.get('pwd')
    if name == 'tiny' and pwd == '123':
        url = reserve('index_page')  # reserse会将别名'index_page'反向解析成路径:/index/
        return redirect(url)
    else:
        return HttpResponse('用户名和密码错误!')
    
    
def index(request):
    return render(request, 'index.html')

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
    <!--强调:login_page必须加引号-->
    <form action="{% url 'login_page' %}" method="post">
        {% csrf_token %}
        <p>用户名:<input type="text" name="name"></p>
        <p>密码:<input type="password" name="pwd"></p>
        <p><input type="submit" value="提交"></p>
</form>
</body>
</html>

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
    <h3>我是indexyemian...</h3>
</body>
</html>

总结:

  1. 在views.py中,反向解析的使用

    url = reverse('index_page')
    
  2. 在模板login.html文件中,反向解析的使用

路由分发

前提
在django中所有的app都可以有自己独立的urls.py templates static
正是由于上面的特点 你用django开发项目就能够完全做到多人分组开发 互相不干扰
每个人只开发自己的app
小组长只需要将所有人开发的app整合到一个空的django项目里面
然后在settings配置文件注册 再利用路由分发将多个app整合到一起即可完成大项目的拼接
路由分发解决的就是项目的总路由匹配关系过多的情况使用路由分发 会将总路由不再做匹配的活 而仅仅是做任务分发(请求来了之后 总路由不做对应关系只询问你要访问哪个app的功能 然后将请求转发给对应的app去处理)

from app01 import urls as app01_urls
from app02 import urls as app02_urls
urlpatterns = [
	url(r'^admin/', admin.site.urls),  # url第一个参数是一个正则表达式
	# 路由分发
	url(r'^app01/',include(app01_urls)),  # 路由分发需要注意的实现 就是总路由里面不能以$结尾
	url(r'^app02/',include(app02_urls)),
]
# 子路由
from django.conf.urls import url
from app01 import views

urlpatterns = [
	url('^reg/',views.reg)
]
from django.conf.urls import url
from app02 import views

urlpatterns = [
	url('^reg/',views.reg)
]
# 最省事的写法(******)
url(r'^app01/',include('app01.urls')),
url(r'^app02/',include('app02.urls'))

名称空间

当多个app中出现了起别名冲突的情况 你在做路由分发的时候 可以给每一个app创建一个名称空间
然后在反向解析的时候 可以选择到底去哪个名称空间中查找别名

url(r'^app01/',include('app01.urls',namespace='app01')),
url(r'^app02/',include('app02.urls',namespace='app02'))

# 后端
print(reverse('app01:reg'))
print(reverse('app02:reg'))
# 前端
<a href="{% url 'app01:reg' %}"></a>
<a href="{% url 'app02:reg' %}"></a>

其实上面的名称空间知识点可以完全不用 你只需要保证起别名的时候 在整个django项目中不冲突即可
参考建议
起别名的时候统一加上应用名前缀

urlpatterns = [										url(r'^reg/',views.reg,name='app02_reg')
]
urlpatterns = [		   								url('^reg/',views.reg,name='app01_reg')
]

伪静态

将一个动态网页伪装成一个静态网页,以此来提高搜索引擎的SEO查询频率和收藏力度

Django版本区别

urls.py中路由匹配的方法有区别

# django2.X用的是path
urlpatterns = [
	path('admin/', admin.site.urls),
]
django1.X用的是url
urlpatterns = [										url(r'^reg.html',views.reg,name='app02_reg')
]
  1. django2.X里面path第一个参数不是正则也不支持正则,写什么就匹配什么
  2. 虽然path不支持正则,但是还有一个re_path的方法,该方法就是django1.X里面的url
  3. path还提供了五种转换器,能够将匹配到的数据自动转换成对应的类型
  4. 除了有默认的五种转换器外,还支持你自定义转换器
posted @ 2019-11-25 21:09  二二二二白、  阅读(141)  评论(0编辑  收藏  举报