Django开发:(3.1)ORM:单表操作
Posted neozheng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django开发:(3.1)ORM:单表操作相关的知识,希望对你有一定的参考价值。
MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大的减轻了开发人员的工作量,不需要面对因数据库变更而导致的无效劳动
ORM是“对象-关系-映射”的简称。
mysql中的表对应python中的类,表的字段对应类的属性,表的记录对应类的实例化的对象
单表操作
创建表
1. 创建模型
创建名为app01的app,在app01下的models.py中创建模型:
from django.db import models # Create your models here. class Book(models.Model): # 类名可以随便起,但一定得继承 models.Model id = models.AutoField(primary_key=True) # AutoField表示自增字段; primary_key=True 表示是主键 title = models.CharField(max_length=32) # state = models.BooleanField() pub_date = models.DateField() price = models.DecimalField(max_digits=8,decimal_places=2) publish = models.CharField(max_length=32)
2. 更多字段和参数
每个字段有一些特有的参数,例如,CharField需要max_length参数来指定VARCHAR
数据库字段的大小。还有一些适用于所有字段的通用参数。
3. settings配置
若想将模型转为mysql数据库中的表,需要在settings中配置:
DATABASES = { ‘default‘:{ ‘ENGINE‘:‘django.db.backends.mysql‘, ‘NAME‘:‘orm‘, # 要连接的数据库,连接前需要先创建好 ‘USER‘:‘root‘, # 连接数据库的用户名 ‘PASSWORD‘:‘tj037778‘, # 连接数据库的密码 ‘HOST‘:‘127.0.0.1‘, # 连接主机 ‘PORT‘:3306 # 端口 } }
注意1:NAME即数据库的名字,在mysql连接前该数据库必须已经创建(ORM只能处理到表这一层,数据库操作不了),而上面的sqlite数据库下的db.sqlite3则是项目自动创建 USER和PASSWORD分别是数据库的用户名和密码。设置完后,再启动我们的Django项目前,我们需要激活我们的mysql。然后,启动项目,会报错:no module named MySQLdb 。这是因为django默认你导入的驱动是MySQLdb,可是MySQLdb 对于py3有很大问题,所以我们需要的驱动是PyMySQL 所以,我们只需要找到项目名文件下的__init__,在里面写入:
import pymysql pymysql.install_as_MySQLdb()
最后通过两条数据库迁移命令即可在指定的数据库中创建表 :
python manage.py makemigrations
python manage.py migrate
注意2:确保配置文件中的INSTALLED_APPS中写入我们创建的app名称
# 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‘, ]
注意3:如果报错如下:
django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.3 or newer is required; you have 0.7.11.None
MySQLclient目前只支持到python3.4,因此如果使用的更高版本的python,需要修改如下:
通过查找路径:D:pythonLibsite-packagesdjangodbackendsmysqlase.py
把里面的
if version < (1, 3, 3): raise ImproperlyConfigured("mysqlclient 1.3.3 or newer is required; you have %s" % Database.__version__)
注释掉 就OK了。
注意4: 如果想打印orm转换过程中的sql,需要在settings中进行如下配置:
LOGGING = { ‘version‘: 1, ‘disable_existing_loggers‘: False, ‘handlers‘: { ‘console‘:{ ‘level‘:‘DEBUG‘, ‘class‘:‘logging.StreamHandler‘, }, }, ‘loggers‘: { ‘django.db.backends‘: { ‘handlers‘: [‘console‘], ‘propagate‘: True, ‘level‘:‘DEBUG‘, }, } }
添加表记录
urls.py
from django.contrib import admin from django.urls import path from app01 import views urlpatterns = [ path(‘admin/‘, admin.site.urls), path(r‘index/‘,views.index) ]
app01/models.py
from django.db import models # Create your models here. class Book(models.Model): # 类名可以随便起,但一定得继承 models.Model id = models.AutoField(primary_key=True) # AutoField表示自增字段; primary_key=True 表示是主键 title = models.CharField(max_length=32) # state = models.BooleanField() pub_date = models.DateField() price = models.DecimalField(max_digits=8,decimal_places=2) publish = models.CharField(max_length=32)
app01/views.py
from django.shortcuts import render,HttpResponse # Create your views here. # 先把模型导入进来 from app01.models import Book def index(request): # 添加表记录 # 方式一:实例化Book对象 book_obj = Book(id=1,title="python全栈开发",pub_date="2018-6-7",price=100,publish="IT出版社") # pub_date是一个日期类型,一定得按照"年-月-日"的格式 book_obj.save() # save()之后记录才会生成 # 表里面的一条记录就是类的一个对象 # 方式二:用 objects去调用create; create方法有返回值,返回值就是生成的记录对象 book_obj2 = Book.objects.create(title="linux运维",pub_date="2015-6-7",price=100,publish="IT出版社") # id是自增的,所以无需再写 # 这种方式不需要 save();.objects.create(kwargs) 直接就在数据库中生成了一条记录(对象),并把这个对象返回给 book_obj2(我们也就可以打印book_obj2中的属性) print(book_obj2.pub_date) return HttpResponse("ok")
单表查询:
models.py
from django.db import models # Create your models here. class Book(models.Model): # 类名可以随便起,但一定得继承 models.Model id = models.AutoField(primary_key=True) # AutoField表示自增字段; primary_key=True 表示是主键 title = models.CharField(max_length=32) # state = models.BooleanField() pub_date = models.DateField() price = models.DecimalField(max_digits=8,decimal_places=2) publish = models.CharField(max_length=32) def __str__(self): # 只是控制了对象的打印形式 return self.title
views.py
from django.shortcuts import render,HttpResponse # Create your views here. # 先把模型导入进来 from app01.models import Book def index(request): # #######################查询表结构API####################### # 注意:要知道每个方法的返回值是什么、以及每个方法是谁来调用的 # 1. all() :查询所有结果;返回值是一个QuerySet数据类型(Django自定义的数据类型),调用者是 objects all_books = Book.objects.all() print(all_books) # Book类没有 __str()__方法时的打印结果: # <QuerySet [<Book: Book object (1)>, <Book: Book object (2)>]> # Book有 __str()__ 方法时的打印结果: # <QuerySet [<Book: python全栈开发>, <Book: linux运维>]> # QuerySet数据类型:相当于 [obj1,obj2,...],可用列表的方式去处理它 for obj in all_books: # 支持遍历 print(obj.title,obj.pub_date) print(all_books[1].publish) # 支持索引 # 2. first(),last()方法;返回值是一个model(模型)对象,调用者是 QuerySet对象 book1 = Book.objects.all().first() # 相当于 Book.objects.all()[0] book2 = Book.objects.all().last() print(book1,book2) # 3. filter()方法:返回值:QuerySet对象,调用者:管理器(objects) books = Book.objects.filter(title="python全栈开发",price=100) # filter()的作用相当于sql语句的where;# 返回值:[obj1,obj2,....];多个过滤条件用逗号分隔 print(books) # filter()方法也可以调用 first(),last()方法 print(books.first()) # 4. get()方法:有且只有一个查询结果时才有意义;如果有多个查询结果或者没有查询结果,报错;所以,返回值:model对象 book_get = Book.objects.get(title="python全栈开发") print(book_get.price) # 5. exclude():排除条件的过滤,对应filter();返回QuerySet ret = Book.objects.exclude(title="python全栈开发") print(ret) # 6. order_by():按照某种条件排序(默认是按照id);返回值:QuerySet,调用者:QuerySet book_order_asc = Book.objects.all().order_by("id") print(book_order_asc) book_order_desc = Book.objects.all().order_by("-id") # 按照降序排列 print(book_order_desc) book_price_desc = Book.objects.all().order_by("-price") # 按照价格降序排列 print(book_price_desc) # Book.objects.all().order_by("-price","id") # 先按照价格降序排列,再按照id升序 # 要熟悉orm的链式操作 # 7. reverse() :对查询结果反向排序 # 8. count():计数;返回值:int,调用者:QuerySet Book.objects.all().count() # 计数里面有多少个元素 # 9. exists():如果QuerySet包含数据,就返回True,否则返回False ret_exists = Book.objects.all().exists() # 判断 Book.objects.all() 里面是否有数据 # 10. values(*field):field代表字段;values()具有遍历作用,返回一个QuerySet --- 一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列;返回值:QuerySet(列表里面放字典),调用者:QuerySet # values()方法很重要 ret_values = Book.objects.all().values("price","title") print(ret_values) # <QuerySet [{‘price‘: Decimal(‘100.00‘), ‘title‘: ‘python全栈开发‘}, {‘price‘: Decimal(‘100.00‘), ‘title‘: ‘linux运维‘}]> print(ret_values[0].get("price")) # 100.00 # 11. values_list(*field):它与values()非常相似,它返回的QuerySet里面是一个元组序列,values返回的是一个字典序列 ret_values_list = Book.objects.all().values_list("price", "title") print(ret_values_list) # <QuerySet [(Decimal(‘100.00‘), ‘python全栈开发‘), (Decimal(‘100.00‘), ‘linux运维‘)]> # 12. distinct():从返回结果中剔除重复纪录(通常配合values,values_list一起使用) ret_distinct = Book.objects.all().values("price").distinct() print(ret_distinct) # <QuerySet [{‘price‘: Decimal(‘100.00‘)}]> # 注: Book.objects.all().distinct() 这种写法没有任何意义 # #######################查询表结构之模糊查询####################### # 1. __gt :大于;__lt:小于;返回值:QuerySet price__gt = Book.objects.filter(price__gt=50,price__lt=200) print("__gt",price__gt) # 2. __startswith:以什么开头;返回值:QuerySet obj_start = Book.objects.filter(title__startswith="py") print(obj_start) # 3. __contains:包含什么;返回值:QuerySet # 4. __icontains:包含某些元素(不区分大小写) obj_contains = Book.objects.filter(title__contains="x") print(obj_contains) # 5. __in = [] :是列表中的一个;返回值:QuerySet obj_in = Book.objects.filter(price__in=[100,150,200]) print(obj_in) # 6. __year : 某一年的(只有date类型有);返回值:QuerySet obj_year = Book.objects.filter(pub_date__year=2018) print(obj_year) # 7. __range = [] : 在某个区间(包含两端) obj_range = Book.objects.filter(price__range=[50,100]) print("range",obj_range) return HttpResponse("ok")
单表之删除和编辑
views.py
from django.shortcuts import render,HttpResponse # Create your views here. # 先把模型导入进来 from app01.models import Book def index(request): # #######################删除、修改表记录####################### # delete() : 删除;调用者:QuerySet对象 或者 model对象;返回值是删除元素的一些信息 # Book.objects.filter(pub_date__year=2018).delete() # 需要都把记录查询出来才能删除;调用者:QuerySet对象 # Book.objects.filter(pub_date__year=2015).first().delete() # 调用者:model对象 # update():编辑记录; 调用者:QuerySet Book.objects.filter(title__contains="linux").update(title="linux运营维护") return HttpResponse("ok")
图书管理系统
settings.py
""" Django settings for bookms project. Generated by ‘django-admin startproject‘ using Django 2.0.1. For more information on this file, see https://docs.djangoproject.com/en/2.0/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/2.0/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/2.0/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = ‘m6=&s25aszxks#m(5f57mdpi)hc%v7#&[email protected]‘ # 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 = ‘bookms.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 = ‘bookms.wsgi.application‘ # Database # https://docs.djangoproject.com/en/2.0/ref/settings/#databases # DATABASES = { # ‘default‘: { # ‘ENGINE‘: ‘django.db.backends.sqlite3‘, # ‘NAME‘: os.path.join(BASE_DIR, ‘db.sqlite3‘), # } # } DATABASES = { ‘default‘:{ ‘ENGINE‘:‘django.db.backends.mysql‘, ‘NAME‘:‘bookms‘, # 要连接的数据库,连接前需要先创建好 ‘USER‘:‘root‘, # 连接数据库的用户名 ‘PASSWORD‘:‘tj037778‘, # 连接数据库的密码 ‘HOST‘:‘127.0.0.1‘, # 连接主机 ‘PORT‘:3306 # 端口 } } # Password validation # https://docs.djangoproject.com/en/2.0/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/2.0/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/2.0/howto/static-files/ STATIC_URL = ‘/static/‘ # 若存放静态文件的static目录在app目录下,则改局生效,无需定义下面的 # STATICFILES_DIRS = [ # os.path.join(BASE_DIR,"static"), # ] # 若存放静态文件的static目录在project目录下,则用该定义 LOGGING = { ‘version‘: 1, ‘disable_existing_loggers‘: False, ‘handlers‘: { ‘console‘:{ ‘level‘:‘DEBUG‘, ‘class‘:‘logging.StreamHandler‘, }, }, ‘loggers‘: { ‘django.db.backends‘: { ‘handlers‘: [‘console‘], ‘propagate‘: True, ‘level‘:‘DEBUG‘, }, } }
urls.py
"""bookms URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/2.0/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: path(‘‘, views.home, name=‘home‘) Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: path(‘‘, Home.as_view(), name=‘home‘) Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path(‘blog/‘, include(‘blog.urls‘)) """ from django.contrib import admin from django.urls import path,re_path from app01 import views urlpatterns = [ path(‘admin/‘, admin.site.urls), path(r"addbook/",views.addbook), path(r"books/",views.books), # (d+)用于匹配获取表记录的主键(书的id) re_path(r"books/(d+)/delete",views.bookdel), re_path(r"books/(d+)/edit",views.bookedit) ]
views.py
from django.shortcuts import render,HttpResponse,redirect # Create your views here. # 把模型表引入 from app01.models import Book def addbook(request): # 由于templates/addbook.html 中 form标签的 action没写,所以还是提交到了当前页面index.html if request.method == "POST": title = request.POST.get("title") price = request.POST.get("price") date = request.POST.get("date") press = request.POST.get("press") # 添加记录 book_obj = Book.objects.create(title=title,price=price,pub_date=date,publish=press) return redirect("/books/") return render(request,"addbook.html") def books(request): books_list = Book.objects.all() return render(request,"books.html",locals()) def bookdel(request,pk): # 把对应ID的书删除 Book.objects.filter(id=pk).delete() # redirect()的作用就是让浏览器往重定向的路径再发一次请求 return redirect("/books/") def bookedit(request,id): # 编辑对应ID的书 # 先获取对应书对象 book_obj = Book.objects.filter(id=id).first() # 由于编辑后的内容还是提交到当前页面,所以在这个函数里面要判断请求是否就POST if request.method == "POST": # 获取编辑后的内容 title = request.POST.get("title") price = request.POST.get("price") date = request.POST.get("date") press = request.POST.get("press") # 把编辑后的内容更新到表中 Book.objects.filter(id=id).update(title=title,price=price,pub_date=date,publish=press) # 更新完后重定向到 books.html 页面 return redirect("/books/") return render(request,"editbook.html",{"book_obj":book_obj})
models.py
from django.db import models # Create your models here. class Book(models.Model): id = models.AutoField(primary_key=True) title = models.CharField(max_length=32) pub_date = models.DateField() price = models.DecimalField(max_digits=8, decimal_places=2) publish = models.CharField(max_length=32)
books.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>addbook</title> <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css"> <style> .container{ margin-top: 70px; } .btn{ margin-bottom: 10px; } </style> </head> <body> <h3>查看书籍</h3> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <a href="/addbook/" class="btn btn-primary">添加书籍</a> {# .table-striped 类可以给 <tbody> 之内的每一行增加斑马条纹样式;.table-bordered 类为表格和其中的每个单元格增加边框。#} <table class="table table-striped table-bordered"> <thead> <tr> <th>书籍名称</th> <th>价格</th> <th>出版日期</th> <th>出版社</th> <th>编辑</th> <th>删除</th> </tr> </thead> <tbody> {# 遍历 books_list是的每一个对象(表记录),把每条表记录添加到 table的一行中 #} {% for book in books_list %} <tr> <td>{{ book.title }}</td> <td>{{ book.price }}</td> {# 利用date过滤器格式化时间样式 #} <td>{{ book.pub_date|date:"Y-m-d" }}</td> <td>{{ book.publish }}</td> {# 动态的为每个a标签添加索引 #} <td><a href="/books/{{ book.pk }}/edit" class="btn btn-info">编辑</a></td> {# 把主键id添加到a标签的路径中;.pk表示model对象的主键 #} <td><a href="/books/{{ book.pk }}/delete" class="btn btn-danger">删除</a></td> </tr> {% endfor %} </tbody> </table> </div> </div> </div> </body> </html>
addbook.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>addbook</title> <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css"> <style> .container{ margin-top: 70px; } .btn{ margin-top: 10px; } </style> </head> <body> <h3>添加书籍</h3> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <form action="" method="post"> {% csrf_token %} <div> <label for="">书籍名称</label> {# form-controlform-control控件,可以为input元素添加CSS定制样式#} <input type="text" class="form-control" name="title"> </div> <div> <label for="">价格</label> <input type="text" class="form-control" name="price"> </div> <div> <label for="">出版日期</label> {# date类型:能够下拉选择日期 #} <input type="date" class="form-control" name="date"> </div> <div> <label for="">出版社</label> <input type="text" class="form-control" name="press"> </div> {# btn btn-success:绿色按钮;pull-right:右移 #} <input type="submit" class="btn btn-success pull-right"> </form> </div> </div> </div> </body> </html>
editbook.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>addbook</title> <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css"> <style> .container{ margin-top: 70px; } .btn{ margin-top: 10px; } </style> </head> <body> <h3>编辑书籍</h3> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> {# form标签的action没写,所以默认还是会提交到当前页面 #} <form action="" method="post"> {% csrf_token %} <div> <label for="">书籍名称</label> {# 编辑时书名这一栏的内容是该对象原先的title;其它栏同理 #} <input type="text" class="form-control" name="title" value="{{ book_obj.title }}"> </div> <div> <label for="">价格</label> <input type="text" class="form-control" name="price" value="{{ book_obj.price }}"> </div> <div> <label for="">出版日期</label> {# 此处的日期也需要用date过滤器格式化,要不然显示不出来 #} <input type="date" class="form-control" name="date" value="{{ book_obj.pub_date|date:‘Y-m-d‘ }}"> </div> <div> <label for="">出版社</label> <input type="text" class="form-control" name="press" value="{{ book_obj.publish }}"> </div> {# btn btn-success:绿色按钮;pull-right:右移 #} <input type="submit" class="btn btn-success pull-right"> </form> </div> </div> </div> </body> </html>
以上是关于Django开发:(3.1)ORM:单表操作的主要内容,如果未能解决你的问题,请参考以下文章