【Python之路】第二十二篇--Django【基礎篇】

1 Django流程介紹

MTV模式      php

        著名的MVC模式:所謂MVC就是把web應用分爲模型(M),控制器(C),視圖(V)三層;他們之間以一種插件似的,鬆耦合的方式鏈接在一塊兒。html

        模型負責業務對象與數據庫的對象(ORM),視圖負責與用戶的交互(頁面),控制器(C)接受用戶的輸入調用模型和視圖完成用戶的請求。前端

        

       Django的MTV模式本質上與MVC模式沒有什麼差異,也是各組件之間爲了保持鬆耦合關係,只是定義上有些許不一樣,Django的MTV分別表明:python

       Model(模型):負責業務對象與數據庫的對象(ORM)mysql

       Template(模版):負責如何把頁面展現給用戶jquery

       View(視圖):負責業務邏輯,並在適當的時候調用Model和Templategit

       此外,Django還有一個url分發器,它的做用是將一個個URL的頁面請求分發給不一樣的view處理,view再調用相應的Model和Templateweb

2 開始Django

一、建立Django項目正則表達式

django-admin startproject mysite

當前目錄下會生成一個 mysite的工程,目錄結構以下:sql

 

  • manage.py ----- Django項目裏面的工具,經過它能夠調用django shell和數據庫等。

  • settings.py ---- 包含了項目的默認設置,包括數據庫信息,調試標誌以及其餘一些工做的變量。

  • urls.py ----- 負責把URL模式映射到應用程序。

二、在mysite目錄下建立app應用

python manage.py startapp blog

三、啓動django項目

python manage.py runserver 8899   # ip:端口,默認本地ip

當咱們訪問:http://127.0.0.1:8899/ 時就能夠看到:

3 Setting文件配置

方法一:

  靜態文件在單獨的app下:如 /app01/static/app01/JS/jquery-2.1.4.min.js  (其中藍色app01目錄爲必須,但可改其餘名字,static文件夾也可改其餘名字)

# index.html
{% load static %} <script src="{% static 'app01/JS/jquery-2.1.4.min.js' %}"></script>

  setting文件設置: (其中app01爲項目名字,static爲保存靜態文件的文件夾。)

STATIC_URL = '/whattttt/'   # 前端使用前綴

STATICFILES_DIRS = (
    os.path.join(BASE_DIR,'app01','static'),
)

方法二: (同上述setting配置)

# index.html
<script src="/whattttt/app01/JS/jquery-2.1.4.min.js"></script>

方法三:  使用別名的形式

# index.html
{% load static %} <script src="{% static 'biemin/JS/jquery-2.1.4.min.js' %}"></script> <script src="/whattttt/biemin/JS/jquery-2.1.4.min.js"></script>

  setting文件設置: 

STATIC_URL = '/whattttt/'

STATICFILES_DIRS = (
    ('biemin',os.path.join(BASE_DIR,'app01','static','app01')),
)

補充:

  若是不想每次在模版中加載靜態文件都使用 {% load static%}

  能夠在settings.py中的 TEMPLATES/OPTIONS添加'builtins':['django.templatetags.static']

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',
      ],
      #添加在這個位置
      'builtins' : [
        'django.templatetags.static'
      ],
    },
  },
]

  

4 Django URL路由系統

  它的本質是URL模式以及要爲該URL模式調用的視圖函數之間的映射表

urlpatterns = [
    url(正則表達式, view函數,參數,別名),
]

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^index/', views.index , {"a":'123'} , 'FFF'),
]

參數說明:

  • 一個正則表達式字符串

  • 一個可調用對象,一般爲一個視圖函數或一個指定視圖函數路徑的字符串

  • 可選的要傳遞給視圖函數的默認參數(字典形式)

  • 一個可選的name參數 (別名)

from django.conf.urls import url
from app01 import views

urlpatterns = [
    url(r'^index/', views.index),
    url(r'^articles/([0-9]{4})/$', views.year_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]
demo

無命名分組:

  加了( )後,視圖函數須要添加一個形參,都爲字符串類型 !   

urlpatterns = [
    url(r'^articles/([0-9]{4})/$', views.year_archive),
]

# 視圖函數:
def year_archive(request,y):
    pass

命名分組 :

  視圖函數形參名爲分組名 ! 

urlpatterns = [
    url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
]

# 視圖函數:
def year_archive(request,year):
    pass

參數

  加上參數時,對應的視圖函數,必須加上一個形參,形參名必須與參數名相同!

  若是 參數名與正則分組名字相同時,後面覆蓋前面!

urlpatterns = [
    url(r'^index/', views.index , {"a":'123'} , 'FFF'),
]

別名:

  加載時,一行一行去查找 url 中 name = ‘new_login’ 的行 , 而後替換 !

urlpatterns = [
    url(r'^index/', views.login, name = 'new_login'),
]

用法:
<form action = {% url 'new_login' %} >

URL映射分發 :

  每當Django 遇到 include()時,它會去掉URL 中匹配的部分並將剩下的字符串發送給包含的URLconf 作進一步處理。

from django.conf.urls import url,include

urlpatterns = [
    url(r'^hot/', include('app01.urls')),
]

  例子中的正則表達式沒有包含 $(字符串結束匹配符),可是包含一個末尾的斜槓。

from django.conf.urls import url,include
from app01 import views

urlpatterns = [
    url(r'^all/', views.allpage),
]

  頁面訪問 http://127.0.0.1:8000/hot/all 時觸發views.allpage

別名的應用:

urlpatterns = [
    url(r'^index',views.index,name='bieming'),
]
###################

def index(req):
    if req.method=='POST':
        username=req.POST.get('username')
        password=req.POST.get('password')
        if username=='alex' and password=='123':
            return HttpResponse("登錄成功")
    return render(req,'index.html')

#####################

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{#  <form action="/index/" method="post"> #}
     <form action="{% url 'bieming' %}" method="post">
         用戶名:<input type="text" name="username">
         密碼:<input type="password" name="password">
         <input type="submit" value="submit">
     </form>
</body>
</html>

#######################

settings 中註釋掉: csrf該行進行測試demo
MIDDLEWARE = [
    # 'django.middleware.csrf.CsrfViewMiddleware',
]
View Code

5 Django Views(視圖函數)

http請求中產生兩個核心對象:

http請求:HttpRequest對象

http響應:HttpResponse對象

所在位置:django.http

視圖函數接收的參數request就是HttpRequest    檢測方法:isinstance(request,HttpRequest)

HttpRequest對象的屬性:

 

# path:       請求頁面的全路徑,不包括域名
#
# method:     請求中使用的HTTP方法的字符串表示。全大寫表示。例如
#
#                    if  req.method=="GET":
#
#                              do_something()
#
#                    elseif req.method=="POST":
#
#                              do_something_else()
#
# GET:         包含全部HTTP GET參數的類字典對象
#
# POST:       包含全部HTTP POST參數的類字典對象
#
#              服務器收到空的POST請求的狀況也是可能發生的,也就是說,表單form經過
#              HTTP POST方法提交請求,可是表單中可能沒有數據,所以不能使用
#              if req.POST來判斷是否使用了HTTP POST 方法;應該使用  if req.method=="POST"
#
#
#
# COOKIES:     包含全部cookies的標準Python字典對象;keys和values都是字符串。
#
# FILES:      包含全部上傳文件的類字典對象;FILES中的每個Key都是<input type="file" name="" />標籤中                     name屬性的值,FILES中的每個value同時也是一個標準的python字典對象,包含下面三個Keys:
#
#             filename:      上傳文件名,用字符串表示
#             content_type:   上傳文件的Content Type
#             content:       上傳文件的原始內容
#
#
# user:       是一個django.contrib.auth.models.User對象,表明當前登錄的用戶。若是訪問用戶當前
#              沒有登錄,user將被初始化爲django.contrib.auth.models.AnonymousUser的實例。你
#              能夠經過user的is_authenticated()方法來辨別用戶是否登錄:
#              if req.user.is_authenticated();只有激活Django中的AuthenticationMiddleware
#              時該屬性纔可用
#
# session:    惟一可讀寫的屬性,表明當前會話的字典對象;本身有激活Django中的session支持時該屬性纔可用。
View Code

HttpRequest對象的方法:

  get_full_path()   好比:http://127.0.0.1:8000/index33/?name=123 ,req.get_full_path()  獲得的結果就是/index33/?name=123

HttpResponse對象

  對於HttpRequest對象來講,是由django自動建立的,可是,HttpResponse對象就必須咱們本身建立。

  每一個view請求處理方法必須返回一個HttpResponse對象。

HttpResponse 類在 django.http.HttpResponse

在HttpResponse對象上擴展的經常使用方法:

  • 頁面渲染:render,render_to_response,

  • 頁面跳轉:redirect

  • locals():  能夠直接將函數中全部的變量傳給模板    

from django.shortcuts import render,HttpResponse,redirect,render_to_response
import time

def index(request):
    times = time.time()
    
    return render(request,'index.html',{"times":times})  # 頁面渲染
   
    return render(request,'index.html',locals())         # 頁面渲染 , HTML文件路徑在Setting文件中作了拼接處理!
   
    return render_to_response('index.html',locals())     # 頁面渲染 , 能夠不用填寫request
    
    return redirect('/login')           # 跳轉
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>{{ times }}</h1>
</body>
</html>
Demo: index.html

6 Django Models

1. django默認支持sqlite,mysql, oracle,postgresql數據庫。

<1> sqlite

  django默認使用sqlite的數據庫,默認自帶sqlite的數據庫驅動

  引擎名稱:django.db.backends.sqlite3

<2>mysql

  引擎名稱:django.db.backends.mysql

2. mysql驅動程序

  MySQLdb(mysql python)

  mysqlclient

  MySQL

  PyMySQL(純python的mysql驅動程序)

3. 在django的項目中會默認使用sqlite數據庫,在settings裏有以下設置:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

若是咱們想要更改數據庫爲MYSQL,須要修改以下:

DATABASES = {
    'default': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME':'dbname',
    'USER': 'root',
    'PASSWORD': 'xxx',
    'HOST': '',
    'PORT': '',
    }
}

注意:NAME即數據庫的名字,在mysql鏈接前該數據庫必須已經建立,而上面的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

添加日誌記錄:(顯示每次執行的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',
        },
    }
}
LOGGING

