Django框架进阶5 models常用字段及参数, choices参数, 自动显示sql命令配置, orm查询优化相关, orm中的事务操作, MTV与MVC模型, 图书管理系统(图书的增删改查)
models中的常用字段
AutoField(primary_key=True) 主键 (int自增列,必须填入参数 primary_key=True。当model中如果没有自增列,则自动会创建一个列名为id的列。)
CharField(max_length=32) varchar(32)
IntegerField() int
BigIntergerField() bigint
DecimalField() decimal
EmailField() varchar(254)
DateField() date
DateTimeField() datetime
auto_now:每次编辑数据的时候都会自动更新该字段时间
auto_now_add:创建数据的时候自动更新
BooleanField(Field)
给该字段传布尔值 会对影成 数字0/1
is_delete
is_status
is_vip
TextField(Field)
-文本类型 存储大段文本
FileField(Field)
- 字符串,路径保存在数据库,文件上传到指定目录,只存文件路径
upload_to = '指定文件路径'
给该字段传文件对象 文件会自动保存到upload_to指定的文件夹下 然后该字段存文件的路径
如何自定义char类型字段
from django.db.models import Field class RealCharField(Field): def __init__(self,max_length,*args,**kwargs): self.max_length = max_length # 拦截一个父类的方法 操作完之后 利用super调用父类的方法 super().__init__(max_length=max_length,*args,**kwargs) def db_type(self, connection): return 'char(%s)'%self.max_length class Movie(models.Model): textField = RealCharField(max_length=64)
字段内的关键性参数
null null=True 允许字段为空,必须用null
default 默认参数
django 1.x默认就是级联更新级联删除 django2.x需要你自己手动指定
on_delete = models.CASCADE
db_contraints = True
# 百度
choice参数
用户的性别
学历
婚否
在职状态
客户来源
当你的数据能够被你列举完全 你就可以考虑使用choices参数
models.py
class Userinfo(models.Model): username = models.CharField(max_length=32) gender_choices = ( (1,'男'), (2,'女'), (3,'其他'), ) gender = models.IntegerField(choices=gender_choices) # 该字段还是存数字 并且可以匹配关系之外的数字 record_choices = (('checked','已签到'), ('vacate','请假'), ('noshow','缺勤'), ('leave_early','早退'), ) record = models.CharField('上课记录',choices=record_choices,default='checked',max_length=64)
test.py
user_obj = models.Userinfo.objects.get(pk=1) print(user_obj.username) print(user_obj.gender) # 针对choices参数字段 取值的时候 get_xxx_display() print(user_obj.get_gender_display()) # 针对没有注释信息的数据 get_xxx_display()获取到的还是数字本身 user_obj = models.Userinfo.objects.get(pk=4) print(user_obj.gender) # 100 print(user_obj.get_gender_display()) # 100
django自动显示sql命令配置
settings.py文件中加入
LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level':'DEBUG', }, } }
数据库查询优化(面试会问)
only与defer
only作用
括号内传字段 得到的结果是一个列表套数据对象 该对象内只含有括号内指定的字段属性
对象点该字段属性是不会走数据库的 但是你一旦点了非括号内的字段 也能够拿到数据
但是是重新走的数据库查询吧
defer与only相反
括号内传字段 得到的结果是一个列表套数据对象 该对象内没有括号内指定的字段属性
对象点该字段属性会重复走数据库 但是你一旦点了非括号内的字段 就不走数据库了
# res = models.Book.objects.all() # django orm查询都是惰性查询 # print(res) # res = models.Book.objects.values('title') # print(res) # for r in res: # print(r.title) # res = models.Book.objects.only('title') # 這些對象内部只有title屬性 # # print(res) # for r in res: # # print(r.title) # print(r.price) # 内部会重新遍历,寻找价格 """ only作用 括号内传字段 得到的结果是一个列表套数据对象 该对象内只含有括号内指定的字段属性 对象点该字段属性是不会走数据库的 但是你一旦点了非括号内的字段 也能够拿到数据 但是是重新走的数据库查询吧 """ # res = models.Book.objects.defer('title') # defer与only互为反关系 # for r in res: # print(r.title) """ defer与only相反 括号内传字段 得到的结果是一个列表套数据对象 该对象内没有括号内指定的字段属性 对象点该字段属性会重复走数据库 但是你一旦点了非括号内的字段 就不走数据库了 """
selected_related与prefetch_related
selected_related
内部是连表操作 现将关系表全部链接起来 之后再一次性查询出来 封装到对象中
数据对象之后在获取任意表中的数据的时候都不需要再走数据库了 因为全部封装成了对象的属性
select_related括号内只能传外键字段 并且不能是多对多字段 只能是一对多和一对一
select_related(外键字段1__外键字段2__外键字段3...)
prefetch_related
prefetch_related内部是子查询 但是给你的感觉是连表操作
内部通过子查询将外键管理表中的数据页全部给你封装到对象中
之后对象点当前表或者外键关联表中的字段也都不需要走数据库了
优缺点比较
select_related连表操作 好处在于只走一次sql查询
耗时耗在 连接表的操作 10s
prefetch_related子查询 走两次sql查询
耗时耗在 查询次数 1s
# select_related和prefetch_related # res = models.Book.objects.get(pk=1) # print(res.publish.name) # res = models.Book.objects.select_related('publish') # for r in res: # print(r.publish.name) # print(r.publish.addr) """ 内部是连表操作 现将关系表全部链接起来 之后再一次性查询出来 封装到对象中 数据对象之后在获取任意表中的数据的时候都不需要再走数据库了 因为全部封装成了对象的属性 select_related括号内只能传外键字段 并且不能是多对多字段 只能是一对多和一对一 select_related(外键字段1__外键字段2__外键字段3...) """ # prefetch_related # res = models.Book.objects.prefetch_related('publish') # # print(res) # # for r in res: # print(r.publish.name) """ prefetch_related内部是子查询 但是给你的感觉是连表操作 内部通过子查询将外键管理表中的数据页全部给你封装到对象中 之后对象点当前表或者外键关联表中的字段也都不需要走数据库了 """ """ 优缺点比较 select_related连表操作 好处在于只走一次sql查询 耗时耗在 连接表的操作 10s prefetch_related子查询 走两次sql查询 耗时耗在 查询次数 1s """
django orm如何开启事务操作
事务的四大特性(ACID)
原子性
一致性
隔离性
持久性
start transaction rollback commit
代码:
# django orm开启事务操作 from django.db import transaction with transaction.atomic(): # 在with代码块中执行的orm语句同属于一个事务 pass # 代码块运行结束 事务就结束了 事务相关的其他配置 你可以百度搜搜看
MTV与MVC模型
MTV django号称是MTV框架
M:models
T:templates
V:views
MVC
M:models
V:views
C:controller 控制器(路由分发 urls.py)
本质:MTV本质也是MVC
BMS 图书管理系统
代码:
app01/models.py
from django.db import models # Create your models here. from django.db.models import Field class RealCharField(Field): def __init__(self,max_length,*args,**kwargs): self.max_length = max_length # 拦截一个父类的方法 操作完之后 利用super调用父类的方法 super().__init__(max_length=max_length,*args,**kwargs) def db_type(self,connection): return 'char(%s)'%self.max_length class Movie(models.Model): textField = RealCharField(max_length=64) class Userinfo(models.Model): username = models.CharField(max_length=32) gender_choices = ( (1,'男'), (2,'女'), (3,'其他'), ) gender = models.IntegerField(choices=gender_choices) # 该字段还是存数字 并且可以匹配关系之外的数字 record_choices = (('checked','已签到'), ('vacate','请假'), ('noshow','缺勤'), ('leave_early','早退'), ) record = models.CharField('上课记录',choices=record_choices,default='checked',max_length=64) class Book(models.Model): title = models.CharField(max_length=32) price = models.CharField(max_length=32) publish_time = models.DateField(auto_now_add=True) authors = models.ManyToManyField(to='Author') publish = models.ForeignKey(to='Publish') class Publish(models.Model): name = models.CharField(max_length=32) addr = models.CharField(max_length=64) class Author(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() author_detail = models.OneToOneField(to='AuthorDetail') class AuthorDetail(models.Model): phone = models.BigIntegerField() addr = models.CharField(max_length=64)
app01/views.py
from django.shortcuts import render,HttpResponse,redirect,reverse from app01 import models # Create your views here. def home(request): return render(request,'home.html') def show_book(request): book_queryset = models.Book.objects.all() return render(request,'book_list.html',locals()) def add_book(request): if request.method == 'POST': title = request.POST.get('title') price = request.POST.get('price') publish_time = request.POST.get('publish_time') publish_id = request.POST.get('publish') authors_list = request.POST.getlist('authors') book_obj = models.Book.objects.create(title=title,price=price,publish_time=publish_time,publish_id=publish_id) # 书籍与作者关系 book_obj.authors.add(*authors_list) _url = reverse('show') return redirect(_url) publish_queryset = models.Publish.objects.all() author_queryset = models.Author.objects.all() return render(request,'add_book.html',locals()) def edit_book(request,edit_id): edit_obj = models.Book.objects.filter(pk=edit_id).first() if request.method == 'POST': title = request.POST.get('title') price = request.POST.get('price') publish_time = request.POST.get('publish_time') publish_id = request.POST.get('publish') author_list = request.POST.getlist('authors') models.Book.objects.filter(pk=edit_id).update(title=title,price=price,publish_time=publish_time,publish_id=publish_id) edit_obj.authors.set(author_list) # 重定向到书籍展示页 _url = reverse('show') return redirect(_url) publish_queryset = models.Publish.objects.all() author_queryset = models.Author.objects.all() return render(request,'edit_book.html',locals()) def delete_book(request,delete_id): models.Book.objects.filter(pk=delete_id).delete() _url = reverse('show') return redirect(_url)
BMS/__init__.py
import pymysql pymysql.install_as_MySQLdb()
BMS/settings.py
""" Django settings for BMS project. Generated by 'django-admin startproject' using Django 1.11.11. For more information on this file, see https://docs.djangoproject.com/en/1.11/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/1.11/ref/settings/ """ import os # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = '9j+w4f3$e%&3su_1d7-dp)hh*&#yz$xwfyp=#q=j5k-5&-yh!y' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01.apps.App01Config', ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] ROOT_URLCONF = 'BMS.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')] , 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] WSGI_APPLICATION = 'BMS.wsgi.application' # Database # https://docs.djangoproject.com/en/1.11/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'BMS', 'USER':'root', 'PASSWORD':'', 'HOST':'127.0.0.1', 'PORT':3306, 'CHARSET':'utf8', } } # Password validation # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] # Internationalization # https://docs.djangoproject.com/en/1.11/topics/i18n/ LANGUAGE_CODE = 'en-us' TIME_ZONE = 'UTC' USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.11/howto/static-files/ STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR,'static') ] # 自动显示命令对应sql命令 # LOGGING = { # 'version': 1, # 'disable_existing_loggers': False, # 'handlers': { # 'console':{ # 'level':'DEBUG', # 'class':'logging.StreamHandler', # }, # }, # 'loggers': { # 'django.db.backends': { # 'handlers': ['console'], # 'propagate': True, # 'level':'DEBUG', # }, # } # }
BMS/urls.py
"""BMS URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/1.11/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.conf.urls import url, include 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) """ from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), # 主页 url(r'^$', views.home,name='home'), # 书籍展示页 url(r'^book_list/', views.show_book,name='show'), # 书籍添加页 url(r'^add_book/', views.add_book,name='add'), # 书籍编辑页 url(r'^edit_book/(?P<edit_id>\d+)', views.edit_book,name='edit'), # 书籍删除页 url(r'^delete_book/(\d+)', views.delete_book,name='delete'), ]
templates/add_book.html
{% extends 'home.html' %} {% block content %} <h2 class="text-center">添加书籍</h2> <form action="" method="post"> <p>书名: <input type="text" name="title" class="form-control"> </p> <p>价格: <input type="text" name="price" class="form-control"> </p> <p>出版日期: <input type="date" name="publish_time" class="form-control"> </p> <p>出版社: <select name="publish" id="" class="form-control"> {% for publish_obj in publish_queryset %} <option value="{{ publish_obj.pk }}">{{ publish_obj.name }}</option> {% endfor %} </select> </p> <p>作者: <select name="authors" id="" class="form-control" multiple> # 多选 {% for author_obj in author_queryset %} <option value="{{ author_obj.pk }}">{{ author_obj.name }}</option> {% endfor %} </select> </p> <input type="submit" class="btn btn-primary"> </form> {% endblock %}
templates/book_list.html
{% extends 'home.html' %} {% block content %} <div> <a href="{% url 'add' %}" class="btn btn-success">新增</a> </div> <br> <table class="table table-hover table-striped table-bordered"> <thead> <tr> <th>序号</th> <th>书名</th> <th>价格</th> <th>出版日期</th> <th>出版社</th> <th>作者</th> <th>操作</th> </tr> </thead> <tbody> {% for book_obj in book_queryset %} <tr> <td>{{ forloop.counter }}</td> <td>{{ book_obj.title }}</td> <td>{{ book_obj.price }}</td> <td>{{ book_obj.publish_time|date:'Y-m-d' }}</td> <td>{{ book_obj.publish.name}}</td> <td> {% for author_obj in book_obj.authors.all %} {% if forloop.last %} {{ author_obj.name }} {% else %} {{ author_obj.name }}, {% endif %} {% endfor %} </td> <td> <a href="{% url 'edit' book_obj.pk %}" class="btn btn-primary btn-sm">编辑</a> <a href="{% url 'delete' book_obj.pk %}" class="btn btn-danger btn-sm">删除</a> </td> </tr> {% endfor %} </tbody> </table> <nav aria-label="Page navigation" class="text-center"> <ul class="pagination"> <li> <a href="#" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> <li><a href="#">1</a></li> <li><a href="#">2</a></li> <li><a href="#">3</a></li> <li><a href="#">4</a></li> <li><a href="#">5</a></li> <li> <a href="#" aria-label="Next"> <span aria-hidden="true">»</span> </a> </li> </ul> </nav> {% endblock %}
templates/edit_book.html
{% extends 'home.html' %} {% block content %} <h2 class="text-center">编辑书籍</h2> <form action="" method="post"> <p>书名: <input type="text" name="title" class="form-control" value="{{ edit_obj.title }}"> </p> <p>价格: <input type="text" name="price" class="form-control" value="{{ edit_obj.price }}"> </p> <p>出版日期 <input type="date" name="publish_time" class="form-control" value="{{ edit_obj.publish_time|date:'Y-m-d' }}"> </p> <p>出版社 <select name="publish" id="" class="form-control"> {% for publish_obj in publish_queryset %} {% if edit_obj.publish == publish_obj %} <option value="{{ publish_obj.pk }}" selected>{{ publish_obj.name }}</option> {% else %} <option value="{{ publish_obj.pk }}">{{ publish_obj.name }}</option> {% endif %} {% endfor %} </select> </p> <p>作者: <select name="authors" id="" class="form-control" multiple> {% for author_obj in author_queryset %} {% if author_obj in edit_obj.authors.all %} <option value="{{ author_obj.pk }}" selected>{{ author_obj.name }}</option> {% else %} <option value="{{ author_obj.pk }}">{{ author_obj.name }}</option> {% endif %} {% endfor %} </select> </p> <input type="submit" class="btn btn-warning"> </form> {% endblock %}
templates/home.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> {% load static %} <link href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}" rel="stylesheet"> <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script> </head> <body> <nav class="navbar navbar-inverse"> <div class="container-fluid"> <!-- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">BMS</a> </div> <!-- Collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li class="active"><a href="#">图书 <span class="sr-only">(current)</span></a></li> <li><a href="#">出版社</a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">更多 <span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#">Action</a></li> <li><a href="#">Another action</a></li> <li><a href="#">Something else here</a></li> <li role="separator" class="divider"></li> <li><a href="#">Separated link</a></li> <li role="separator" class="divider"></li> <li><a href="#">One more separated link</a></li> </ul> </li> </ul> <form class="navbar-form navbar-left"> <div class="form-group"> <input type="text" class="form-control" placeholder="Search"> </div> <button type="submit" class="btn btn-default">Submit</button> </form> <ul class="nav navbar-nav navbar-right"> <li><a href="#">Link</a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#">Action</a></li> <li><a href="#">Another action</a></li> <li><a href="#">Something else here</a></li> <li role="separator" class="divider"></li> <li><a href="#">Separated link</a></li> </ul> </li> </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> <div class="container-fluid"> <div class="row"> <div class="col-md-3"> <div class="list-group"> <a href="{% url 'home' %}" class="list-group-item active"> 首页 </a> <a href="{% url 'show' %}" class="list-group-item">图书列表</a> <a href="#" class="list-group-item">出版社列表</a> <a href="#" class="list-group-item">作者列表</a> <a href="#" class="list-group-item">更多操作</a> </div> </div> <div class="col-md-9"> <div class="panel panel-primary"> <div class="panel-heading"> <h3 class="panel-title">BMS</h3> </div> <div class="panel-body"> {% block content %} <div class="jumbotron"> <h1>欢迎来到BMS系统</h1> <p>请收藏网页持续关注</p> <p><a class="btn btn-primary btn-lg" href="#" role="button">点这里</a></p> </div> {% endblock %} </div> </div> </div> </div> </div> </body> </html>