昨日作业讲解

1.图书管理系统

实现功能:book单表的增删改查

1.1 新建一个项目bms,创建应用book。过程略…

1.2 手动创建static目录,并在目录里面创建css文件夹,修改settings.py,设置static的目录位置

  1. STATICFILES_DIRS=[
  2. os.path.join(BASE_DIR,"static")
  3. ]

修改templates的目录位置

  1. TEMPLATES = [
  2. {
  3. 'BACKEND': 'django.template.backends.django.DjangoTemplates',
  4. 'DIRS': [os.path.join(BASE_DIR, 'templates')],
  5. 'APP_DIRS': True,
  6. 'OPTIONS': {
  7. 'context_processors': [
  8. 'django.template.context_processors.debug',
  9. 'django.template.context_processors.request',
  10. 'django.contrib.auth.context_processors.auth',
  11. 'django.contrib.messages.context_processors.messages',
  12. ],
  13. },
  14. },
  15. ]

注册app

  1. INSTALLED_APPS = [
  2. 'django.contrib.admin',
  3. 'django.contrib.auth',
  4. 'django.contrib.contenttypes',
  5. 'django.contrib.sessions',
  6. 'django.contrib.messages',
  7. 'django.contrib.staticfiles',
  8. 'book',
  9. ]

下载bootstrap.css放到static目录下的css目录里面

https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css

修改models.py,设计表

  1. from django.db import models
  2. # Create your models here.
  3. class Book(models.Model):
  4. title=models.CharField(max_length=32,unique=True)
  5. price=models.DecimalField(max_digits=8,decimal_places=2,null=True)
  6. pub_date=models.DateField()
  7. publish=models.CharField(max_length=32)
  8. is_pub=models.BooleanField(default=True)

注意:这里没有加id字段,django会自动创建id字段,并设置主键自增,类型为int

默认的是sqlite3数据库,直接用它就可以了。它是基于文件的,不需要用户名和密码。

执行2个命令

  1. python manage.py makemigrations
  2. python manage.py migrate

就可以创建sqlite数据库

点击Pycharm右侧的数据库,添加sqlite

Day72 昨日作业讲解,昨日内容回顾,Django多表创建 - 图1

点击下载驱动

Day72 昨日作业讲解,昨日内容回顾,Django多表创建 - 图2

开始安装

Day72 昨日作业讲解,昨日内容回顾,Django多表创建 - 图3

选择file文件,点击测试连接,点击Ok

Day72 昨日作业讲解,昨日内容回顾,Django多表创建 - 图4

展开右边的数据库,打开book_book

Day72 昨日作业讲解,昨日内容回顾,Django多表创建 - 图5

编辑urls.py,新增url

  1. from django.contrib import admin
  2. from django.urls import path,re_path
  3. from book import views
  4. urlpatterns = [
  5. path('admin/', admin.site.urls),
  6. path('', views.index),
  7. path('index/', views.index),
  8. path('books/add/', views.add),
  9. path('books/manage/', views.manage),
  10. re_path('books/delete/(?P<id>\d+)', views.delete),
  11. re_path('books/modify/(?P<id>\d+)', views.modify),
  12. ]

path(‘’, views.index),表示输入url: http://127.0.0.1:8001 可以直接跳转首页

