MVC或者MVC框架中包括一個重要的部分,就是ORM,它實現了數據模型與數據庫的解耦,即數據模型的設計不須要依賴於特定的數據庫,經過簡單的配置就能夠輕鬆更換數據庫,這極大的減輕了開發人員的工做量,不須要面對因數據庫變動而致使的無效勞動css
ORM是「對象-關係-映射」的簡稱。html
Mysql中的表對應python中的類,表的字段對應類的屬性,表的記錄對應類的實例化的對象python
1. 建立模型mysql
建立名爲app01的app,在app01下的models.py中建立模型:linux
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. 更多字段和參數git
每一個字段有一些特有的參數,例如,CharField須要max_length參數來指定VARCHAR
數據庫字段的大小。還有一些適用於全部字段的通用參數。sql
3. settings配置數據庫
若想將模型轉爲mysql數據庫中的表,須要在settings中配置:django
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 因此,咱們只須要找到項目名(project)文件下的__init__(ORM/ORM/__init__.py),在裏面寫入:bootstrap
import pymysql pymysql.install_as_MySQLdb()
最後經過兩條數據庫遷移命令便可在指定的數據庫中建立表 :
python manage.py makemigrations
python manage.py migrate
# makemigrations 後並無在數據庫生成表,而是在對應的 migrationsns 文件夾下生成了 py 文件 # migrate 時會執行 migrations文件夾下的 py文件(至於執行哪一個py文件,程序會先去 django自帶的 django_migrations 這張表中去查,若是migrationsns 文件夾下人某個py文件在 django_migrations 這張表已經存在,則 migrate時則會跳過這個py文件不執行,即已經執行過的py文件會存放在 django_migrations表中) # 修改數據庫的時候,儘可能用 makemigrations 和 migrate,不要直接在Navicat 中修改
注意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:\python\Lib\site-packages\django\db\backends\mysql\base.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")
補充:例如上面的4.get() 方法,若是值不存在,能夠捕獲到這個異常
from django.core.exceptions import ObjectDoesNotExist # ObjectDoesNotExist 值不存在的異常類型
單表之刪除和編輯
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#&e0$kmak48@80xr7t0h' # 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>