第18天課程內容:html
mtv補充python
遇到的問題:mysql
一、 修改pycharm鏈接數據庫改成mysql時遇到的問題git
解決:web
須要在項目的__init__.py文件中加sql
import pymysql
pymysql.install_as_MySQLdb()二、post提交表單數據時,默認會提示403 forbidden,須要在form表單處添加{% csrf_token %},render方法會爲它渲染一個隨機字符串一併提交給服務端作驗證,就能夠解決了;數據庫
也能夠臨時在settings裏註釋掉關於csrf的配置。(不推薦)django
自定義標籤和過濾器
django提供的標籤與過濾器畢竟有限,更多的是須要本身去自定義標籤和過濾器,如下是過程:app
一、在settings中的INSTALLED_APPS配置當前app,否則django沒法找到自定義的simple_tag.ide
二、在app中建立templatetags模塊(模塊名只能是templatetags)
三、建立任意 .py 文件,如:my_tags.py
from django import template
from django.utils.safestring import mark_safe
register = template.Library()
# 以上爲固定格式
@register.filter #自定義過濾器
def multi(x,y):
return x*y
@register.simple_tag#自定義標籤
def mult_tag(x,y,z):
return x**y**z
四、在使用自定義simple_tag和filter的html文件中導入以前建立的 my_tags.py
{
%
load my_tags
%
}
五、使用simple_tag和filter(如何調用)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{#自定義過濾器:在經過render方法渲染頁面時只支持接受2個參數#}
{% load Mytag %}
<h2>{{ n1|multi:2 }}</h2>
<hr>
{#自定義標籤:能夠接受多個參數,經過render方法渲染頁面時也沒問題#}
<h1>{% mult_tag 2 6 2%}</h1>
</body>
</html>注意:filter能夠用在if等語句後,simple_tag不能夠
{
%
if
num|filter_multi:
30
>
100
%
}
{{ num|filter_multi:
30
}}
{
%
endif
%
}
總結:
tempalte(模板層): 功能: 爲了更有邏輯的將數據庫中的數據渲染到模板中 模板語法 變量 {{ }} 深度查詢: 句點符 . 過濾器: {{var|filter_name:參數}} 標籤 {% url %} {% for i in obj %} {% endfor %} {% if %} {%endif%} {% with %} {% csrf_token%} 自定義過濾器與標籤: 定義流程: 1、在settings中的INSTALLED_APPS配置當前app,否則django沒法找到自定義的simple_tag. 2、在app中建立templatetags模塊(模塊名只能是templatetags) 3、建立任意 .py 文件,如:my_tags.py: from django import template from django.utils.safestring import mark_safe register = template.Library() # register的名字是固定的,不可改變 @register.filter # 定義過濾器 def multi(x,y): return x*y @register.simple_tag # 定義標籤 def multi_tag(x,y,z): return x*y*z 4、在使用自定義simple_tag和filter的html文件中導入以前建立的 my_tags.py {% load my_tags %} 5、使用simple_tag和filter(如何調用) 總結區別: 1、自定義filter只能接受兩個參數 2、自定義simple_tag不能與if使用
模板繼承 (extend)
Django模版引擎中最強大也是最複雜的部分就是模版繼承了。模版繼承可讓您建立一個基本的「骨架」模版,它包含您站點中的所有元素,而且能夠定義可以被子模版覆蓋的 blocks 。
經過從下面這個例子開始,能夠容易的理解模版繼承:
View Code這個模版,咱們把它叫做
base.html
, 它定義了一個能夠用於兩列排版頁面的簡單HTML骨架。「子模版」的工做是用它們的內容填充空的blocks。在這個例子中,
block
標籤訂義了三個能夠被子模版內容填充的block。block
告訴模版引擎: 子模版可能會覆蓋掉模版中的這些位置。子模版可能看起來是這樣的:
View Code
extends
標籤是這裏的關鍵。它告訴模版引擎,這個模版「繼承」了另外一個模版。當模版系統處理這個模版時,首先,它將定位父模版——在此例中,就是「base.html」。那時,模版引擎將注意到
base.html
中的三個block
標籤,並用子模版中的內容來替換這些block。根據blog_entries
的值,輸出可能看起來是這樣的:View Code請注意,子模版並無定義
sidebar
block,因此係統使用了父模版中的值。父模版的{% block %}
標籤中的內容老是被用做備選內容(fallback)。
這種方式使代碼獲得最大程度的複用,而且使得添加內容到共享的內容區域更加簡單,例如,部分範圍內的導航。
這裏是使用繼承的一些提示:
若是你在模版中使用
{% extends %}
標籤,它必須是模版中的第一個標籤。其餘的任何狀況下,模版繼承都將沒法工做。在base模版中設置越多的
{% block %}
標籤越好。請記住,子模版沒必要定義所有父模版中的blocks,因此,你能夠在大多數blocks中填充合理的默認內容,而後,只定義你須要的那一個。多一點鉤子總比少一點好。若是你發現你本身在大量的模版中複製內容,那可能意味着你應該把內容移動到父模版中的一個
{% block %}
中。If you need to get the content of the block from the parent template, the
{{ block.super }}
variable will do the trick. This is useful if you want to add to the contents of a parent block instead of completely overriding it. Data inserted using{{ block.super }}
will not be automatically escaped (see the next section), since it was already escaped, if necessary, in the parent template.爲了更好的可讀性,你也能夠給你的
{% endblock %}
標籤一個 名字 。例如:{% block content %} ... {% endblock content %}
在大型模版中,這個方法幫你清楚的看到哪個
{% block %}
標籤被關閉了。最後,請注意您並不能在一個模版中定義多個相同名字的
block
標籤。這個限制的存在是由於block標籤的做用是「雙向」的。這個意思是,block標籤不只提供了一個坑去填,它還在 _父模版_中定義了填坑的內容。若是在一個模版中有兩個名字同樣的block
標籤,模版的父模版將不知道使用哪一個block的內容。
ORM
映射關係:
表名 <-------> 類名 字段 <-------> 屬性 表記錄 <------->類實例對象建立表(創建模型)
實例:咱們來假定下面這些概念,字段和關係
做者模型:一個做者有姓名和年齡。
做者詳細模型:把做者的詳情放到詳情表,包含生日,手機號,家庭住址等信息。做者詳情模型和做者模型之間是一對一的關係(one-to-one)
出版商模型:出版商有名稱,所在城市以及email。
書籍模型: 書籍有書名和出版日期,一本書可能會有多個做者,一個做者也能夠寫多本書,因此做者和書籍的關係就是多對多的關聯關係(many-to-many);一本書只應該由一個出版商出版,因此出版商和書籍是一對多關聯關係(one-to-many)。
模型創建以下:
class Author(models.Model): nid = models.AutoField(primary_key=True) name=models.CharField( max_length=32) age=models.IntegerField() # 與AuthorDetail創建一對一的關係 authorDetail=models.OneToOneField(to="AuthorDetail") class AuthorDetail(models.Model): nid = models.AutoField(primary_key=True) birthday=models.DateField() telephone=models.BigIntegerField() addr=models.CharField( max_length=64) class Publish(models.Model): nid = models.AutoField(primary_key=True) name=models.CharField( max_length=32) city=models.CharField( max_length=32) email=models.EmailField() class Book(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField( max_length=32) publishDate=models.DateField() price=models.DecimalField(max_digits=5,decimal_places=2) keepNum=models.IntegerField()<br> commentNum=models.IntegerField() # 與Publish創建一對多的關係,外鍵字段創建在多的一方 publish=models.ForeignKey(to="Publish",to_field="nid") # 與Author表創建多對多的關係,ManyToManyField能夠建在兩個模型中的任意一個,自動建立第三張表 authors=models.ManyToManyField(to='Author')經過logging能夠查看翻譯成的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', }, } }
注意事項:
一、 表的名稱
myapp_modelName
,是根據 模型中的元數據自動生成的,也能夠覆寫爲別的名稱二、
id
字段是自動添加的三、對於外鍵字段,Django 會在字段名上添加"_id" 來建立數據庫中的列名
四、這個例子中的
CREATE TABLE
SQL 語句使用PostgreSQL 語法格式,要注意的是Django 會根據settings 中指定的數據庫類型來使用相應的SQL 語句。五、定義好模型以後,你須要告訴Django _使用_這些模型。你要作的就是修改配置文件中的INSTALL_APPSZ中設置,在其中添加
models.py
所在應用的名稱。六、外鍵字段 ForeignKey 有一個 null=True 的設置(它容許外鍵接受空值 NULL),你能夠賦給它空值 None 。
字段選項
每一個字段有一些特有的參數,例如,CharField須要max_length參數來指定
VARCHAR
數據庫字段的大小。還有一些適用於全部字段的通用參數。 這些參數在文檔中有詳細定義,這裏咱們只簡單介紹一些最經常使用的:View Code(1)null 若是爲True,Django 將用NULL 來在數據庫中存儲空值。 默認值是 False. (1)blank 若是爲True,該字段容許不填。默認爲False。 要注意,這與 null 不一樣。null純粹是數據庫範疇的,而 blank 是數據驗證範疇的。 若是一個字段的blank=True,表單的驗證將容許該字段是空值。若是字段的blank=False,該字段就是必填的。 (2)default 字段的默認值。能夠是一個值或者可調用對象。若是可調用 ,每有新對象被建立它都會被調用。 (3)primary_key 若是爲True,那麼這個字段就是模型的主鍵。若是你沒有指定任何一個字段的primary_key=True, Django 就會自動添加一個IntegerField字段作爲主鍵,因此除非你想覆蓋默認的主鍵行爲, 不然不必設置任何一個字段的primary_key=True。 (4)unique 若是該值設置爲 True, 這個數據字段的值在整張表中必須是惟一的 (5)choices 由二元組組成的一個可迭代對象(例如,列表或元組),用來給字段提供選擇項。 若是設置了choices ,默認的表單將是一個選擇框而不是標準的文本框,並且這個選擇框的選項就是choices 中的選項。 這是一個關於 choices 列表的例子: YEAR_IN_SCHOOL_CHOICES = ( ('FR', 'Freshman'), ('SO', 'Sophomore'), ('JR', 'Junior'), ('SR', 'Senior'), ('GR', 'Graduate'), ) 每一個元組中的第一個元素,是存儲在數據庫中的值;第二個元素是在管理界面或 ModelChoiceField 中用做顯示的內容。 在一個給定的 model 類的實例中,想獲得某個 choices 字段的顯示值,就調用 get_FOO_display 方法(這裏的 FOO 就是 choices 字段的名稱 )。例如: from django.db import models class Person(models.Model): SHIRT_SIZES = ( ('S', 'Small'), ('M', 'Medium'), ('L', 'Large'), ) name = models.CharField(max_length=60) shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES) >>> p = Person(name="Fred Flintstone", shirt_size="L") >>> p.save() >>> p.shirt_size 'L' >>> p.get_shirt_size_display() 'Large'一旦你創建好數據模型以後,django會自動生成一套數據庫抽象的API,可讓你執行關於表記錄的增刪改查的操做。
查詢表記錄
查詢相關API
<1> all(): 查詢全部結果 <2> filter(**kwargs): 它包含了與所給篩選條件相匹配的對象 <3> get(**kwargs): 返回與所給篩選條件相匹配的對象,返回結果有且只有一個, 若是符合篩選條件的對象超過一個或者沒有都會拋出錯誤。 <5> exclude(**kwargs): 它包含了與所給篩選條件不匹配的對象 <4> values(*field): 返回一個ValueQuerySet——一個特殊的QuerySet,運行後獲得的並非一系列 model的實例化對象,而是一個可迭代的字典序列 <9> values_list(*field): 它與values()很是類似,它返回的是一個元組序列,values返回的是一個字典序列 <6> order_by(*field): 對查詢結果排序 <7> reverse(): 對查詢結果反向排序 <8> distinct(): 從返回結果中剔除重複紀錄 <10> count(): 返回數據庫中匹配查詢(QuerySet)的對象數量。 <11> first(): 返回第一條記錄 <12> last(): 返回最後一條記錄 <13> exists(): 若是QuerySet包含數據,就返回True,不然返回False雙下劃線之單表查詢
models.Tb1.objects.filter(id__lt=10, id__gt=1) # 獲取id大於1 且 小於10的值 models.Tb1.objects.filter(id__in=[11, 22, 33]) # 獲取id等於十一、2二、33的數據 models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in models.Tb1.objects.filter(name__contains="ven") models.Tb1.objects.filter(name__icontains="ven") # icontains大小寫不敏感 models.Tb1.objects.filter(id__range=[1, 2]) # 範圍bettwen and startswith,istartswith, endswith, iendswith基於對象的跨表查詢
一對多查詢(Publish 與 Book)
正向查詢(按字段:publish):
# 查詢nid=1的書籍的出版社所在的城市<br> book_obj=Book.objects.get(nid=1)<br>print(book_obj.publish.city) # book_obj.publish 是nid=1的書籍對象關聯的出版社對象反向查詢(按表名:book_set):
# 查詢 人民出版社出版過的全部書籍 publish=Publish.objects.get(name="人民出版社") book_list=publish.book_set.all() # 與人民出版社關聯的全部書籍對象集合 for book_obj in book_list: print(book_obj.title)一對一查詢(Author 與 AuthorDetail)
正向查詢(按字段:authorDetail):
# 金瓶眉全部做者的名字以及手機號 book_obj=Book.objects.filter(title="金瓶眉").first() authors=book_obj.authors.all() for author_obj in authors: print(author_obj.name,author_obj.authorDetail.telephone)反向查詢(按表名:book_set):
# 查詢egon出過的全部書籍的名字 author_obj=Author.objects.get(name="egon") book_list=author_obj.book_set.all() #與egon做者相關的全部書籍 for book_obj in book_list: print(book_obj.title)注意:
你能夠經過在 ForeignKey() 和ManyToManyField的定義中設置 related_name 的值來覆寫 FOO_set 的名稱。例如,若是 Article model 中作一下更改: publish = ForeignKey(Blog, related_name='bookList'),那麼接下來就會如咱們看到這般:
# 查詢 人民出版社出版過的全部書籍 publish=Publish.objects.get(name="人民出版社") book_list=publish.bookList.all() # 與人民出版社關聯的全部書籍對象集合基於雙下劃線的跨表查詢
Django 還提供了一種直觀而高效的方式在查詢(lookups)中表示關聯關係,它能自動確認 SQL JOIN 聯繫。要作跨關係查詢,就使用兩個下劃線來連接模型(model)間關聯字段的名稱,直到最終連接到你想要的 model 爲止。
# 練習1: 查詢人民出版社出版過的全部書籍的名字與價格(一對多) # 正向查詢 按字段:publish queryResult=Book.objects .filter(publish__name="人民出版社") .values_list("title","price") # 反向查詢 按表名:book queryResult=Publish.objects .filter(name="人民出版社") .values_list("book__title","book__price") # 練習2: 查詢egon出過的全部書籍的名字(多對多) # 正向查詢 按字段:authors: queryResult=Book.objects .filter(authors__name="yuan") .values_list("title") # 反向查詢 按表名:book queryResult=Author.objects .filter(name="yuan") .values_list("book__title","book__price") # 練習3: 查詢人民出版社出版過的全部書籍的名字以及做者的姓名 # 正向查詢 queryResult=Book.objects .filter(publish__name="人民出版社") .values_list("title","authors__name") # 反向查詢 queryResult=Publish.objects .filter(name="人民出版社") .values_list("book__title","book__authors__age","book__authors__name") # 練習4: 手機號以151開頭的做者出版過的全部書籍名稱以及出版社名稱 queryResult=Book.objects .filter(authors__authorDetail__telephone__regex="151") .values_list("title","publish__name")注意:
反向查詢時,若是定義了related_name ,則用related_name替換表名,例如: publish = ForeignKey(Blog, related_name='bookList'):
# 練習1: 查詢人民出版社出版過的全部書籍的名字與價格(一對多) # 反向查詢 再也不按表名:book,而是related_name:bookList queryResult=Publish.objects .filter(name="人民出版社") .values_list("bookList__title","bookList__price")