修改views.py,增加视图函数

  1. from django.shortcuts import render,redirect,HttpResponse
  2. from book import models
  3. # Create your views here.
  4. def index(request): #首页
  5. ret = models.Book.objects.all().exists() # 判断表是否有记录
  6. if ret:
  7. book_list=models.Book.objects.all() # 查询表的所有记录
  8. return render(request,"index.html",{"book_list":book_list})
  9. else:
  10. hint = '<script>alert("没有书籍,请添加书籍");window.location.href="/books/add"</script>'
  11. return HttpResponse(hint) # js跳转到添加页面
  12. def add(request): # 添加
  13. if request.method=="POST":
  14. # print(request.POST)
  15. title=request.POST.get("title")
  16. price=request.POST.get("price")
  17. pub_date=request.POST.get("pub_date")
  18. publish=request.POST.get("publish")
  19. is_pub=request.POST.get("is_pub")
  20. #插入一条记录
  21. obj=models.Book.objects.create(title=title,price=price,publish=publish,pub_date=pub_date,is_pub=is_pub)
  22. print(obj.title)
  23. hint = '<script>alert("添加成功");window.location.href="/index/"</script>'
  24. return HttpResponse(hint) # js跳转到首页
  25. return render(request,"add.html") # 默认渲染添加页面
  26. def delete(request,id): # 删除
  27. ret = models.Book.objects.filter(id=id).delete() # 返回元组
  28. if ret[0]: # 取值为1的情况下
  29. hint = '<script>alert("删除成功");window.location.href="/index/"</script>'
  30. return HttpResponse(hint)
  31. else: # 取值为0的情况下
  32. hint = '<script>alert("删除失败");window.location.href="/index/"</script>'
  33. return HttpResponse(hint)
  34. def manage(request): # 管理页面
  35. ret = models.Book.objects.all().exists()
  36. if ret:
  37. book_list = models.Book.objects.all()
  38. #加载管理页面
  39. return render(request, "manage.html", {"book_list": book_list})
  40. else:
  41. hint = '<script>alert("没有书籍,请添加书籍");window.location.href="/books/add"</script>'
  42. return HttpResponse(hint)
  43. def modify(request,id): # 修改
  44. if request.method == "POST":
  45. title = request.POST.get("title")
  46. price = request.POST.get("price")
  47. pub_date = request.POST.get("pub_date")
  48. publish = request.POST.get("publish")
  49. is_pub = request.POST.get("is_pub")
  50. #更新一条记录
  51. ret = models.Book.objects.filter(id=id).update(title=title, price=price, publish=publish, pub_date=pub_date, is_pub=is_pub)
  52. # print(ret)
  53. if ret: # 判断返回值为1
  54. hint = '<script>alert("修改成功");window.location.href="/index/"</script>'
  55. return HttpResponse(hint) # js跳转
  56. else: # 返回为0
  57. hint = '<script>alert("修改失败");window.location.href="/index/"</script>'
  58. return HttpResponse(hint) # js跳转
  59. book = models.Book.objects.get(id=id) # 默认获取id值
  60. return render(request, "modify.html", {"book": book}) # 渲染指定id的记录

创建templates目录,在templates目录下创建base.html

注意:这个是模板页面

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. {% block title %}
  6. <title>title</title>
  7. {% endblock title %}
  8. <link rel="stylesheet" href="/static/css/bootstrap.min.css">
  9. <style>
  10. * {
  11. margin: 0;
  12. padding: 0;
  13. }
  14. .header {
  15. width: 100%;
  16. height: 60px;
  17. background-color: #369;
  18. }
  19. .title {
  20. line-height: 60px;
  21. color: white;
  22. font-weight: 100;
  23. margin-left: 20px;
  24. font-size: 20px;
  25. }
  26. .container{
  27. margin-top: 20px;
  28. }
  29. .table th, .table td {
  30. text-align: center;
  31. vertical-align: middle!important;
  32. }
  33. </style>
  34. </head>
  35. <body>
  36. <div class="header">
  37. <p class="title">
  38. 图书管理系统
  39. </p>
  40. </div>
  41. <div class="container">
  42. <div class="row">
  43. <div class="col-md-3">
  44. <div class="panel panel-danger">
  45. <div class="panel-heading"><a href="/index/">查看书籍</a></div>
  46. <div class="panel-body">
  47. Panel content
  48. </div>
  49. </div>
  50. <div class="panel panel-success">
  51. <div class="panel-heading"><a href="/books/add/">添加书籍</a></div>
  52. <div class="panel-body">
  53. Panel content
  54. </div>
  55. </div>
  56. <div class="panel panel-warning">
  57. <div class="panel-heading"><a href="/books/manage/">管理书籍</a></div>
  58. <div class="panel-body">
  59. Panel content
  60. </div>
  61. </div>
  62. </div>
  63. <div class="col-md-9">
  64. {% block content %}
  65. {% endblock %}
  66. </div>
  67. </div>
  68. </div>
  69. </body>
  70. </html>