4.2  Django的ORM(關係對象映射)

4.2.1  模型類的定義(一)

用於實現面向對象編程語言裏不一樣類型系統的數據之間的轉換,換言之,就是用面向對象的方式去操做數據庫的建立表以及增刪改查等操做。

優勢:1 ORM使得咱們的通用數據庫交互變得簡單易行,並且徹底不用考慮該死的SQL語句。快速開發,由此而來。

          2 能夠避免一些新手程序猿寫sql語句帶來的性能問題。

缺點:1 性能有所犧牲,不過如今的各類ORM框架都在嘗試各類方法,好比緩存,延遲加載登來減輕這個問題。效果很顯著。

          2 對於個別複雜查詢,ORM仍然力不從心,爲了解決這個問題,ORM通常也支持寫raw sql。

下面要開始學習Django ORM語法了,爲了更好的理解,咱們來作一個基本的 書籍/做者/出版商 數據庫結構。 咱們這樣作是由於 這是一個衆所周知的例子,不少SQL有關的書籍也經常使用這個舉例。

實例:咱們來假定下面這些概念,字段和關係

做者模型:

  一個做者有姓名。

做者詳細模型:

  把做者的詳情放到詳情表,包含性別,email地址和出生日期,做者詳情模型和做者模型之間是一對一的關係(one-to-one)(相似於每一個人和他的身份證之間的關係),

  在大多數狀況下咱們沒有必要將他們拆分紅兩張表,這裏只是引出一對一的概念。

出版商模型:

  出版商有名稱,地址,所在城市,省,國家和網站。

書籍模型:

  書籍有書名和出版日期,一本書可能會有多個做者,一個做者也能夠寫多本書,因此做者和書籍的關係就是多對多的關聯關係(many-to-many),

  一本書只應該由一個出版商出版,因此出版商和書籍是一對多關聯關係(one-to-many),也被稱做外鍵。

from django.db import models
class Publisher(models.Model):
    name = models.CharField(max_length=30, verbose_name="名稱")
    address = models.CharField("地址", max_length=50)
    city = models.CharField('城市',max_length=60)
    state_province = models.CharField(max_length=30)
    country = models.CharField(max_length=50)
    website = models.URLField()
 
    class Meta:
        verbose_name = '出版商'
        verbose_name_plural = verbose_name
 
    def __str__(self):
        return self.name
 
class Author(models.Model):
    name = models.CharField(max_length=30)
    def __str__(self):
        return self.name
 
class AuthorDetail(models.Model):
    sex = models.BooleanField(max_length=1, choices=((0, ''),(1, ''),))
    email = models.EmailField()
    address = models.CharField(max_length=50)
    birthday = models.DateField()
    author = models.OneToOneField(Author)
 
class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField(Author)
    publisher = models.ForeignKey(Publisher)
    publication_date = models.DateField()
    price=models.DecimalField(max_digits=5,decimal_places=2,default=10)
    def __str__(self):
        return self.title
表結構

默認狀況下,Django 會給每一個模型添加下面這個字段:

id = models.AutoField(primary_key=True)

完成後,記得在settings 裏的INSTALLED_APPS中加入'app01',而後同步數據庫:

INSTALLED_APPS = [
    ....
    'app01',
]

模型之間的三種關係:一對一,一對多,多對多。

一對一:實質就是在主外鍵(author_id就是foreign key)的關係基礎上,給外鍵加了一個UNIQUE的屬性;

一對多:就是主外鍵關係;

多對多: book類裏定義了一個多對多的字段authors,可是並沒在book表中,這是由於建立了一張新的表:

模型的經常使用字段類型以及參數:

# AutoField
# 一個 IntegerField, 添加記錄時它會自動增加. 你一般不須要直接使用這個字段; 若是你不指定主鍵的話,系統會自動添加一個主鍵字段到你的 model.(參閱 _自動主鍵字段)

# BooleanField
# A true/false field. admin 用 checkbox 來表示此類字段.

