python學習點滴記錄-Day18-django-orm

第18天課程內容:html

  • 模板語言的經常使用標籤
  • 自定義過濾器與標籤
  • 模板語言之繼承
  • ORM的查詢API
  • 單表查詢之雙下劃線
  • 一對多的添加數據方法

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相關

 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數據庫字段的大小。還有一些適用於全部字段的通用參數。 這些參數在文檔中有詳細定義,這裏咱們只簡單介紹一些最經常使用的:

(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'
View Code

一旦你創建好數據模型以後,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")
相關文章
相關標籤/搜索