创建index.html,它是首页

  1. {% extends 'base.html' %}
  2. {% block title %}
  3. <title>查看书籍</title>
  4. {% endblock title %}
  5. {% block content %}
  6. <h3>查看书籍</h3>
  7. <table class="table table-hover table-striped ">
  8. <thead>
  9. <tr>
  10. <th>名称</th>
  11. <th>价格</th>
  12. <th>出版日期</th>
  13. <th>出版社</th>
  14. <th>是否出版</th>
  15. </tr>
  16. </thead>
  17. <tbody>
  18. {% for book in book_list %}
  19. <tr>
  20. <td>{{ book.title }}</td>
  21. <td>{{ book.price }}</td>
  22. <td>{{ book.pub_date|date:"Y-m-d" }}</td>
  23. <td>{{ book.publish }}</td>
  24. <td>
  25. {% if book.is_pub %}
  26. 已出版
  27. {% else %}
  28. 未出版
  29. {% endif %}
  30. </td>
  31. </tr>
  32. {% endfor %}
  33. </tbody>
  34. </table>
  35. {% endblock content %}

创建add.html,它是添加页面

  1. {% extends 'base.html' %}
  2. {% block title %}
  3. <title>添加书籍</title>
  4. {% endblock title %}
  5. {% block content %}
  6. <h3>添加书籍</h3>
  7. <form action="" method="post">
  8. {% csrf_token %}
  9. <div class="form-group">
  10. <label for="">书籍名称</label>
  11. <input type="text" name="title" class="form-control">
  12. </div>
  13. <div class="form-group">
  14. <label for="">价格</label>
  15. <input type="text" name="price" class="form-control">
  16. </div>
  17. <div class="form-group">
  18. <label for="">出版日期</label>
  19. <input type="date" name="pub_date" class="form-control">
  20. </div>
  21. <div class="form-group">
  22. <label for="">出版社</label>
  23. <input type="text" name="publish" class="form-control">
  24. </div>
  25. <div class="form-group">
  26. <label for="">是否出版</label>
  27. <select name="is_pub" id="" class="form-control">
  28. <option value="1">已出版</option>
  29. <option value="0" selected="selected">未出版</option>
  30. </select>
  31. </div>
  32. <input type="submit" class="btn btn-success pull-right" value="添加">
  33. </form>
  34. {% endblock content %}

创建manage.html,它是管理页面

  1. {% extends 'base.html' %}
  2. {% block title %}
  3. <title>管理书籍</title>
  4. {% endblock title %}
  5. {% block content %}
  6. <h3>管理书籍</h3>
  7. <table class="table table-hover table-striped ">
  8. <thead>
  9. <tr>
  10. <th>名称</th>
  11. <th>价格</th>
  12. <th>出版日期</th>
  13. <th>出版社</th>
  14. <th>是否出版</th>
  15. <th>删除</th>
  16. <th>编辑</th>
  17. </tr>
  18. </thead>
  19. <tbody>
  20. {% for book in book_list %}
  21. <tr>
  22. <td>{{ book.title }}</td>
  23. <td>{{ book.price }}</td>
  24. <td>{{ book.pub_date|date:"Y-m-d" }}</td>
  25. <td>{{ book.publish }}</td>
  26. <td>
  27. {% if book.is_pub %}
  28. 已出版
  29. {% else %}
  30. 未出版
  31. {% endif %}
  32. </td>
  33. <td>
  34. <a href="/books/delete/{{ book.id }}" >
  35. <button type="button" class="btn btn-danger" data-toggle="modal" id="modelBtn">删除</button>
  36. </a>
  37. </td>
  38. <td>
  39. <a href="/books/modify/{{ book.id }}">
  40. <button type="button" class="btn btn-success" data-toggle="modal">编辑</button>
  41. </a>
  42. </td>
  43. </tr>
  44. {% endfor %}
  45. </tbody>
  46. </table>
  47. {% endblock content %}