# CharField
# 字符串字段, 用於較短的字符串.
# 
# 若是要保存大量文本, 使用 TextField.
# 
# admin 用一個 <input type="text"> 來表示此類字段 (單行輸入).
# 
# CharField 要求必須有一個參數 maxlength, 用於從數據庫層和Django校驗層限制該字段所容許的最大字符數.

# CommaSeparatedIntegerField
# 用於存放逗號分隔的整數值. 相似 CharField, 必需要有 maxlength 參數.

# DateField
# 一個日期字段. 共有下列額外的可選參數:
# 
# Argument    描述
# auto_now    當對象被保存時,自動將該字段的值設置爲當前時間.一般用於表示 "last-modified" 時間戳.
# auto_now_add    當對象首次被建立時,自動將該字段的值設置爲當前時間.一般用於表示對象建立時間.
# admin 用一個文本框 <input type="text"> 來表示該字段數據(附帶一個 JavaScript 日曆和一個"Today"快鍵.
 
# DateTimeField
#  一個日期時間字段. 相似 DateField 支持一樣的附加選項.
# admin 用兩上文本框 <input type="text"> 表示該字段順序(附帶JavaScript shortcuts). 

# EmailField
# 一個帶有檢查 Email 合法性的 CharField,不接受 maxlength 參數.

# FileField
# 一個文件上傳字段.
# 
# 要求一個必須有的參數: upload_to, 一個用於保存上載文件的本地文件系統路徑. 這個路徑必須包含 strftime formatting, 該格式將被上載文件的 date/time 替換(so that uploaded files don't fill up the given directory).
# 
# admin 用一個``<input type="file">``部件表示該字段保存的數據(一個文件上傳部件) .
# 
# 在一個 model 中使用 FileField 或 ImageField 須要如下步驟:
# 
# 在你的 settings 文件中, 定義一個完整路徑給 MEDIA_ROOT 以便讓 Django在此處保存上傳文件. (出於性能考慮,這些文件並不保存到數據庫.) 定義 MEDIA_URL 做爲該目錄的公共 URL. 要確保該目錄對 WEB 服務器用戶賬號是可寫的.
# 在你的 model 中添加 FileField 或 ImageField, 並確保定義了 upload_to 選項,以告訴 Django 使用 MEDIA_ROOT 的哪一個子目錄保存上傳文件.
# 你的數據庫中要保存的只是文件的路徑(相對於 MEDIA_ROOT). 出於習慣你必定很想使用 Django 提供的 get_<fieldname>_url 函數.舉例來講,若是你的 ImageField 叫做 mug_shot, 你就能夠在模板中以 {{ object.get_mug_shot_url }} 這樣的方式獲得圖像的絕對路徑.
# FilePathField
# 可選項目爲某個特定目錄下的文件名. 支持三個特殊的參數, 其中第一個是必須提供的.
# 
# 參數    描述
# path    必需參數. 一個目錄的絕對文件系統路徑. FilePathField 據此獲得可選項目. Example: "/home/images".
# match    可選參數. 一個正則表達式, 做爲一個字符串, FilePathField 將使用它過濾文件名. 注意這個正則表達式只會應用到 base filename 而不是路徑全名. Example: "foo.*\.txt^", 將匹配文件 foo23.txt 卻不匹配 bar.txt 或 foo23.gif.
# recursive    可選參數.要麼 True 要麼 False. 默認值是 False. 是否包括 path 下面的所有子目錄.
# 這三個參數能夠同時使用.
# 
# 我已經告訴過你 match 僅應用於 base filename, 而不是路徑全名. 那麼,這個例子:
# 
# FilePathField(path="/home/images", match="foo.*", recursive=True)
# ...會匹配 /home/images/foo.gif 而不匹配 /home/images/foo/bar.gif
 
# FloatField
# 一個浮點數. 必須 提供兩個 參數:
# 
# 參數    描述
# max_digits    總位數(不包括小數點和符號)
# decimal_places    小數位數
# 舉例來講, 要保存最大值爲 999 (小數點後保存2位),你要這樣定義字段:
# 
# models.FloatField(..., max_digits=5, decimal_places=2)
# 要保存最大值一百萬(小數點後保存10位)的話,你要這樣定義:
# 
# models.FloatField(..., max_digits=19, decimal_places=10)
# admin 用一個文本框(<input type="text">)表示該字段保存的數據.
 
# ImageField
# 相似 FileField, 不過要校驗上傳對象是不是一個合法圖片.它有兩個可選參數:height_field 和 width_field,若是提供這兩個參數,則圖片將按提供的高度和寬度規格保存.
# 
# 該字段要求 Python Imaging Library.

# IntegerField
# 用於保存一個整數.
# 
# admin 用一個``<input type="text">``表示該字段保存的數據(一個單行編輯框)

# IPAddressField
# 一個字符串形式的 IP 地址, (i.e. "24.124.1.30").
# 
# admin 用一個``<input type="text">``表示該字段保存的數據(一個單行編輯框)

# NullBooleanField
# 相似 BooleanField, 不過容許 NULL 做爲其中一個選項. 推薦使用這個字段而不要用 BooleanField 加 null=True 選項.
# 
# admin 用一個選擇框 <select> (三個可選擇的值: "Unknown", "Yes" 和 "No" ) 來表示這種字段數據.

# PhoneNumberField
# 一個帶有合法美國風格電話號碼校驗的 CharField``(格式: ``XXX-XXX-XXXX).

# PositiveIntegerField
# 相似 IntegerField, 但取值範圍爲非負整數(這個字段應該是容許0值的....因此字段名字取得不太好,無符號整數就對了嘛).

# PositiveSmallIntegerField
# 相似 PositiveIntegerField, 取值範圍較小(數據庫相關)

# SlugField
# "Slug" 是一個報紙術語. slug 是某個東西的小小標記(短籤), 只包含字母,數字,下劃線和連字符.它們一般用於URLs.
# 
# 若你使用 Django 開發版本,你能夠指定 maxlength. 若 maxlength 未指定, Django 會使用默認長度: 50. 在之前的 Django 版本,沒有任何辦法改變 50 這個長度.
# 
# 這暗示了 db_index=True.
# 
# 它接受一個額外的參數: prepopulate_from, which is a list of fields from which to auto-populate the slug, via JavaScript, in the object's admin form:
# 
# models.SlugField(prepopulate_from=("pre_name", "name"))
# prepopulate_from 不接受 DateTimeFields.
# 
# admin 用一個``<input type="text">``表示 SlugField 字段數據(一個單行編輯框) 
 
# SmallIntegerField
# 相似 IntegerField, 不過只容許某個取值範圍內的整數.(依賴數據庫)
  
# TextField
# 一個容量很大的文本字段.
# 
# admin 用一個 <textarea> (文本區域)表示該字段數據.(一個多行編輯框).
 
# TimeField
# A time. Accepts the same auto-population options as DateField 和 DateTimeField.
# 
# admin 用一個 <input type="text"> 文本框表示該字段保存的數據(附加一些JavaScript shortcuts).
 
# URLField
# 用於保存 URL. 若 verify_exists 參數爲 True (默認), 給定的 URL 會預先檢查是否存在(即URL是否被有效裝入且沒有返回404響應).
# 
# admin 用一個 <input type="text"> 文本框表示該字段保存的數據(一個單行編輯框)
 
