django數據庫操作和中間件


數據庫配置

django的數據庫相關表配置在models.py文件中,數據庫的連接相關信息配置在settings.py中

  • models.py相關相關參數配置
from django.db import models
  
class userinfo(models.Model):
    name = models.CharField(max_length=30)
    email = models.EmailField()
    memo = models.TextField()

 

可用的字段:

1、models.AutoField  自增列 = int(11)
  如果沒有的話,默認會生成一個名稱為 id 的列,如果要顯示的自定義一個自增列,必須將給列設置為主鍵 primary_key=True。
2、models.CharField  字符串字段
  必須 max_length 參數
3、models.BooleanField  布爾類型=tinyint(1)
  不能為空,Blank=True
4、models.ComaSeparatedIntegerField  用逗號分割的數字=varchar
  繼承CharField,所以必須 max_lenght 參數
5、models.DateField  日期類型 date
  對於參數,auto_now = True 則每次更新都會更新這個時間;auto_now_add 則只是第一次創建添加,之后的更新不再改變。
6、models.DateTimeField  日期類型 datetime
  同DateField的參數
7、models.Decimal  十進制小數類型 = decimal
  必須指定整數位max_digits和小數位decimal_places
8、models.EmailField  字符串類型(正則表達式郵箱) =varchar
  對字符串進行正則表達式
9、models.FloatField  浮點類型 = double
10、models.IntegerField  整形
11、models.BigIntegerField  長整形
  integer_field_ranges = {
    'SmallIntegerField': (-32768, 32767),
    'IntegerField': (-2147483648, 2147483647),
    'BigIntegerField': (-9223372036854775808, 9223372036854775807),
    'PositiveSmallIntegerField': (0, 32767),
    'PositiveIntegerField': (0, 2147483647),
  }
12、models.IPAddressField  字符串類型(ip4正則表達式)
13、models.GenericIPAddressField  字符串類型(ip4和ip6是可選的)
  參數protocol可以是:both、ipv4、ipv6
  驗證時,會根據設置報錯
14、models.NullBooleanField  允許為空的布爾類型
15、models.PositiveIntegerFiel  正Integer
16、models.PositiveSmallIntegerField  正smallInteger
17、models.SlugField  減號、下划線、字母、數字
18、models.SmallIntegerField  數字
  數據庫中的字段有:tinyint、smallint、int、bigint
19、models.TextField  字符串=longtext
20、models.TimeField  時間 HH:MM[:ss[.uuuuuu]]
21、models.URLField  字符串,地址正則表達式
22、models.BinaryField  二進制
23、models.ImageField   圖片
24、models.FilePathField 文件

 

字段相關參數:

1、null=True
  數據庫中字段是否可以為空
2、blank=True
  django的 Admin 中添加數據時是否可允許空值
3、primary_key = False
  主鍵,對AutoField設置主鍵后,就會代替原來的自增 id 列
4、auto_now 和 auto_now_add
  auto_now   自動創建---無論添加或修改,都是當前操作的時間
  auto_now_add  自動創建---永遠是創建時的時間
5、choices
GENDER_CHOICE = (
        (u'M', u'Male'),
        (u'F', u'Female'),
    )
gender = models.CharField(max_length=2,choices = GENDER_CHOICE)
6、max_length
7、default  默認值
8、verbose_name  Admin中字段的顯示名稱
9、name|db_column  數據庫中的字段名稱
10、unique=True  不允許重復
11、db_index = True  數據庫索引
12、editable=True  在Admin里是否可編輯
13、error_messages=None  錯誤提示
14、auto_created=False  自動創建
15、help_text  在Admin中提示幫助信息
16、validators=[]
17、upload-to

 

  • settings.py相關配置

數據庫連接配置:

DATABASES = {
    'default': {
        #'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
        'ENGINE': 'django.db.backends.sqlite3', #添加數據庫引擎;選項['postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'].
        'NAME': 'F:/TestPython/blog/blog/db/data.db', # 數據庫文件的路徑.
        # The following settings are not used with sqlite3:
        # 下面的配置不適用於sqlite3:
        'USER': '',    # 數據庫登陸用戶名
        'PASSWORD': '', # 數據庫登陸密碼
        'HOST': '',                      # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. # 主機名
        'PORT': '',                      # Set to empty string for default. # 端口號
    }
}

 

注冊app:
在settings里的INSTALLED_APPS里面加上你的app名字

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01',
]

 

生成數據庫表

python  manage.py makemigrations 
# 生成一個數據庫結構migrations里面一個表
python  manage.py migrate      
# 根據migrations里面的表來創建數據庫

 

將app的數據庫注冊到admin

在app01下面的admin.py寫入以下內容:
from django.contrib import admin