创建modify.html,它是修改页面

  1. {% extends 'base.html' %}
  2. {% block title %}
  3. <title>修改书籍</title>
  4. {% endblock title %}
  5. {% block content %}
  6. <h3>修改书籍</h3>
  7. <form action="" method="post">
  8. {% csrf_token %}
  9. <div class="form-group">
  10. <label for="">书籍名称</label>
  11. <input type="text" name="title" class="form-control" value="{{ book.title }}">
  12. </div>
  13. <div class="form-group">
  14. <label for="">价格</label>
  15. <input type="text" name="price" class="form-control" value="{{ book.price }}">
  16. </div>
  17. <div class="form-group">
  18. <label for="">出版日期</label>
  19. <input type="date" name="pub_date" class="form-control" value="{{ book.pub_date|date:"Y-m-d" }}">
  20. </div>
  21. <div class="form-group">
  22. <label for="">出版社</label>
  23. <input type="text" name="publish" class="form-control" value="{{ book.publish }}">
  24. </div>
  25. <div class="form-group">
  26. <label for="">是否出版</label>
  27. <select name="is_pub" id="" class="form-control">
  28. {% if book.is_pub %}
  29. <option value="1" selected="selected">已出版</option>
  30. <option value="0">未出版</option>
  31. {% else %}
  32. <option value="1">已出版</option>
  33. <option value="0" selected="selected">未出版</option>
  34. {% endif %}
  35. </select>
  36. </div>
  37. <input type="submit" class="btn btn-default pull-right" value="修改">
  38. </form>
  39. {% endblock content %}

启动django项目,访问首页

Day72 昨日作业讲解,昨日内容回顾,Django多表创建 - 图6

添加一条数据

Day72 昨日作业讲解,昨日内容回顾,Django多表创建 - 图7

提示添加成功

Day72 昨日作业讲解,昨日内容回顾,Django多表创建 - 图8

效果如下:

Day72 昨日作业讲解,昨日内容回顾,Django多表创建 - 图9

点击左侧的管理书籍

Day72 昨日作业讲解,昨日内容回顾,Django多表创建 - 图10

点击编辑按钮,修改价格和日期

Day72 昨日作业讲解,昨日内容回顾,Django多表创建 - 图11

提示修改成功

Day72 昨日作业讲解,昨日内容回顾,Django多表创建 - 图12

查看首页,发现数据更改过来了!

Day72 昨日作业讲解,昨日内容回顾,Django多表创建 - 图13

2.查询练习

答案:

  1. 1 查询苹果出版社过的价格大于200的书籍
  2. Book.objects.filter(price__gt=200,publish="苹果出版社",is_pub=True)
  3. 2 查询20176月出版的所有以py开头的书籍名称
  4. Book.objects.filter(title__startswith="py",pub_date__year=2017,pub_date__month=6)
  5. 3 查询价格为50,100或者150的所有书籍名称及其出版社名称
  6. Book.objects.filter(price__in=[50,100,150]).values("title","publish")
  7. 4 查询价格在100200之间的所有书籍名称及其价格
  8. Book.objects.filter(price__range=[100,200]).values("title","price")
  9. 5 查询所有人民出版社出版的书籍的价格(从高到低排序,去重)
  10. Book.objects.filter(publish="人民出版社").order_by("prcie").reverse().values("prcie").distinct()
  11. 6 查询价格大于200的书籍的个数
  12. Book.objects.filter(price__gt=200).count()
  13. 7 查询价格不等于100的所有书籍
  14. Book.objects.exclude(prcie=100)
  15. 8 查询苹果出版社出版的书籍中的第3-7本(前提存在足够数量的书籍)
  16. Book.objects.filter(publish="苹果出版社")[2:7]