# USStateField
# 一個兩字母的美國州名縮寫.
# 
# admin 用一個 <input type="text"> 文本框表示該字段保存的數據(一個單行編輯框)
 
# XMLField
# 一個校驗值是否爲合法XML的 TextField,必須提供參數: schema_path, 它是一個用來校驗文本的 RelaxNG schema 的文件系統路徑.
View Code

4.2.1  模型類的定義(二)

4.2.1  模型類的定義(二)      

一  定義數據模型的擴展屬性

     經過內部類Meta給數據模型類增長擴展屬性:

     class Meta:

             verbose_name='名稱'      #表名由英文轉換成中文了

             verbose_name_plural='名稱複數形式'

             ordering='排序字段'   

    建立超級用戶後,登陸admin發現咱們定義的表並不在,咱們須要對所建立的表(類)進行註冊:

from django.contrib import admin

# Register your models here.

from app01.models import *

admin.site.register(Author)
admin.site.register(AuthorDetail)
admin.site.register(Publisher)
admin.site.register(Book)
View Code

這是由於:

二  定義模型方法

    定義模型方法和定義普通python類方法沒有太大的差異,定義模型方法能夠將當前對應的數據組裝成具體的業務邏輯。

    示例:定義__str__()讓對象有一個名字

def __str__(self):
    return self.name

#py2
def __unicode__(self):
    return self.name

當添加一個做者保存後:       

這裏只顯示生成了一個做者對象,可咱們但願在這裏出現的是做者的名字,因此:

刷新頁面:

4.3 ORM經常使用操做

4.3.1 增長

    create和save方法

實例:

Author.objects.create(name='abcd')
AuthorDetail.objects.create(sex=False, email='123@qq.com', address='bejing', birthday='1999-9-9',author_id=1)

********************************************
author= Author()
author.name = 'eve'
author.save()

注意:若是每次建立一個對象,想顯示對應的raw 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',
#         },
#     }
# }
View Code

那麼如何插入存在 外鍵多對多關係 的一本書的信息呢?

pub = Publisher.objects.get(id=1)
Book.objects.create(title='php', publisher=pub, publication_date='2017-7-7')

author1=Author.objects.get(id=1)
book=Book.objects.get(id=1)
book.authors.add(author1)

總結:

      1   objects:   model默認管理器。

      2   插入主外鍵關係的時候,能夠用對象的方式,也能夠用關聯id的方式。

      3   插入多對多關係的時候要分步操做。

      4   create是管理器objects的方法

           save是model對象的方法

4.3.2 修改

    update和save方法

實例:

author = Author.objects.get(id=2)
author.name = 'mnm'
author.save()
    
Publisher.objects.filter(id=1).update(name='American publisher')

注意:<1> update是QuerySet對象的方法,get返回的是一個model對象,它沒有update方法,而filter返回的是一個QuerySet對象。

     <2> save()方法,這個方法會更新一行裏的全部列。

     <3> update()方法對於任何結果集(QuerySet)均有效,這意味着你能夠同時更新多條記錄。

     <4> update()方法會返回一個整型數值,表示受影響的記錄條數。

Publisher.objects.all().update(country='USA')

4.3.3  查詢 

models.Tb1.objects.get(id=123)           # 獲取單條數據,不存在則報錯(不建議)
models.Tb1.objects.all()                 # 獲取所有
models.Tb1.objects.filter(name='seven')  # 獲取指定條件的數據

4.3.4  刪除

models.Tb1.objects.filter(name='seven').delete()  # 刪除指定條件的數據

咱們表面上刪除了一條信息,實際卻刪除了三條,由於咱們刪除的這本書在Book_authors表中有兩條相關信息,這種刪除方式就是django默認的級聯刪除

Model 進階操做

1、建立表

一、基本結構

from django.db import models
   
class userinfo(models.Model):
    name = models.CharField(max_length=30)
    email = models.EmailField()
    memo = models.TextField()
AutoField(Field)
        - int自增列,必須填入參數 primary_key=True

    BigAutoField(AutoField)
        - bigint自增列,必須填入參數 primary_key=True

        注:當model中若是沒有自增列,則自動會建立一個列名爲id的列
        from django.db import models

        class UserInfo(models.Model):
            # 自動建立一個列名爲id的且爲自增的整數列
            username = models.CharField(max_length=32)

        class Group(models.Model):
            # 自定義自增列
            nid = models.AutoField(primary_key=True)
            name = models.CharField(max_length=32)

    SmallIntegerField(IntegerField):
        - 小整數 -32768 ~ 32767

    PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正小整數 0 ~ 32767
    IntegerField(Field)
        - 整數列(有符號的) -2147483648 ~ 2147483647

    PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正整數 0 ~ 2147483647

    BigIntegerField(IntegerField):
        - 長整型(有符號的) -9223372036854775808 ~ 9223372036854775807

    自定義無符號整數字段

        class UnsignedIntegerField(models.IntegerField):
            def db_type(self, connection):
                return 'integer UNSIGNED'

        PS: 返回值爲字段在數據庫中的屬性,Django字段默認的值爲:
            'AutoField': 'integer AUTO_INCREMENT',
            'BigAutoField': 'bigint AUTO_INCREMENT',
            'BinaryField': 'longblob',
            'BooleanField': 'bool',
            'CharField': 'varchar(%(max_length)s)',
            'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
            'DateField': 'date',
            'DateTimeField': 'datetime',
            'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
            'DurationField': 'bigint',
            'FileField': 'varchar(%(max_length)s)',
            'FilePathField': 'varchar(%(max_length)s)',
            'FloatField': 'double precision',
            'IntegerField': 'integer',
            'BigIntegerField': 'bigint',
            'IPAddressField': 'char(15)',
            'GenericIPAddressField': 'char(39)',
            'NullBooleanField': 'bool',
            'OneToOneField': 'integer',
            'PositiveIntegerField': 'integer UNSIGNED',
            'PositiveSmallIntegerField': 'smallint UNSIGNED',
            'SlugField': 'varchar(%(max_length)s)',
            'SmallIntegerField': 'smallint',
            'TextField': 'longtext',
            'TimeField': 'time',
            'UUIDField': 'char(32)',

    BooleanField(Field)
        - 布爾值類型

    NullBooleanField(Field):
        - 能夠爲空的布爾值

    CharField(Field)
        - 字符類型
        - 必須提供max_length參數, max_length表示字符長度

    TextField(Field)
        - 文本類型

    EmailField(CharField):
        - 字符串類型,Django Admin以及ModelForm中提供驗證機制

    IPAddressField(Field)
        - 字符串類型,Django Admin以及ModelForm中提供驗證 IPV4 機制

    GenericIPAddressField(Field)
        - 字符串類型,Django Admin以及ModelForm中提供驗證 Ipv4和Ipv6
        - 參數:
            protocol,用於指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
            unpack_ipv4, 若是指定爲True,則輸入::ffff:192.0.2.1時候,可解析爲192.0.2.1,開啓刺功能,須要protocol="both"

    URLField(CharField)
        - 字符串類型,Django Admin以及ModelForm中提供驗證 URL

    SlugField(CharField)
        - 字符串類型,Django Admin以及ModelForm中提供驗證支持 字母、數字、下劃線、鏈接符(減號)

    CommaSeparatedIntegerField(CharField)
        - 字符串類型,格式必須爲逗號分割的數字

    UUIDField(Field)
        - 字符串類型,Django Admin以及ModelForm中提供對UUID格式的驗證

    FilePathField(Field)
        - 字符串,Django Admin以及ModelForm中提供讀取文件夾下文件的功能
        - 參數:
                path,                      文件夾路徑
                match=None,                正則匹配
                recursive=False,           遞歸下面的文件夾
                allow_files=True,          容許文件
                allow_folders=False,       容許文件夾

    FileField(Field)
        - 字符串,路徑保存在數據庫,文件上傳到指定目錄
        - 參數:
            upload_to = ""      上傳文件的保存路徑
            storage = None      存儲組件,默認django.core.files.storage.FileSystemStorage

    ImageField(FileField)
        - 字符串,路徑保存在數據庫,文件上傳到指定目錄
        - 參數:
            upload_to = ""      上傳文件的保存路徑
            storage = None      存儲組件,默認django.core.files.storage.FileSystemStorage
            width_field=None,   上傳圖片的高度保存的數據庫字段名(字符串)
            height_field=None   上傳圖片的寬度保存的數據庫字段名(字符串)

    DateTimeField(DateField)
        - 日期+時間格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]

    DateField(DateTimeCheckMixin, Field)
        - 日期格式      YYYY-MM-DD

    TimeField(DateTimeCheckMixin, Field)
        - 時間格式      HH:MM[:ss[.uuuuuu]]

    DurationField(Field)
        - 長整數,時間間隔,數據庫中按照bigint存儲,ORM中獲取的值爲datetime.timedelta類型

    FloatField(Field)
        - 浮點型

    DecimalField(Field)
        - 10進制小數
        - 參數:
            max_digits,小數總長度
            decimal_places,小數位長度

    BinaryField(Field)
        - 二進制類型