# Register your models here.
# 導入app01的數據庫模塊
from app01 import models

# 注冊咱們創建的類,通過他來訪問
admin.site.register(models.UserInfo)

 

數據庫相關操作

增刪改查

# 插入數據:
UserInfo.objects.create(name='rain',password='123',email='rain@163.com')

# 刪除數據:
UserInfo.objects.filter(name='rain').delete()

# 修改數據:
UserInfo.objects.filter(name='rain').update(name='Rain1')

# 查找數據:
UserInfo.objects.filter(name='rain')
UserInfo.objects.all()
UserInfo.objects.all()[:10] 
# 切片操作,獲取10個人,不支持負索引,切片可以節約內存
UserInfo.objects.get(name='rain')
#查找所有
models.UserInfo.objects.all()
#查找指定條件
models.UserInfo.objects.filter(age=18)
#查找第一個
models.UserInfo.objects.filter(age=18).first()
#查找所有並且顯示出來
user_list_obj = models.UserInfo.objects.all()
for line in user_list_obj:
    print(line.username,line.age)

 

進階操作

  • 利用雙下划線將字段和對應的操作連接起來
  # 獲取個數
     
    models.Tb1.objects.filter(name='seven').count()

    # 大於,小於
 
    models.Tb1.objects.filter(id__gt=1)              # 獲取id大於1的值
    models.Tb1.objects.filter(id__lt=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等於11、22、33的數據
    models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in

    # 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

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

    # 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"

 

  • F和Q操作
# F 使用查詢條件的值

from django.db.models import F
models.Tb1.objects.update(num=F('num')+1)

# Q 構建搜索條件
from django.db.models import Q
con = Q()

q1 = Q()
q1.connector = 'OR'
q1.children.append(('id', 1))
q1.children.append(('id', 10))
q1.children.append(('id', 9))

q2 = Q()
q2.connector = 'OR'
q2.children.append(('c1', 1))
q2.children.append(('c1', 10))
q2.children.append(('c1', 9))

con.add(q1, 'AND')
con.add(q2, 'AND')

models.Tb1.objects.filter(con)

from django.db import connection
cursor = connection.cursor()
cursor.execute("""SELECT * from tb where name = %s""", ['Lennon'])
row = cursor.fetchone()

 

連表操作

連表關系:

  • 一對多,models.ForeignKey(ColorDic)
  • 一對一,models.OneToOneField(OneModel)
  • 多對多,authors = models.ManyToManyField(Author)

應用場景:

  • 一對一:在某表中創建一行數據時,有一個單選的下拉框(下拉框中的內容被用過一次就消失了)。 例如:原有含10列數據的一張表保存相關信息,經過一段時間之后,10列無法滿足需求,需要為原來的表再添加5列數據。
  • 一對多:當一張表中創建一行數據時,有一個單選的下拉框(可以被重復選擇)。 例如:創建用戶信息時候,需要選擇一個用戶類型【普通用戶】【金牌用戶】【鉑金用戶】等。
  • 多對多:在某表中創建一行數據是,有一個可以多選的下拉框。 例如:創建用戶信息,需要為用戶指定多個愛好。

一對多

  • 數據庫表:models.py UserType存放用戶類型,UserInfo存放用戶信息
from django.db import models
# Create your models here.

class UserType(models.Model):
    caption = models.CharField(max_length=32)
        # 超級管理員,普通用戶,游客,黑河
    def __str__(self):
        return self.caption

class UserInfo(models.Model):
    user = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)
    user_type = models.ForeignKey('UserType')

 

  • 創建有外鍵的數據
#方法一:需要進行兩次數據庫操作,不推薦
UserInfo.objects.create(user='test',pwd='123',user_type=UserType.objects.get(id=1))
#方法二:利用外鍵關系進行直接插入值,此時user_type代指的就是usertype表
UserInfo.objects.create(user='test',pwd='123',user_type_id=1)

>>> from app01 import models
>>> models.UserInfo.objects.create(user='test',pwd='123',user_type=models.UserType.objects.get(id=1))
<UserInfo: UserInfo object>
>>> models.UserInfo.objects.create(user='asdasdadas',pwd='123',user_type_id=3)
<UserInfo: UserInfo object>

 

  • 數據:

  • 查找

1.根據用戶,查找用類型

>>> models.UserInfo.objects.filter(user="test")[0].user_type.caption
'管理員'
此時user_type對應的就是usertype的表,所以直接使用.caption就可以拿到數據

 

2.根據用戶類型查找用戶

#方法一:先查找出用戶類型對應的user_type的id,然后再去userinfo表中查找id對應的用戶
>>> role_id = models.UserType.objects.get(caption='管理員').id
>>> role_id
1
>>> models.UserInfo.objects.filter(user_type=role_id).values('user','pwd')
<QuerySet [{'pwd': '123', 'user': '張三'}, {'pwd': '123', 'user': 'test2'}, {'pwd': '123', 'user': 'test'}]>