昨日内容回顾:

  1. 单表操作
  2. class Book(models.Model):
  3. title=models.CharField(max_length=32,unique=True)
  4. price=models.DecimalField(max_digits=8,decimal_places=2,null=True)# 999999.99
  5. pub_date=models.DateField()
  6. publish=models.CharField(max_length=32)
  7. is_pub=models.BooleanField(default=True)
  8. def __str__(self):
  9. return self.title
  10. 添加记录:
  11. 添加记录方式1:
  12. Book.objects.create(title="三体",....)
  13. 添加记录方式1:
  14. book=Book(title="三体",....)
  15. book.save()
  16. 查询记录:
  17. 查询API
  18. 1 Book.objects.all() # querysey [obj,....]
  19. 2 Book.objects.filter(title="三体") # querysey [obj,....]
  20. queryset.filter() # 返回值 queryset
  21. 3 Book.objects.exclude(title="三体") # querysey [obj,....]
  22. 4 Book.objects.all().first() # obj
  23. 5 Book.objects.all().last() # obj
  24. 6 Book.objects.all()[0] # obj
  25. 7 Book.objects.get(title="三体") # obj
  26. #################################################
  27. 8 queryset.order_by() # 返回值 queryset
  28. 9 queryset.reverse() # 返回值 queryset
  29. 10 queryset.count() # 返回值 int (queryset的终止函数)
  30. Book.objects.all().filter(price__gt=100).order_by("pirce").count()
  31. 11 queryset.exist() # 返回值是布尔值
  32. #################################################
  33. 12 queryset.values("price") # 返回值 queryset [{"price":123},{"price":124},{"price":13}]
  34. 13 queryset.valueslist("price") # 返回值 queryset [(123,),(124,),(345,)]
  35. 14 queryset.distinct("price") # 返回值 queryset
  36. 模糊查询 __
  37. Book.objects.filter(price__in=[100,200,300])
  38. Book.objects.filter(price__gt=100)
  39. Book.objects.filter(price__lt=100)
  40. Book.objects.filter(price__range=[100,200])
  41. Book.objects.filter(title__contains="x")
  42. Book.objects.filter(title__icontains="x")
  43. Book.objects.filter(title__startswith="py")
  44. Book.objects.filter(pub_date__year=2012)

models.py里面的Book类,就是一个model对象。

对象可以调用属性字段,queryset可以调用对应的方法

下面这种,就属于链式操作。因为queryset可以调用API接口,只要前一个接口的返回值是queryset,它可以可以一直调用API接口,除非遇到返回值不是queryset的情况下,链式操作,才可以终止。因为count的返回值是int,所以到这里,就结束了!不能再调用API接口了!

  1. Book.objects.all().filter(price__gt=100).order_by("pirce").count()

distinct是去重操作,看下面的代码,执行是没有意义的。因为每一条记录,都是唯一的。

  1. Book.objects.all().distinct()

icontains表示不区分大小写。

三、Django多表创建

如何确定表关系?

表关系是在2张表之间建立的,没有超过2个表的情况。

那么相互之间有2条关系线,先来判断一对多的关系。

如果其中一张表的记录能够对应另外一张表的多条记录,那么关系线成立!

如果只有一条线成立,那么就是一对多的关系。

如果有2条线成立,那么就是多对多的关系。

一对多

比如book和publish。一本书不能对应多个出版社(常规是这样的,否则就盗版了),那么不成立。

一个出版社可以对应多本书,关系线成立。所以book和publish表的关系是一对多的关系

多对多

多对多的关系,就是2张表互相对应多条记录。