字段
字段
    null                數據庫中字段是否能夠爲空
    db_column           數據庫中字段的列名
    db_tablespace
    default             數據庫中字段的默認值
    primary_key         數據庫中字段是否爲主鍵
    db_index            數據庫中字段是否能夠創建索引
    unique              數據庫中字段是否能夠創建惟一索引
    unique_for_date     數據庫中字段【日期】部分是否能夠創建惟一索引
    unique_for_month    數據庫中字段【月】部分是否能夠創建惟一索引
    unique_for_year     數據庫中字段【年】部分是否能夠創建惟一索引

    verbose_name        Admin中顯示的字段名稱
    blank               Admin中是否容許用戶輸入爲空
    editable            Admin中是否能夠編輯
    help_text           Admin中該字段的提示信息
    choices             Admin中顯示選擇框的內容,用不變更的數據放在內存中從而避免跨表操做
                        如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)

    error_messages      自定義錯誤信息(字典類型),從而定製想要顯示的錯誤信息;
                        字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
                        如:{'null': "不能爲空.", 'invalid': '格式錯誤'}

    validators          自定義錯誤驗證(列表類型),從而定製想要的驗證規則
                        from django.core.validators import RegexValidator
                        from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\
                        MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
                        如:
                            test = models.CharField(
                                max_length=32,
                                error_messages={
                                    'c1': '優先錯信息1',
                                    'c2': '優先錯信息2',
                                    'c3': '優先錯信息3',
                                },
                                validators=[
                                    RegexValidator(regex='root_\d+', message='錯誤了', code='c1'),
                                    RegexValidator(regex='root_112233\d+', message='又錯誤了', code='c2'),
                                    EmailValidator(message='又錯誤了', code='c3'), ]
                            )
參數
    class UserInfo(models.Model):
        nid = models.AutoField(primary_key=True)
        username = models.CharField(max_length=32)
        class Meta:
            # 數據庫中生成的表名稱 默認 app名稱 + 下劃線 + 類名
            db_table = "table_name"

            # 聯合索引
            index_together = [
                ("pub_date", "deadline"),
            ]

            # 聯合惟一索引
            unique_together = (("driver", "restaurant"),)

            # admin中顯示的表名稱
            verbose_name

            # verbose_name加s
            verbose_name_plural
        
    更多:https://docs.djangoproject.com/en/1.10/ref/models/options/
元信息
    1.觸發Model中的驗證和錯誤提示有兩種方式:
        a. Django Admin中的錯誤信息會優先根據Admiin內部的ModelForm錯誤信息提示,若是都成功,纔來檢查Model的字段並顯示指定錯誤信息
        b. 調用Model對象的 clean_fields 方法,如:
            # models.py
            class UserInfo(models.Model):
                nid = models.AutoField(primary_key=True)
                username = models.CharField(max_length=32)

                email = models.EmailField(error_messages={'invalid': '格式錯了.'})

            # views.py
            def index(request):
                obj = models.UserInfo(username='11234', email='uu')
                try:
                    print(obj.clean_fields())
                except Exception as e:
                    print(e)
                return HttpResponse('ok')

           # Model的clean方法是一個鉤子,可用於定製操做,如:上述的異常處理。

    2.Admin中修改錯誤提示
        # admin.py
        from django.contrib import admin
        from model_club import models
        from django import forms


        class UserInfoForm(forms.ModelForm):
            username = forms.CharField(error_messages={'required': '用戶名不能爲空.'})
            email = forms.EmailField(error_messages={'invalid': '郵箱格式錯誤.'})
            age = forms.IntegerField(initial=1, error_messages={'required': '請輸入數值.', 'invalid': '年齡必須爲數值.'})

            class Meta:
                model = models.UserInfo
                # fields = ('username',)
                fields = "__all__"


        class UserInfoAdmin(admin.ModelAdmin):
            form = UserInfoForm


        admin.site.register(models.UserInfo, UserInfoAdmin)
擴展知識

