表与表之间的关系:一对多,多对多,一对一。
判断表关系的方法:换位思考。
案例:图书表,出版社表,作者表,作者详情表
图书表和出版社表是一对多的关系,外键字段建在多的一方,即图书表上;
图书表和作者表是多对多的关系,需要创建第三张表来存储两张表的外键字段;
作者表与作者详情表是一对一的关系,外键字段建在查询频率较高的一方,即作者表上。
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=32, verbose_name='书名')
price = models.DecimalField(max_length=8, max_digits=2, verbose_name='价格')
class Publish(models.Model):
name = models.CharField(max_length=32, verbose_name='出版社名')
addr = models.CharField(max_length=128, verbose_name='出版社地址')
class Author(models.Model):
name = models.CharField(max_length=32, verbose_name='作者姓名')
age = models.IntegerField(verbose_name='作者年龄')
class AuthorDetail(models.Model):
phone = models.BigAutoField(verbose_name='手机号码')
addr = models.CharField(max_length=128, verbose_name='居住地址')
图书表和出版社表是一对多的关系,外键字段建在多的一方,即图书表上。
models.ForeignKey(to='关联表名')
class Book(models.Model):
title = models.CharField(max_length=32, verbose_name='书名')
price = models.DecimalField(max_length=8, max_digits=2, verbose_name='价格')
public = models.ForeignKey(to='Public') # 默认是与出版社表的主键字段做关联。
图书表和作者表是多对多的关系,不需要手动创建第三张关系表;
需要外键字段,外键字段建在任意一方均可,推荐建在查询频率较高的一方;
外键字段只是一个虚拟字段,不会真正地在表中展示出来,只是用来表明当前表和关联表是多对多的关系,ORM会自动创建第三张关系表。
models.ManyToManyField(to='关联表名')
class Book(models.Model):
title = models.CharField(max_length=32, verbose_name='书名')
price = models.DecimalField(max_length=8, max_digits=2, verbose_name='价格')
public = models.ForeignKey(to='Public')
authors = models.ManyToManyField(to='Author')
# authors是一个虚拟字段,表明图书表和作者表是多对多的关系。
作者表与作者详情表是一对一的关系,外键字段推荐建在查询频率较高的一方,即作者表上。
models.OneToOneField(to='关联表名')
class Author(models.Model):
name = models.CharField(max_length=32, verbose_name='作者姓名')
age = models.IntegerField(verbose_name='作者年龄')
author_detail = models.OneToOneField(to='AuthorDetail')
app02_author
app02_authordetail
app02_book
app02_book_authors
app02_publish
auth_group
auth_group_permissions
auth_permission
auth_user
auth_user_groups
auth_user_user_permissions
django_admin_log
django_content_type
django_migrations
django_session
# 图书表和出版社表是一对多的关系,外键字段建在多的一方,即图书表上。
publish = models.ForeignKey(to='Publish')
# 图书表和作者表是多对多的关系,ORM会自动创建第三张表,外键字段推荐建在查询频率较高的一方,即图书表上。
authors = models.ManyToManyField(to='Author')
# 作者表与作者详情表是一对一的关系,外键字段推荐建在查询频率较高的一方,即作者表上。
author_detail = models.OneToOneField(to='AuthorDetail')
web服务网关接口
Django使用自带的wsgiref模块
作用:
补充:
urls.py
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'test', views.test),
url(r'test123', views.test123),
]
url函数中第一个参数是正则表达式。
一旦请求的url与正则表达式匹配成功,立即停止继续匹配,并执行相应的视图函数。
当访问 http://127.0.0.1:8000/test123 时,test123中包含test,匹配成功,
只要正则表达式能够匹配到内容,就会停止向下继续匹配,执行相应的视图函数test。
这意味着视图函数test123永远无法执行。
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'test/', views.test),
url(r'test123/', views.test123),
]
结尾没有正斜杠/的匹配流程
当访问 http://127.0.0.1:8000/test123
时,其结尾没有正斜杠,不满足任何url函数的正则匹配条件。
django会自动在url后面添加正斜杠,并让浏览器重定向到新url: http://127.0.0.1:8000/test123/
,
django对新的url重新进行匹配,最后找到 url(r'test123/', views.test123)
。
可以让django取消为url自动添加正斜杠功能。
settings.py
APPEND_SLASH = False
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^test/$', views.test),
url(r'^test123/$', views.test123),
]
主页匹配
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', views.home),
]
分组,就是将某一段正则表达式用小括号包起来。
无名分组,就是将括号内正则表达式匹配到的内容当作位置参数传递给后面的视图函数。
urls.py
url(r'^test/(\d+)/', views.test)
访问 http://127.0.0.1:8000/test/123456/ 时,会将匹配到的内容123456传递给后面的视图函数。
views.py
def test(request, arg1):
print(arg1) # 123456
return HttpResponse('test')
可以给正则表达式起一个别名。
有名分组,就是将括号内正则表达式匹配到的内容当作关键字参数传递给后面的视图函数。
urls.py
url(r'^testadd/(?P\d+)' , views.test)
访问 http://127.0.0.1:8000/test/2020/
views.py
def test(request, year):
print(year) # 2020
return HttpResponse('test')
urls.py
url(r'^index1/(\d+)/(\d+)/(\d+)/', views.index1),
url(r'^index2/(?P\d+)/(?P\d+)/(?P\d+)/' , views.index2),
views.py
def index1(request, *args, **kwargs):
return HttpResponse('index1')
def index2(request, *args, **kwargs):
return HttpResponse('index2')
路由层中如果修改了用于匹配url的正则表达式,前端模板中的超链接和后端视图中的重定向都要随之发生变化。
希望让超链接和重定向根据路由层中的正则表达式反向地动态地获取,即反向解析。
反向解析的本质:通过一些方法得到一个结果,该结果可以访问到对应的url,从而去触发对应的视图函数。
urls.py
url(r'^test/', views.func_test, name='test_name')
别名不能出现重复。
前端反向解析
<a href="{% url 'test_name' %}">链接a>
后端反向解析
views.py
from django.shortcuts import redirect, reverse
print(reverse('test_name')) # /test/
# 视图中的重定向
return redirect(reverse('test_name'))
urls.py
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^test/(\d+)', views.test, name='test_name'),
]
后端
views.py
def test(request):
print(reverse('test_name', args=(1,))) # /test/1
return render(request, 'test.html')
函数reverse中需要提供参数args,用于匹配路由的正则表达式,否则会报错。
NoReverseMatch at /test/
Reverse for 'test_name' with no arguments not found. 1 pattern(s) tried: ['test/(\\d+)']
前端
test.html
<a href="{% url 'test_name' 123 %}">链接a>
这个数字一般是数据的主键值,便于定位数据,进行数据获取、编辑和删除等操作。
urls.py
url(r'^edit/(\d+)/', views.edit, name='edit_url')
views.py
def edit(request, user_id):
reverse('edit_url', args=(user_id,))
test.html
{% for user_obj in user_queryset %}
<a href="{% url 'edit_url' user_obj.id %}">编辑a>
{% endfor %}
urls.py
url(r'^edit/(?P\d+)/' , views.edit, name='edit_url')
views.py
def edit(request, user_id):
# 正式写法
reverse('edit_url', kwargs={'user_id': user_id})
def edit(request, user_id):
# 简便写法 与无名分组一样
reverse('edit_url', args=(user_id,))
test.html
{% for user_obj in user_queryset %}
<a href="{% url 'edit_url' edit_url=user_obj.id %}">编辑a>
<a href="{% url 'edit_url' user_obj.id %}">编辑a>
{% endfor %}