比如book和author。一本书可以有多个作者,一个作者可以写多本!

一对一

一对一的关系,就很简单了,彼此唯一。

比如author和authordetail是一对一的关系。

如何建立关联

一对多:

一旦确定一对多的关系:在多的表中创建关联字段

多对多:

一旦确定多对多的关系:创建第三张关系表

一对一:

一旦确定一对一的关系 : 创建关联字段(任意一张表创建都可以)

一般情况下,在重要的表创建关联字段

3种表关系的演进

一对多

看下面一张book表

id title price pub_date publish
1 西游记 123 1743-04-12 苹果出版社

如果需要查询出版社的邮箱呢?再加一列

id title price pub_date publish email
1 西游记 123 1743-04-12 苹果出版社 123@qq.com

查询出版社的地址呢?再加一列

id tiitle price pub_date publish email addr
1 西游记 123 1743-04-12 苹果出版社 123@qq.com 北京

添加2条记录

id title price pub_date publish email addr
1 西游记 123 1743-04-12 苹果出版社 123@qq.com 北京
2 水浒传 456 1743-04-12 苹果出版社 123@qq.com 北京
3 红楼梦 678 1743-04-12 橘子出版社 123@qq.com 北京

问题来了:出版社,邮箱,地址,都重复了!这边非常浪费磁盘空间!

怎么解决这个问题呢?那么多表,就是为了解决问题,而诞生的。

将上面的单表,拆分成2张表。

book表,关联字段为publish_id

id title price pub_date publish_id
1 西游记 123 1743-04-12 1
2 水浒传 456 1743-04-12 1
3 红楼梦 678 1743-04-12 2

publish表

id name email addr
1 苹果出版社 123@qq.com 北京
2 橘子出版社 456@qq.com 南京

这样就可以节省空间

举例:查询西游记的出版社的邮箱

使用子查询(一次查询结果作为另一个查询的条件)

多对多

book和author是多对多的关系

一本书可以有多个作者,一个作者可以写多本!

常规做法,可能是这样的

book表

id title price pub_date publish author_id
1 西游记 123 1743-04-12 1 1,2
2 水浒传 456 1743-04-12 1 1,2

author表

id name age book_id
1 xiao 23 1,2
2 zhang 24 1,2

上面的方案不好,为什么呢?取字段的值,还得用split方法,用逗号分隔。它的返回结果是列表,再对列表进行循环。这样太麻烦了!所以,必须得创建第三张关系表

book表

id title price pub_date publish_id
1 西游记 123 1743-04-12 1
2 水浒传 456 1743-04-12 2

author表

id name age ad_id
1 xiao 23 1
2 zhang 24 2

book_author(关系表)

关系表有且只有3个字段,分别是id,book_id(book表主键),author_id(author表主键)

id book_id author_id
1 1 1
2 1 1
3 2 2
4 2 2

举例:查询西游记所有的作者

思路:先查询西游记的主键id,在关系表中查询id=book_id。最后通过author_id查询author表的作者!

一对一

author和authordetail是一对一的关系

一个作者对应唯一的详细信息

由于authordetail表是author表的延伸,所以在author表创建关联字段

author表

ad_id是关联字段,关联字段的值必须唯一,需要设置唯一属性

id name age ad_id
1 xiao 25 1
2 zhang 26 2

authordetail表

gf表示女朋友,tel表示电话。

id gf tel
1 赵丽颖 110
2 刘诗诗 111

看下面一张图,这是5个表的关系图

Day72 昨日作业讲解,昨日内容回顾,Django多表创建 - 图14

它是一个完整的系统,包含了3种表关系。

三、多表创建

创建模型

实例:我们来假定下面这些概念,字段和关系

作者模型:一个作者有姓名和年龄。

作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息。作者详情模型和作者模型之间是一对一的关系(one-to-one)

出版商模型:出版商有名称,所在城市以及email。