二、連表結構

  • 一對多:models.ForeignKey(其餘表)

  • 多對多:models.ManyToManyField(其餘表)

  • 一對一:models.OneToOneField(其餘表)

    ForeignKey(ForeignObject) # ForeignObject(RelatedField)
        to,                         # 要進行關聯的表名
        to_field=None,              # 要關聯的表中的字段名稱
        on_delete=None,             # 當刪除關聯表中的數據時,當前表與其關聯的行的行爲
                                        - models.CASCADE,刪除關聯數據,與之關聯也刪除
                                        - models.DO_NOTHING,刪除關聯數據,引起錯誤IntegrityError
                                        - models.PROTECT,刪除關聯數據,引起錯誤ProtectedError
                                        - models.SET_NULL,刪除關聯數據,與之關聯的值設置爲null(前提FK字段須要設置爲可空)
                                        - models.SET_DEFAULT,刪除關聯數據,與之關聯的值設置爲默認值(前提FK字段須要設置默認值)
                                        - models.SET,刪除關聯數據,
                                                      a. 與之關聯的值設置爲指定值,設置:models.SET(值)
                                                      b. 與之關聯的值設置爲可執行對象的返回值,設置:models.SET(可執行對象)

                                                        def func():
                                                            return 10

                                                        class MyModel(models.Model):
                                                            user = models.ForeignKey(
                                                                to="User",
                                                                to_field="id"
                                                                on_delete=models.SET(func),)
        related_name=None,          # 反向操做時,使用的字段名,用於代替 【表名_set】 如: obj.表名_set.all()
        related_query_name=None,    # 反向操做時,使用的鏈接前綴,用於替換【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
        limit_choices_to=None,      # 在Admin或ModelForm中顯示關聯數據時,提供的條件:
                                    # 如:
                                            - limit_choices_to={'nid__gt': 5}
                                            - limit_choices_to=lambda : {'nid__gt': 5}

                                            from django.db.models import Q
                                            - limit_choices_to=Q(nid__gt=10)
                                            - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
                                            - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
        db_constraint=True          # 是否在數據庫中建立外鍵約束
        parent_link=False           # 在Admin中是否顯示關聯數據


    OneToOneField(ForeignKey)
        to,                         # 要進行關聯的表名
        to_field=None               # 要關聯的表中的字段名稱
        on_delete=None,             # 當刪除關聯表中的數據時,當前表與其關聯的行的行爲

                                    ###### 對於一對一 ######
                                    # 1. 一對一其實就是 一對多 + 惟一索引
                                    # 2.當兩個類之間有繼承關係時,默認會建立一個一對一字段
                                    # 以下會在A表中額外增長一個c_ptr_id列且惟一:
                                            class C(models.Model):
                                                nid = models.AutoField(primary_key=True)
                                                part = models.CharField(max_length=12)

                                            class A(C):
                                                id = models.AutoField(primary_key=True)
                                                code = models.CharField(max_length=1)

    ManyToManyField(RelatedField)
        to,                         # 要進行關聯的表名
        related_name=None,          # 反向操做時,使用的字段名,用於代替 【表名_set】 如: obj.表名_set.all()
        related_query_name=None,    # 反向操做時,使用的鏈接前綴,用於替換【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
        limit_choices_to=None,      # 在Admin或ModelForm中顯示關聯數據時,提供的條件:
                                    # 如:
                                            - limit_choices_to={'nid__gt': 5}
                                            - limit_choices_to=lambda : {'nid__gt': 5}

                                            from django.db.models import Q
                                            - limit_choices_to=Q(nid__gt=10)
                                            - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
                                            - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
        symmetrical=None,           # 僅用於多對多自關聯時,symmetrical用於指定內部是否建立反向操做的字段
                                    # 作以下操做時,不一樣的symmetrical會有不一樣的可選字段
                                        models.BB.objects.filter(...)

                                        # 可選字段有:code, id, m1
                                            class BB(models.Model):

                                            code = models.CharField(max_length=12)
                                            m1 = models.ManyToManyField('self',symmetrical=True)

                                        # 可選字段有: bb, code, id, m1
                                            class BB(models.Model):

                                            code = models.CharField(max_length=12)
                                            m1 = models.ManyToManyField('self',symmetrical=False)

        through=None,               # 自定義第三張表時,使用字段用於指定關係表
        through_fields=None,        # 自定義第三張表時,使用字段用於指定關係表中那些字段作多對多關係表
                                        from django.db import models

                                        class Person(models.Model):
                                            name = models.CharField(max_length=50)

                                        class Group(models.Model):
                                            name = models.CharField(max_length=128)
                                            members = models.ManyToManyField(
                                                Person,
                                                through='Membership',
                                                through_fields=('group', 'person'),
                                            )

                                        class Membership(models.Model):
                                            group = models.ForeignKey(Group, on_delete=models.CASCADE)
                                            person = models.ForeignKey(Person, on_delete=models.CASCADE)
                                            inviter = models.ForeignKey(
                                                Person,
                                                on_delete=models.CASCADE,
                                                related_name="membership_invites",
                                            )
                                            invite_reason = models.CharField(max_length=64)
        db_constraint=True,         # 是否在數據庫中建立外鍵約束
        db_table=None,              # 默認建立第三張表時,數據庫中表的名稱
字段以及參數

建立表時,順序問題:

class UserType(models.Model):
    nid = models.AutoField(primary_key=True)
    caption = models.CharField(max_length=16)

class UserInfo(models.Model):
    name = models.CharField(max_length=32)
    email = models.EmailField(max_length=32)
    pwd = models.CharField(max_length=64)
    user_type = models.ForeignKey(UserType)        # UserType已存在時

#*********************************************

class UserInfo(models.Model):
    name = models.CharField(max_length=32)
    email = models.EmailField(max_length=32)
    pwd = models.CharField(max_length=64)
    user_type = models.ForeignKey("UserType")     #UserType 不存在時 加上雙引號

class UserType(models.Model):
    nid = models.AutoField(primary_key=True)
    caption = models.CharField(max_length=16)
View Code

2、操做表

一、基本操做

    #
    #
    # models.Tb1.objects.create(c1='xx', c2='oo')  增長一條數據,能夠接受字典類型數據 **kwargs
    #
    # tb1_dict = {'a1':'123',...}
    # models.Tb1.objects.create(**tb1_dict)

    # obj = models.Tb1(c1='xx', c2='oo')
    # obj.save()

    #
    #
    # models.Tb1.objects.get(id=123)         # 獲取單條數據,不存在則報錯(不建議)
    # models.Tb1.objects.all()               # 獲取所有
    # models.Tb1.objects.filter(name='seven') # 獲取指定條件的數據

    #
    #
    # models.Tb1.objects.filter(name='seven').delete() # 刪除指定條件的數據

    #
    # models.Tb1.objects.filter(name='seven').update(gender='0')  # 將指定條件的數據更新,均支持 **kwargs
    # obj = models.Tb1.objects.get(id=1)
    # obj.c1 = '111'
    # obj.save()                                                 # 修改單條數據
View Code

二、進階操做(了不得的雙下劃線)