#方法二:使用雙下划線進行一次連表操作
>>> models.UserInfo.objects.filter(user_type__caption="管理員")
<QuerySet [<UserInfo: UserInfo object>, <UserInfo: UserInfo object>, <UserInfo: UserInfo object>]>
>>> sql[0].user
'張三'
>>> sql[0].pwd
'123'
>>> sql[0].user_type.caption
'管理員'
>>> sql[0].user_type.id
1

繼續封裝,同時取用戶的所有信息:
>>> sql = models.UserInfo.objects.filter(user_type__caption="管理員").values('user','pwd','user_type__id','user_type__caption')
>>> sql
<QuerySet [{'user_type__id': 1, 'pwd': '123', 'user': '張三', 'user_type__caption': '管理員'}, {'user_type__id': 1, 'pwd': '123', 'user': 'test2', 'user_type__caption': '管理員'}, {'user_type__'pwd': '123', 'user': 'test', 'user_type__caption': '管理員'}]>


打印sql語句:
>>> print(sql.query)
SELECT "app01_userinfo"."user", "app01_userinfo"."pwd", "app01_userinfo"."user_type_id", "app01_usertype"."caption" FROM "app01_userinfo" INNER JOIN "app01_usertype" ON ("app01_userinfo"."user_type_id" = "app01_usertype"."id") WHERE "app01_usertype"."caption" = 管理員

 

跨多張表進行操作,如果UserType表中還有外鍵指向另一張表的主鍵,怎么查呢?
新的表結構如下:

from django.db import models
# Create your models here.

class UserType(models.Model):
    caption = models.CharField(max_length=32) # 超級管理員,普通用戶,游客,黑河
    s = models.ForeignKey('something')
    def __str__(self):
        return self.caption

class UserInfo(models.Model):
    user = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)
    user_type = models.ForeignKey('UserType')
    
class something(models.Model):
    name = models.CharField(max_length=32)

 

查詢:

models.UserInfo.objects.filter(user_type__s__name="一些條件值"

 


這是跨兩張表,跨三張表、四張表都這樣

多對多

  • 表結構: 一個girl表、一個boy表,還一個boy_girl的關系表

  

class Girl(models.Model): 
    name = models.CharField(max_length=32)
    b = models.ManyToManyField('Boy')

class Boy(models.Model):
    name = models.CharField(max_length=32)

 

PS:多對多關系需要三張表,兩張數據表,一張關系表,但是在django 中如果使用ManyToManyField的話,不需要在指定第三張表,默認django會創建。當然,如果不使用該字段的話,也可以手動指定第三張表,然后使用models.ForeignKey做外鍵關聯

  • 添加數據

添加數據到關系表:

女孩跟男孩建立關系   正向操作
>>> G = models.Girl.objects.get(id=1)
>>> g = models.Girl.objects.get(id=1)
>>> girl = models.Girl.objects.get(id=1)
>>> boy = models.Boy.objects.get(id=3)
>>> girl.name
'fuzj3'
>>> boy.name
'fuzj2'

    #使用對象建立關系

>>> girl.b.add(boy)         #此時的b時多對多的字段
>>> bs = models.Boy.objects.all()   #獲取男孩的所有對象,返回數組
>>> g.b.add(*bs)        #批量將關系插入到關系表

    #使用主鍵值建立關系
>>> girl = models.Girl.objects.get(id=3)
>>> girl.b.add(3)
>>> bs_list = [1,4,5]
>>> girl.b.add(*bs_list)


男孩跟女孩建立關系  反向操作

>>> boy = models.Boy.objects.get(id=1)
>>> boy
<Boy: Boy object>
>>> boy.girl_set.add(3)

 

  • 刪除

    remove() 刪除
    clear() 清空

>>> g1 = models.Girl.objects.get(id=1)   #獲取一個女孩對象
>>> g1.b.remove(2)              #單個刪除一個關系
>>> g1.b.remove(*[3,4])     #批量刪除多個關系
>>> g1.b.clear()                #清空本對象對應的所有關系

 

  • 查詢
    支持all() filer()等操作

    

1.通過女孩查找男孩(正向查找)
>>> models.Girl.objects.filter(name='fuzj2').values('id','name','b__name')
<QuerySet [{'name': 'fuzj2', 'id': 3, 'b__name': 'fuzj'}, {'name': 'fuzj2', 'id': 3, 'b__name': 'fuzj2'}, {'name': 'fuzj2', 'id': 3, 'b__name': 'fuzj3'}, {'name': 'fuzj2', 'id': 3, 'b__name': None}]>

'b__name'中 b此時代指的關系表,所以b__name 就是跨到了boy表,。此時相當於直接跨了兩張表
    2. 通過男孩查找女孩(反向查找)
>>> models.Boy.objects.filter(name='fuzj').values('id','name','girl__name')
<QuerySet [{'name': 'fuzj', 'id': 1, 'girl__name': 'fuzj2'}]>

'girl__name' 中,girl是boy表中隱藏的字段,代指的是和girl的關系表,所以girl__name就跨到了girl表

 


  • 修改

    默認django不支持修改操作,如果實現修改操作,只能是先刪除,然后再創建,顯然這個效率不是很高。所以,我們可以通過原生的sql語句進行操作

from django.db import connection
cursor = connection.cursor()
cursor.execute("update tbname set girl_id = '3' where boy_id = %s",[3])

 

中間件

中間件定義:

  • 中間件是一個、一個的管道,如果相對任何所有的通過Django的請求進行管理都需要自定義中間件

  • 中間件可以對進來的請求和出去的請求進行控制

  • 中間件是一類。

由上圖可知,中間件是位於wsgi和路由系統中間的環節。用戶請求和和回應請求都會經過中間件。

看下面的代碼在settings里中間件的類:

MIDDLEWARE_CLASSES = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

 

當有請求過來的時候,默認從上倒下執行!然后在返回的時候從下面在返回回去

自定義中間件

中間件中可以定義四個方法,分別是:

  • process_request(self,request)
  • process_view(self, request, callback, callback_args, callback_kwargs)
  • process_exception(self, request, exception) 這個方法只有在出現錯誤的時候才會觸發
  • process_response(self, request, response)
  • process_template_response(self,request,response) 這個方法只有在返回對象中有render方法的時候才執行,如render_to_response('/index/')

以上方法的返回值可以是None和HttpResonse對象,如果是None,則繼續按照django定義的規則向下執行,如果是HttpResonse對象,則直接將該對象返回給用戶。

  • 創建中間件腳本

在django的的project目錄下創建一個middleware目錄,並創建一個md.py的腳本,內容如下:

class Testmiddle:
    def process_request(self,request):
        print 'Testmiddle process_request'
    def process_view(self, request, callback, callback_args, callback_kwargs):
        print 'Testmiddle process_view'
    def process_exception(self, request, exception):
        pass
    def process_response(self, request, response):
        print 'Testmiddle process_response'
        return response
    
class Nextmiddle:
    def process_request(self,request):
        print 'Nextmiddle process_request'
    def process_view(self, request, callback, callback_args, callback_kwargs):
        print 'Nextmiddle process_view'
    def process_exception(self, request, exception):
        pass
    def process_response(self, request, response):
        print 'Nextmiddle process_response'
        return response

 

  • 注冊中間件

修改settings.py文件,在MIDDLEWARE_CLASSES中添加我們創建的中間件

MIDDLEWARE_CLASSES = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'middleware.middle.Testmiddle',
    'middleware.middle.Nextmiddle',
]

 

  • 設置url 略
  • 測試:
Testmiddle process_request
Nextmiddle process_request
Testmiddle process_view
Nextmiddle process_view
This app01 Views.index
Nextmiddle process_response
Testmiddle process_response

 

從輸出結果可以看出:

他是先執行Testmiddle 的request 方法又執行了Nextmiddle的 process_request方法, 然后在執行Testmiddle的view方法,Nextmiddle的view方法

注意:django版本1.10以后,會報如下錯誤:

解決如下:

from django.utils.deprecation import MiddlewareMixin
class Testmiddle(MiddlewareMixin):
    def process_request(self,request):
        print 'Testmiddle process_request'
    def process_view(self, request, callback, callback_args, callback_kwargs):
        print 'Testmiddle process_view'
    def process_exception(self, request, exception):
        pass
    def process_response(self, request, response):
        print 'Testmiddle process_response'
        return response
    
class Nextmiddle(MiddlewareMixin):
    def process_request(self,request):
        print 'Nextmiddle process_request'
    def process_view(self, request, callback, callback_args, callback_kwargs):
        print 'Nextmiddle process_view'
    def process_exception(self, request, exception):
        pass
    def process_response(self, request, response):
        print 'Nextmiddle process_response'
        return response

 

注意:
* 老版本中在中間件中如果某個中間件類的方法返回的不是none,則后面的中間件不會再處理請求,也不會到達路由系統,而是直接到第一個process_response,開始所有的process_response處理
* 新版本中在中間件中如果某個中間件類的方法返回的不是none,則后面的中間件不會再處理請求,也不會到達路由系統,而是直接到最后一個process_response處理,然后返回給客戶端

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM