表关系的创建
表与表之间的关系:一对一,一对多,多对多
如何判断表与表之间的关系?
换位思考的角度去考虑
以图书管理系统为例:
图书表
- 图书和出版社是一对多的外键关系
- 一对多的外键关系,外键字段建立在使用频率多的一方
出版社表
作者表
- 图书与作者是多对多的外键关系
- 多对多的外键关系,外键字段无论建在哪张表里面都可以
- 但是推荐建立在查询频率比较高的那张表中
作者详情表
- 作者与作者详情表是一对一的外键关系
- 一对一的外键关系 外键字段建在哪张表里面都可以
- 但是推荐建立在使用频率较高的那张表中
外键建立使用频率较高的一方,方便我们后面基于orm查询
Django的表关系建立
会将字段名和另外一张表的主键字段自动关联起来,建立起外键关系
一对多:字段名 = models.Foreignkey(to='表名')
多对多:字段名 = models.ManyToManyField(to='表名')
一对一:字段名 = models.OneToOneField(to='表名')
ForeignKey
字段以及OneToOneField
字段,在创建表的时候orm会自动给该字段加上_id
的后缀,无论自身是否携带。因此字段名为:字段名_id
# 在书写表关系的时候 要先把基表全部写出来 之后再考虑外键字段
from django.db import models
# Create your models here.
class Book(models.Model):
# id是自动创建的 我们就不写了
title = models.CharField(max_length=64)
# price为小数字段 总共8位小数位占2位
price = models.DecimalField(max_digits=8,decimal_places=2)
# 书籍与出版社 是一对多外键关系
publish = models.ForeignKey(to='Publish') # 默认关联字段就是出版社表的主键字段
# publish = models.ForeignKey(to=Publish) # to后面也可以直接写表的变量名 但是需要保证该变量名在当前位置的上方出现
# 书籍与作者 是多对多外键关系
authors = models.ManyToManyField(to='Author') # 书籍和作者是多对多关系
"""
authors字段是一个虚拟字段 不会真正的在表中创建出来
只是用来告诉django orm 需要创建书籍和作者的第三张关系表
"""
class Publish(models.Model):
name = models.CharField(max_length=64)
addr = models.CharField(max_length=64)
class Author(models.Model):
name = models.CharField(max_length=32)
phone = models.BigIntegerField()
# 一对一外键关系建立
author_detail = models.OneToOneField(to='AuthorDetail')
class AuthorDetail(models.Model):
age = models.IntegerField()
addr = models.CharField(max_length=255)
Django
请求生命周期流程图
Django
的路由系统
URL配置(urls.py
)类似网站的目录,它的本质就是URL与视图函数之间的映射表。
以这种方式告诉django
,这个URL调用这段代码,那个URL调用那段代码。
URL conf配置
基本格式
from django.conf.urls import url
from app名字 import 视图名字
urlpatterns = [
url(正则表达式, views视图函数,参数,别名),
]
urlpatterns = [
url(r'^/$', views.home) # 为网站首页的标准写法,默认匹配后缀为空url路径调用views.home函数
url(r'^admin/', admin.site.urls),
url(r'^index/$', views.index),
url(r'^login/$', views.login),
]
-
正则表达式:一个正则表达式字符串,路由匹配按照正则匹配,一旦正则能够匹配到内容,会立刻执行对应的视图函数,不会再继续匹配了。
-
views视图函数:一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
-
参数:可选的要传递给视图函数的默认参数(字典形式)
-
别名:一个可选的name参数
正则表达式
^
匹配以某字符开头,此处如果不写会造成前面的字母随便输,只要结尾是test/的就可以匹配的上,例如:sdfsdfasdfasdtest/
也可识别到。
如果只写/
,例如:(test/),其实发生了两次请求:当用户在url中输入地址https://www.xxx.com/test
扫描后,发现没有test,之后会让浏览器自动在test结尾多加一个/
,此时会扫描到test。
因此第一次请求没有找到,django会进行301重定向,让浏览器在url后面加一个/再次进行尝试。
# 如果不写^表达式,只写/
urlpatterns = [
url(r'test/', views.test),
url(r'testadd/', views.testadd),
]
用户输入url,django会自动帮我们加上/
,下面参数可以在settings.py
中添加并修改(默认没有)
为False
,就会禁止自动添加/
APPEND_SLASH = True # 自动加斜杠
无名分组
在路由匹配的时候给某段正则表达式加上括号
匹配时候会将括号内正则表达式匹配到的内容当做位置参数传递给对应的视图函数
# 无名分组
url(r'^test/([0-9]{4})/',views.test) # 会将括号内的内容当做位置参数传入视图函数中的args
# 视图函数
def index(request,args):
return HttpResponse('')
有名分组
给一段正则表达式起一个别名
匹配的时候会将括号内正则表达式匹配到的内容当做关键字参数传递给对应的视图函数
# 有名分组
url(r'^test/(?P<year>d+)/', views.test)
# 视图函数
def index(request, year) # 此处的year必须和有名分组中的year保持一致,因为是关键字参数,并不是位置参数,不可以像位置参数那样用形参接收。
无名分组和有名分组不可以混合使用,虽然不能混合使用,但是同一种命名方式,可以使用多个,只要在相应的视图函数中使用相应数量的形参或关键字参数接收即可。
反向解析
给路由与视图函数对应关系起一个名字,前端和后端可以根据这个名字通过一些方法,能够得到一个结果,该结果可以访问到对应的url
此名字整个项目不可以重复
使用方法:
先给路由与视图函数对应关系,起一个名字:
url(r'^testadd/', views.testadd, name='add') # name后面跟的就是名字
前端解析:
{% url 'add' %}
后端解析:
# 需要导入reverse模块
from django.shortcuts import render, HttpResponse, redirect, reverse
reverse('add')
无名分组反向解析
# 无名分组反向解析
url(r'^testadd/(d+)/', views.testadd, name='add')
# 前端解析
{% url 'add' 1 %}
# 后端解析
reverse('add', args=(12,))
有名分组反向解析
# 前端解析
{% url 'edit_user' user_obj.id %} # 推荐使用
# 执行name为'edit_user'的url中的视图函数,并将user_obj.id一并传入url中的函数
{% url 'edit_user' year=1 %} # 标准的
# 有名分组反向解析
url(r'^edit_user_info/(d+)', views.edit_user_info, name='edit_user')
# 后端解析
reverse('add', args=(12,))
reverse('add', kwargs={'year': 12})
伪代码诠释
url(r'^edit_user/(d+)/',views.edit_user,names='edit')
{% for user_obj in user_queryset %}
<a href="edit_user/{{ user_obj.id }}/">编辑</a>
<a href="{% url 'edit' user_obj.id %}">编辑</a>
{% endfor %}
def edit_user(request,edit_id):
reverse('edit',args=(edit_id,))
路由分发
当django项目比较庞大的时候,路由和视图函数对应的关系较多,总路由代码太多冗长,考虑到总路由代码不好维护,django支持每个app都可以有自己的urls.py。
并且总路由不再做路由与视图函数的对应关系,而仅仅只做一个分发任务的操作。
根据请求的不同,识别出当前请求需要访问的功能属于哪个app,然后自动下发到对应app里面的urls.py中,然后由app里面的urls.py做路由与视图函数的匹配。
不仅如此,每个app除了可以有自己的urls.py之外,还可以有自己的static静态资源文件夹,templates模板文件夹。
基于上面的特点,基于django分小组开发会变得额外的简单
每个人只需要开发自己的app即可,之后只需要创建一个空的django项目,将多个人的app全部拷贝到项目下,配置文件注册。
1、总路由
1.总路由
from django.conf.urls import url,include
# 路由分发 注意事项应用名后面千万不能加$
# from app01 import urls as app01_urls
# from app02 import urls as app02_urls
# url(r'^app01/',include(app01_urls)),
# url(r'^app02/',include(app02_urls))
# 简写
url(r'^app01/',include('app01.urls')),
url(r'^app02/',include('app02.urls'))
2、子路由
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'^index/',views.index)
]
from django.conf.urls import url
from app02 import views
urlpatterns = [
url(r'^index/',views.index)
]
名称空间(了解)
url(r'^app01/',include('app01.urls',namespace='app01'))
url(r'^app02/',include('app02.urls',namespace='app02'))
后端解析
reverse('app01:index')
reverse('app02:index')
前端解析
{% url 'app01:index' %}
{% url 'app02:index' %}
# 在给路由与视图函数起别名的时候只需要保证永远不出现冲突的情况即可
# 通常情况下我们推荐期别名的时候加上当前应用的应用名前缀
url(r'^index/',views.index,name='app01_index')
url(r'^index/',views.index,name='app02_index')
虚拟环境
我们想做到针对不同的项目,只安装项目所需要的功能模块,项目用不到的一概不装,来避免加载资源时的消耗。
如何创建虚拟环境?利用pycharm的虚拟环境。此时的虚拟环境类似有一个新的python解释器。
Django
版本区别
路由层:
1.x 用的是url
2.x、3.x用的是path
urlpatterns = [
path('index/',views.index)
]
url第一个参数是一个正则表达式,而path第一参数不支持正则表达式,写什么就匹配什么。
如果觉得path不好用,2.x和3.x版本提供了一个跟url一样的功能:
re_path # 等价于1.x版本里面的url功能
urlpatterns = [
re_path(r'^index/',views.index)
]
虽然path不支持正则表达式,但是它给你提供了五种默认的转换器:
str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
int,匹配正整数,包含0。
slug,匹配字母、数字以及横杠、下划线组成的字符串。
uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
path,匹配任何非空字符串,包含了路径分隔符(/)(不能用?)
path('login/<int:year>/',login
除了默认的五种转换器之外,还支持你自定义转换器
class MonthConverter:
regex='d{2}' # 属性名必须为regex
def to_python(self, value):
return int(value)
def to_url(self, value):
return value # 匹配的regex是两个数字,返回的结果也必须是两个数字
伪静态
url以.html
结尾,给人的感觉好像是这个文件是写死的,内容不会轻易的改变
作用:
为了提高网站的被搜索引擎收藏的力度,提供网站的SEO查询效率
但是,无论你怎么做优化,都玩不过RMB玩家