利用雙下劃線將字段和對應的操做鏈接起來

        # 獲取個數
        #
        # models.Tb1.objects.filter(name='seven').count()

        # 大於,小於
        #
        # models.Tb1.objects.filter(id__gt=1)              # 獲取id大於1的值
        # models.Tb1.objects.filter(id__gte=1)              # 獲取id大於等於1的值
        # models.Tb1.objects.filter(id__lt=10)             # 獲取id小於10的值
        # models.Tb1.objects.filter(id__lte=10)             # 獲取id小於10的值
        # models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 獲取id大於1 且 小於10的值

        # in
        #
        # models.Tb1.objects.filter(id__in=[11, 22, 33])   # 獲取id等於十一、2二、33的數據
        # models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in

        # isnull
        # Entry.objects.filter(pub_date__isnull=True)

        # contains
        #
        # models.Tb1.objects.filter(name__contains="ven")
        # models.Tb1.objects.filter(name__icontains="ven") # icontains大小寫不敏感
        # models.Tb1.objects.exclude(name__icontains="ven")

        # range
        #
        # models.Tb1.objects.filter(id__range=[1, 2])   # 範圍bettwen and

        # 其餘相似
        #
        # startswith,istartswith, endswith, iendswith,

        # order by
        #
        # models.Tb1.objects.filter(name='seven').order_by('id')    # asc
        # models.Tb1.objects.filter(name='seven').order_by('-id')   # desc

        # group by
        #
        # from django.db.models import Count, Min, Max, Sum
        # models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num'))
        # SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"

        # limit 、offset
        #
        # models.Tb1.objects.all()[10:20]

        # regex正則匹配,iregex 不區分大小寫
        #
        # Entry.objects.get(title__regex=r'^(An?|The) +')
        # Entry.objects.get(title__iregex=r'^(an?|the) +')

        # date
        #
        # Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
        # Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))

        # year
        #
        # Entry.objects.filter(pub_date__year=2005)
        # Entry.objects.filter(pub_date__year__gte=2005)

        # month
        #
        # Entry.objects.filter(pub_date__month=12)
        # Entry.objects.filter(pub_date__month__gte=6)

        # day
        #
        # Entry.objects.filter(pub_date__day=3)
        # Entry.objects.filter(pub_date__day__gte=3)

        # week_day
        #
        # Entry.objects.filter(pub_date__week_day=2)
        # Entry.objects.filter(pub_date__week_day__gte=2)

        # hour
        #
        # Event.objects.filter(timestamp__hour=23)
        # Event.objects.filter(time__hour=5)
        # Event.objects.filter(timestamp__hour__gte=12)

        # minute
        #
        # Event.objects.filter(timestamp__minute=29)
        # Event.objects.filter(time__minute=46)
        # Event.objects.filter(timestamp__minute__gte=29)

        # second
        #
        # Event.objects.filter(timestamp__second=31)
        # Event.objects.filter(time__second=2)
        # Event.objects.filter(timestamp__second__gte=31)
View Code

一對多,實例使用表結構:

class UserType(models.Model):
    nid = models.AutoField(primary_key=True)
    caption = models.CharField(max_length=16)

class UserInfo(models.Model):
    name = models.CharField(max_length=32)
    email = models.EmailField(max_length=32)
    pwd = models.CharField(max_length=64)
    user_type = models.ForeignKey(UserType)
View Code

查詢:

ret = models.UserType.objects.all()
print(ret,type(ret))
# <QuerySet [<UserType: UserType object>, <UserType: UserType object>, ]> <class 'django.db.models.query.QuerySet'>
# [對象,...,...]   => 獲得對象列表
for item in ret:
    print(item,item.nid,item.caption)

ret = models.UserType.objects.all().values('nid')# <QuerySet [{'nid': 1}, {'nid': 2}, {'nid': 3}]>
# [字典,...,...] 

ret = models.UserType.objects.all().values_list('nid')# <QuerySet [(1,), (2,), (3,)]>
# [元組,...,...] 

連表查詢:

ret = models.UserInfo.objects.all()
for item in ret:
    print(item.name,item.user_type.caption)     #經過Userinfo表的外鍵user_type去查詢了UserType表
# alex 管理員
# eric 普通用戶

ret = models.UserInfo.objects.all().values('id','user_type__caption')
# <QuerySet [{'user_type__caption': '管理員', 'id': 1}, {'user_type__caption': '普通用戶', 'id': 2}]>

# 正向查找:
ret = models.UserInfo.objects.filter(id=1)
ret = models.UserInfo.objects.filter(user_type__caption='管理員')
# 返回 [對象,...,...] 列表
# 能夠經過 .來訪問該對象的屬性

ret = models.UserInfo.objects.filter(user_type__caption='管理員').values('name','user_type__caption')
# <QuerySet [{'name': 'alex', 'user_type__caption': '管理員'}]>
# 返回 [字典,...,...] 列表

反向查找:

ret = models.UserType.objects.filter(caption='管理員').first()
print(ret)
# UserType object 

obj = ret.userinfo_set.all()
obj = ret.userinfo_set.filter(id=1)
# <QuerySet [<UserInfo: UserInfo object>]>

for item in obj:
    print(item.name,item.email)

# 方法二:
ret = models.UserType.objects.all().values('nid','caption','userinfo__name')
# 以UserType表爲主, 鏈接UserInfo表 , 不存在的爲 None
# <QuerySet [{'caption': '管理員', 'userinfo__name': 'alex', 'nid': 1}, {'caption': '管理員', 'userinfo__name': 'eric', 'nid': 1}, {'caption': '普通用戶', 'userinfo__name': None, 'nid': 2}, {'caption': '超級管理員', 'userinfo__name': None, 'nid': 3}]>

ret = models.UserType.objects.filter(nid=1,userinfo__name='alex')
# 返回 UserType對象列表
# <QuerySet [<UserType: UserType object>]>

多對多,實例使用表結構:

class Host(models.Model):
    hid = models.AutoField(primary_key=True)
    hostname = models.CharField(max_length=32)
    ip = models.CharField(max_length=32)
    #h2g = models.ManyToManyField(Group)

class Group(models.Model):
    gid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=16)
    h2g = models.ManyToManyField(Host)


# ****************************************
# 填充數據:
models.Host.objects.create(hostname='alex1',ip='1.1.1.1')
models.Host.objects.create(hostname='alex2',ip='1.1.1.2')
models.Host.objects.create(hostname='alex3',ip='1.1.1.3')
models.Host.objects.create(hostname='alex4',ip='1.1.1.4')
models.Host.objects.create(hostname='alex5',ip='1.1.1.5')
models.Host.objects.create(hostname='alex6',ip='1.1.1.6')
models.Host.objects.create(hostname='alex7',ip='1.1.1.7')


models.Group.objects.create(name='運營部')
models.Group.objects.create(name='運維部')
models.Group.objects.create(name='人事部')
models.Group.objects.create(name='開發部')
models.Group.objects.create(name='後勤部')
View Code

狀況一: 關係表(自動建立)

添加:

# 一個一個添加
h1 = models.Host.objects.get(hid=1)
g1 = models.Group.objects.get(gid=1)
g1.h2g.add(h1)

# 批量添加(多臺機器分給一個組)
g1 = models.Group.objects.get(gid=1)
h = models.Host.objects.filter(hid__gt=3)
g1.h2g.add(*h)

# 一臺機器分給多個組
h1 = models.Host.objects.get(hid=5)
g = models.Group.objects.filter(gid__gt=3)
h1.group_set.add(*g)

能夠發如今 Host表中,隱含了一個 group_set

class Host(models.Model):
    hid = models.AutoField(primary_key=True)
    hostname = models.CharField(max_length=32)
    ip = models.CharField(max_length=32)
    group_set = ....

class Group(models.Model):
    gid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=16)
    h2g = models.ManyToManyField(Host)    # 只生成3列
View Code

刪除:

h = models.Host.objects.get(hid=1)
h.group_set.remove(*models.objects.filter(gid__gt=1))  # 關係表,刪除 hid等於1 , gid 大於1的記錄
h.group_set.all().delete()   # 關係表,group數據表的數據也刪除了!!!

修改:

h = models.Host.objects.get(hid=1)
h.group_set.set(models.Group.objects.filter(gid=3))
# 關係表中, hid = 1 的全部行, 只剩下 , gid = 3   ,其他刪除!
# 符合保留,不符合刪除!. (僅限制在 符合hid=1 的關係表的數據行中!!)