书籍模型: 书籍有书名和出版日期,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-many);一本书只应该由一个出版商出版,所以出版商和书籍是一对多关联关系(one-to-many)。

有5个表,这里面有3种关系,分别是一对一,一对多,多对多

正常的sql建表

  1. #作者表
  2. CREATE TABLE `author` (
  3. `id` int(11) NOT NULL AUTO_INCREMENT,
  4. `name` varchar(32) NOT NULL,
  5. `age` int(11) NOT NULL,
  6. `ad_id` int(11) NOT NULL,
  7. PRIMARY KEY (`id`),
  8. UNIQUE KEY `ad_id` (`ad_id`),
  9. CONSTRAINT `author_ad_id_384abbeb_fk_authordetail_id` FOREIGN KEY (`ad_id`) REFERENCES `authordetail` (`id`)
  10. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  11. #作者详情表
  12. CREATE TABLE `authordetail` (
  13. `id` int(11) NOT NULL AUTO_INCREMENT,
  14. `gf` varchar(32) NOT NULL,
  15. `tel` varchar(32) NOT NULL,
  16. PRIMARY KEY (`id`)
  17. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  18. #书籍表
  19. CREATE TABLE `book` (
  20. `id` int(11) NOT NULL AUTO_INCREMENT,
  21. `title` varchar(32) NOT NULL,
  22. `price` decimal(8,2) DEFAULT NULL,
  23. `pub_date` date NOT NULL,
  24. `publish_id` int(11) NOT NULL,
  25. PRIMARY KEY (`id`),
  26. UNIQUE KEY `title` (`title`),
  27. KEY `book_publish_id_d96d3535_fk_publish_id` (`publish_id`),
  28. CONSTRAINT `book_publish_id_d96d3535_fk_publish_id` FOREIGN KEY (`publish_id`) REFERENCES `publish` (`id`)
  29. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  30. #书籍和作者关系表
  31. CREATE TABLE `book_authors` (
  32. `id` int(11) NOT NULL AUTO_INCREMENT,
  33. `book_id` int(11) NOT NULL,
  34. `author_id` int(11) NOT NULL,
  35. PRIMARY KEY (`id`),
  36. UNIQUE KEY `book_authors_book_id_author_id_36f1e11a_uniq` (`book_id`,`author_id`),
  37. KEY `book_authors_author_id_5acae95a_fk_author_id` (`author_id`),
  38. CONSTRAINT `book_authors_author_id_5acae95a_fk_author_id` FOREIGN KEY (`author_id`) REFERENCES `author` (`id`),
  39. CONSTRAINT `book_authors_book_id_19c7077f_fk_book_id` FOREIGN KEY (`book_id`) REFERENCES `book` (`id`)
  40. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  41. #出版社表
  42. CREATE TABLE `publish` (
  43. `id` int(11) NOT NULL AUTO_INCREMENT,
  44. `name` varchar(32) NOT NULL,
  45. `email` varchar(32) NOT NULL,
  46. `addr` varchar(32) NOT NULL,
  47. PRIMARY KEY (`id`)
  48. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

使用ORM创建表

ORM如果遇到关联字段,会自动添加_id后缀

一对一关系表

authordetail表

  1. class AuthorDetail(models.Model):
  2. gf=models.CharField(max_length=32)
  3. tel=models.CharField(max_length=32)

authordetail表虽然没有定义id字段,但是ORM创建表时,会自动添加id字段,设置主键。字段类型为int,设置自增属性!

author表

  1. class Author(models.Model):
  2. name=models.CharField(max_length=32)
  3. age=models.IntegerField()
  4. # 与AuthorDetail建立一对一的关系
  5. # ad=models.ForeignKey(to="AuthorDetail",to_field="id",on_delete=models.CASCADE,unique=True)
  6. ad=models.OneToOneField(to="AuthorDetail",to_field="id",on_delete=models.CASCADE,)

OneToOneField 表示创建一对一关系。

to 表示需要和哪张表创建关系

to_field 表示关联字段

on_delete=models.CASCADE 表示级联删除。假设a表删除了一条记录,b表也还会删除对应的记录。

ad表示关联字段,但是ORM创建表的时候,会自动添加_id后缀。那么关联字段为ad_id

注意:创建一对一关系,会将关联字添加唯一属性。比如:ad_id

一对多关系表

publish表

class Publish(models.Model):
    name=models.CharField(max_length=32)
    email=models.CharField(max_length=32)
    addr=models.CharField(max_length=32)

book表

class Book(models.Model):
    title=models.CharField(max_length=32,unique=True)
    price=models.DecimalField(max_digits=8,decimal_places=2,null=True)
    pub_date=models.DateField()
    # 与Publish建立一对多的关系,外键字段建立在多的一方
    publish=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE)
    # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建关系表book_authors
    authors=models.ManyToManyField(to="Author")

ForeignKey 表示建立外键

to 表示需要和哪张表创建关系

to_field 表示关联字段

on_delete=models.CASCADE 表示级联删除。使用ForeignKey必须要加on_delete。否则报错。这是2.x规定的

ManyToManyField 表示建立多对多的关系。它只需要一个to参数,表示和哪张表创建多对多关系!

这里是在book模型下定义了多对多关系,它会自动创建一张额外的关系表。表的名字就是当前模型的名字(book)+关系的属性名(等式左边的属性名author**s)**。

也就是会创建表book_authors,它只有3个字段,分别是:本身表的id,boo表主键id,authors表主键id。

book_authors表,应该是这个样子的!

id book_id author_id
1 1 1
2 1 1
3 2 2
4 2 2

多对多

book和author是多对多的关系,在上面已经创建好了。

注意:book模型类,会创建2张表。一个是book本身的表,一个是book和author的关系表

使用ORM模型创建表,完整代码如下:

from django.db import models

# Create your models here.

class Book(models.Model):
    title=models.CharField(max_length=32,unique=True)
    price=models.DecimalField(max_digits=8,decimal_places=2,null=True)
    pub_date=models.DateField()
    # 与Publish建立一对多的关系,外键字段建立在多的一方
    publish=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE)
    # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建关系表book_authors
    authors=models.ManyToManyField(to="Author")

class Publish(models.Model):
    name=models.CharField(max_length=32)
    email=models.CharField(max_length=32)
    addr=models.CharField(max_length=32)


class Author(models.Model):
    name=models.CharField(max_length=32)
    age=models.IntegerField()
    # 与AuthorDetail建立一对一的关系
    # ad=models.ForeignKey(to="AuthorDetail",to_field="id",on_delete=models.CASCADE,unique=True)
    ad=models.OneToOneField(to="AuthorDetail",to_field="id",on_delete=models.CASCADE,)


class AuthorDetail(models.Model):
    gf=models.CharField(max_length=32)
    tel=models.CharField(max_length=32)

注意:模型类的每一个属性,并不一定会创建字段。有些会创建表,比如ManyToManyField

生成表如下:

Day72 昨日作业讲解,昨日内容回顾,Django多表创建 - 图15

注意事项:

  • 表的名称myapp_modelName,是根据 模型中的元数据自动生成的,也可以覆写为别的名称  
  • id 字段是自动添加的
  • 对于外键字段,Django 会在字段名上添加”_id” 来创建数据库中的列名
  • 这个例子中的CREATE TABLE SQL 语句使用PostgreSQL 语法格式,要注意的是Django 会根据settings 中指定的数据库类型来使用相应的SQL 语句。
  • 定义好模型之后,你需要告诉Django 使用这些模型。你要做的就是修改配置文件中的INSTALL_APPSZ中设置,在其中添加models.py所在应用的名称。
  • 外键字段 ForeignKey 有一个 null=True 的设置(它允许外键接受空值 NULL),你可以赋给它空值 None 。