Django(三)
一、表关系的创建
以图书表,出版社表,作者表和作者详情表为例
1.一对多
图书表和出版社表是一对多的关系
2.多对多
图书表和作者表是多对多的关系
3.一对一
作者表和作者详情表是一对一的关系
实现方式
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会帮我们创建作者表与图书表多对多关系的那张关系表,表中字段和我们平时创建的内容也是一样
ForeignKey字段以及OneToOneField字段 在创建表的时候orm都会自动给该字段加_id的后缀,所以我们不需要再加上_id后缀
二、django请求生命周期流程图
三、路由层
1.路由匹配
在urls.py下面这段代码
urlpatterns = [ url(r'^admin/', admin.site.urls), ]
url方法第一个参数是一个正则表达式,路由匹配按照正则匹配 一旦正则能够匹配到内容 会立刻执行对应的视图函数,不会再继续匹配了,所以这个参数最好加上开始符:'^'和结束符:'$'
用户输入url不加最后的斜杠,django会默认自动加上 ,可以在配置文件中指定是否开启该功能:APPEND_SLASH = True/False
2.分组
分组就是给一段正则表达式加括号
无名分组
匹配的时候会将括号内正则表达式匹配到的内容当做位置参数传递给对应的视图函数
路由语法:
url(r'^test/([0-9]{4})/',views.test)
视图函数:需要在后面加上一个位置参数
def index(request,args)
有名分组
给一段正则表达式起一个别名,匹配的时候会将括号内正则表达式匹配到的内容当做关键字参数传递给对应的视图函数
路由语法:
url(r'^test/(?P<year>\d+)/',views.test)
视图函数:
def index(request,year)
补充:无名有名不能混合使用
虽然不能混合使用,但是同一种命名方式可以使用多个
反向解析
通过一些方法,能够得到一个结果,该结果可以访问到对应的url
使用方法:
- 先给路由与视图函数对应关系起一个名字:url(r'^testadd/',views.testadd,name='add')
- 前端解析:{% url 'add' %}
- 后端解析:from django.shortcuts import reverse
reverse('add')
- 无名分组反向解析
路由语法:url(r'^testadd/(\d+)/',views.testadd,name='add')
前端解析:{% url 'add' 1 %}
后端解析:reverse('add',args=(12,))
- 有名分组反向解析
路由语法:url(r'^testadd/(?P<year>\d+)/',views.testadd,name='add')
前端解析:{% url 'add' 1 %} # 推荐使用
后端解析:reverse('add',args=(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,)) """
3.路由分发
当django项目比较庞大的时候,路由与视图函数对应关系较多,总路由代码太多冗长。考虑到总路由代码不好维护,django支持每个app都可以有自己的urls.py,并且总路由不再做路由与视图函数的对应关系,而仅仅只做一个分发任务的操作。
根据请求的不同,识别出当前请求需要访问的功能属于哪个app然后自动,下发到对应app里面的urls.py中,然后由app里面的urls.py做路由与视图函数的匹配
总路由:
from django.conf.urls import include url(r'^app01/',include('app01.urls')), url(r'^app02/',include('app02.urls'))
子路由:
# app01 from django.conf.urls import url from app01 import views urlpatterns = [ url(r'^index/',views.index) ] # app02 from django.conf.urls import url from app02 import views urlpatterns = [ url(r'^index/',views.index) ]
四、名称空间
每个app除了可以有自己的urls.py之外,还可以有自己的static文件夹 templates模板文件,基于上面的特点 基于django分小组开发,会变得额外的简单,但是同时会有在不同的APP中出现相同的视图函数别名,会产生冲突。
解决办法:
1.使用名称空间
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' %}
2.起别名的时候加上当前应用的应用名前缀
url(r'^index/',views.index,name='app01_index') url(r'^index/',views.index,name='app02_index'
五、虚拟环境
想做到针对不同的项目,只安装项目所需要的功能模块,项目用不到的一概不装,来避免加载资源时的消耗,这就需要用到虚拟环境
django版本区别:
路由层:
1.x用的是url
2.x用的是path
url第一个参数是正则表达式,而path第一个参数不支持正则表达式,写什么就匹配什么,re_path和url一样
虽然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是两个数字,返回的结果也必须是两个数字
补充内容:
1.伪静态:
url以.html结尾给人的感觉好像是这个文件是写死的,内容不会轻易的改变
作用:为了提高你的网站被搜索引擎收藏的力度,提供网站的SEO查询效率
2.视图层:
视图函数必须要返回一个HttpResponse对象
3.JsonResponse:
from django.http import JsonResponse def xxx(request): user_dict = {'username':'tank坦克','password':'123'} # json_str = json.dumps(user_dict,ensure_ascii=False) # return HttpResponse(json_str) # JsonResponse对象封装了上面两步,当序列化对象中有中文时,需要加一个字典:json_dumps_params={'ensure_ascii':False} return JsonResponse(user_dict,json_dumps_params={'ensure_ascii':False}) l = [1,2,3,4,5,6,7,8,9,] return JsonResponse(l,safe=False) # 序列化非字典格式数据 需要将safe改为False