h.group_set.get_or_create(name='技術部')
h.group_set.update_or_create(name='技術部')
# 在group添加新的記錄,而後關係表也添加記錄!

補充:

# 傳對象
group= models.Group.objects.get(gid=1)
h1.group_set.add(group)

# 傳值
h1.group_set.add(1)
h1.group_set.add(*[2,3])
# 能夠直接添加id 

狀況二: 關係表(本身建立) 須要本身添加惟一約束!

class HostToGroup(models.Model):
    hgid = models.AutoField(primary_key=True)
    host_id = models.ForeignKey("Host")
    group_id = models.ForeignKey("Group")
    status = models.IntegerField()
    class Meta:
        unique_together = [
            ("host_id", "group_id"),
        ]

class Host(models.Model):
    hid = models.AutoField(primary_key=True)
    hostname = models.CharField(max_length=32)
    ip = models.CharField(max_length=32)

class Group(models.Model):
    gid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=16)
View Code

7 Django Template

  模版的組成:HTML代碼+邏輯控制代碼

模版的渲染:

>>> python manange.py shell  (進入該django項目的環境)
>>> from django.template import Context, Template
>>> t = Template('My name is {{ name }}.')
>>> c = Context({'name': 'Stephane'})
>>> t.render(c)
'My name is Stephane.'

邏輯控制代碼:

一、變量

{{ item }}

二、句點號

# 後端數據 :
s = 'hello'
s1 = [1,2]
s2 = { 'user':'eriic' }
s3 = time.localtime()
s4 = Foo( 'eroiic' , 20 )

# 頁面取值 :
{{ obj.1 }}       # 索引取值 
{{ obj.user }}    # 根據字段key取值
{{ obj.year }}    # 根據屬性取值
{{ obj.name }}    # 取類中字段

三、{% if %} 的使用

  不容許同一標籤裏同時出現and和or,不然邏輯容易產生歧義

{% if num >= 100 and 8 %}

{% elif num < 100%}
    <p>num小於100</p>

{% else %}
    <p>num等於100</p>

{% endif %}

四、{% for %}的使用

{% for i in obj %}
# obj 爲列表 , i 爲值 {{ forloop.counter }} # 模擬索引 , 從1開始算 {{ forloop.counter0 }} # 模擬索引 , 從0開始算 {{ forloop.revcounter }} # 反序索引 , 從最後開始算 # obj 爲字典 , i 爲key , 或者改成: obj.keys obj.values obj.items 進行循環 {% endfor %}

五、Filter(過濾器)

語法格式:      {{obj|filter:param}}
   # 1  add          :   給變量加上相應的值
   #
   # 2  addslashes   :    給變量中的引號前加上斜線
   #
   # 3  capfirst     :    首字母大寫
   #
   # 4  cut          :   從字符串中移除指定的字符
   #
   # 5  date         :   格式化日期字符串
   #
   # 6  default      :   若是值是False,就替換成設置的默認值,不然就是用原本的值
   #
   # 7  default_if_none:  若是值是None,就替換成設置的默認值,不然就使用原本的值


#實例:

#value1="aBcDe"
{{ value1|upper }}

#value2=5
{{ value2|add:3 }}

#value3='he  llo wo r ld'
{{ value3|cut:' ' }}

#import datetime
#value4=datetime.datetime.now()
{{ value4|date:'Y-m-d' }}

#value5=[]
{{ value5|default:'空的' }}      # 設置默認值

#value6='<a href="#">跳轉</a>'
{{ value6 }}                    # 字符串形式在頁面顯示

{% autoescape off %}            # 渲染成瀏覽器能解析的標籤
  {{ value6 }}
{% endautoescape %}

{{ value6|safe }}               # 效果同上

{{ value6|striptags }}

#value7='1234'
{{ value7|filesizeformat }}     # obj 數據的大小 ~kb
{{ value7|first }}              # 取第一個值
{{ value7|length }}             #  獲得長度
{{ value7|slice:":-1" }}        #  切片

#value8='http://www.baidu.com/?a=1&b=3'
{{ value8|urlencode }}          # 進行url編碼

value9='hello I am eriic'
{{ value9|truncatechars:'6' }}   # 按字符截斷   總顯示3個點, 佔用3個位置!
{{ value9|truncatewords:'6' }}   # 按單詞截斷
Demo

六、{%csrf_token%}:csrf_token標籤 , 放到form 表單裏

七、{% with %}:用更簡單的變量名替代複雜的變量名

{% with total=fhjsaldfhjsdfhlasdfhljsdal %} 
{{ total }}
{% endwith %}

八、{% verbatim %}: 禁止變量被渲染

{% verbatim %}
    {{ hello }}              # 頁面直接顯示 {{ hello }}
{% endverbatim %}

九、{% load %}: 加載標籤庫 

自定義filter和simple_tag:

0、如今setting中installed_apps 添加當前的app項目!

一、app項目下建立templatetags 

二、建立任意文件 如 my_tags.py

三、引入類,自定義函數

from django import template
from django.utils.safestring import mark_safe

register = template.Library()   #register的名字是固定的,不可改變

@register.filter
def filter_multi(v1,v2):
    return  v1 * v2

@register.simple_tag
def simple_tag_multi(v1,v2):
    return  v1 * v2

@register.simple_tag
def my_input(id,arg):
    result = "<input type='text' id='%s' class='%s' />" %(id,arg,)
    return mark_safe(result)

四、HTML中使用

{% load my_tags %}    # 引入外部文件

使用:
{% my_add 100 101 %}      # simple_tag 能夠傳入多個參數 , 不能用於if語句
{{ obj | my_add:num2 }}   # filter 最多兩個參數 , if 語句能夠跟filter

模版繼承:

include 模板標籤  {% include %}

  該標籤容許在(模板中)包含其它的模板的內容。

  標籤的參數是所要包含的模板名稱,能夠是一個變量,也能夠是用單/雙引號硬編碼的字符串。

  每當在多個模板中出現相同的代碼時,就應該考慮是否要使用 {% include %} 來減小重複。

extend(繼承)模板標籤

  減小共用頁面區域所引發的重複和冗餘代碼

  方法一:解決該問題的傳統作法是使用 服務器端的 includes ,你能夠在 HTML 頁面中使用該指令將一個網頁嵌入到另外一箇中。 

  方法二:模板繼承就是先構造一個基礎框架模板,然後在其子模板中對它所包含站點公用部分和定義塊進行重載。

#1 -- base.html     存放的是頁面共有的代碼 !
....
{% block content %}      # 非共有部分用 block代替 ,  block名字自定義 
    ...
{% endblock %}


#2 -- order.html    只保留非共有部分的代碼 !
{% extend 'base.html' %}   # 繼承外部文件
{% block cotent %}         # 非共有部分的代碼 ! , 會對base.html中的block進行替換 !! 
    .... 
{% endblock %}             # 沒有對應上的block 會在base中原樣顯示!

# 若是須要同時顯示父級的代碼 和本身代碼 能夠嵌套使用
{{ block.super }}

 

更多見文檔:https://docs.djangoproject.com/en/1.10/ref/templates/language/

相關文章
相關標籤/搜索