Django基礎——Model篇(一)


    到目前為止,當程序涉及到數據庫相關操作時,我們一般都會這么操作:
    (1)創建數據庫,設計表結構和字段
    (2)使用MySQLdb來連接數據庫,並編寫數據訪問層代碼
    (3)業務邏輯層去調用數據訪問層,執行數據庫操作

import MySQLdb
 
def GetList(sql):
    db = MySQLdb.connect(user='root', db='mydb', passwd='123', host='localhost')
    cursor = db.cursor()
    cursor.execute(sql)
    data = cursor.fetchall()
    db.close()
    return data
 
def GetSingle(sql):
    db = MySQLdb.connect(user='root', db='mydb', passwd='123', host='localhost')
    cursor = db.cursor()
    cursor.execute(sql)
    data = cursor.fetchone()
    db.close()
    return data
python操作數據庫

    Django為使用一種新的方式,即:關系對象映射(Object Relational Mapping,簡稱ORM)。Django遵循 Code Frist 的原則,即:根據代碼中定義的類來自動生成數據庫表。Django是通過Model類來操作數據庫的,程序員不需要關注SQL語句和數據庫的類型(無論數據庫是MySql、Sqlite,還是其它類型),Django自動生成相應數據庫類型的SQL語句,來完成對數據庫數據的操作。

一 創建數據庫 

    當我們在已經創建的Django工程中創建app時(假設app的名稱為app01),那么在app01模塊下默認會生成models.py文件,這個就是Django工程中操作數據庫的文件。 

 1 創建數據庫Model類(models.py文件)

#/usr/bin/env python #-*- coding:utf-8 -*- from __future__ import unicode_literals from django.db import models # Create your models here. # ORM模型 # 類 -> 數據庫表 # 對象 -> 表中的每一行數據 # 對象.id,對象.value -> 每行中的數據 #這個類是用來生成數據庫表的,這個類必須繼承models.Model類 class UserInfo(models.Model): #創建表的字段  username = models.CharField(max_length=16) #創建一個字段,類型為字符串類型,最大長度為16  password = models.CharField(max_length=32) #創建一個字段,類型為字符串類型,最大長度為32 #注:對於ORM框架,可以簡單的認為自定義類UserInfo表示數據庫的表;根據UserInfo創建的對象表示數據庫表 #里的一行數據;而對象.username和對象.password表示每一行數據里具體的字段(username/password)的數據。 

 (1)更多字段類型

    一般數據庫中字段類型大概5種(字符串/數字/浮點型/時間類型/布爾類型),但Django為了在后台admin中可以操作數據庫,同時為了限制在admin中對數據庫的無效操作,Model中設置了很多種數據類型。

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 文件

 models.DateTimeField/models.GenericIPAddressField/models.ImageField使用字段說明

class UserInfo(models.Model): name = models.CharField(max_length=32) ctime = models.DateTimeField(auto_now=True) #每當你創建一行數據時,Django就會在該行數據中增加一個ctime字段 uptime = models.DateTimeField(auto_now_add=True) #當前表任何一行數據有更新時,Django就會自動更新該字段. #下面兩項是新增的字段,注意新增時參數的設置,否則在命令行創建數據庫時報錯,null=True表示在數據庫中該字段可以為空,default='xxx'表示默認值
     email_1 = models.EmailField(max_length=32,null=True) email_2 = models.EmailField(max_length=32,default='aaa@qq.com') #新增字段,blank=True表示admin后台可以為空
     ip = models.GenericIPAddressField(protocol='ipv4',null=True,blank=True)
#upload_to='upload'表示用戶上傳數據存儲的位置,這里需要注意:在數據庫中實際保存的並不是文件,而是文件存放的路徑 img
= models.ImageField(null=True,blank=True,upload_to='upload')

 (2)更多參數類型

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  文件上傳路徑

 (3)Model類的擴展

   輸出Model對象默認返回值

class UserInfo(models.Model): name = models.CharField(max_length=32) ctime = models.DateTimeField(auto_now=True) #每當你創建一行數據時,Django就會在該行數據中增加一個ctime字段
    uptime = models.DateTimeField(auto_now_add=True) #當前表任何一行數據有更新時,Django就會自動更新該字段.
    #下面兩項是新增的字段,注意新增時參數的設置,否則在命令行創建數據庫時報錯,null=True表示在數據庫中該字段可以為空,default='xxx'表示默認值
    email_1 = models.EmailField(max_length=32,null=True) email_2 = models.EmailField(max_length=32,default='aaa@qq.com') #新增字段,blank=True表示admin后台可以為空
    ip = models.GenericIPAddressField(protocol='ipv4',null=True,blank=True) #upload_to='upload'表示用戶上傳數據存儲的位置,這里需要注意:在數據庫中實際保存的並不是文件,而是文件存放的路徑
    img = models.ImageField(null=True,blank=True,upload_to='upload')
#下面的__unicode__(self)方法,表示當輸出這個類創建的對象時,默認會輸出這個對象的name字段
def __unicode__(self): return self.name
def model(request): #創建兩條數據
    models.UserInfo.objects.create(name='alex') models.UserInfo.objects.create(name='eric') obj_1 = models.UserInfo.objects.all() obj_2 = models.UserInfo.objects.filter(name='alex') #輸出obj及其類型
    print obj_1,type(obj_1) print obj_2,type(obj_2) return HttpResponse('ok')

  如果不加上述__unicode__(self)方法,則輸出結果為

[<UserInfo: UserInfo object>, <UserInfo: UserInfo object>] <class 'django.db.models.query.QuerySet'>
[<UserInfo: UserInfo object>,] <class 'django.db.models.query.QuerySet'>

  如果加上上述__unicode__(self)方法,則輸出結果為

[<UserInfo: alex>, <UserInfo: eric>] <class 'django.db.models.query.QuerySet'> [<UserInfo: alex>,] <class 'django.db.models.query.QuerySet'>

  在數據庫表已經生成的情況下,添加新的字段報錯,錯誤信息如下:

localhost:Django_lastday luotim$ python manage.py makemigrations You are trying to add a non-nullable field 'email' to userinfo without a default; we can't do that (the database needs something to 
populate existing rows).
Please select a fix: 1) Provide a one-off default now (will be set on all existing rows) 2) Quit, and let me add a default in
models.py Select an option:

    當你在已有的數據庫表中添加一個非空的字段的時,由於原表中已有的行沒有這個字段,那么就會導致報錯。解決辦法就是:允許為空、或者設置默認值。假設在已有的表中添加如下兩個字段,那么可以設置字段為空,或者給字段設置默認值

email_1 = models.EmailField(max_length=32,null=True) email_2 = models.EmailField(max_length=32,default='aaa@qq.com')

  上傳圖片實例

class UserInfo(models.Model): name = models.CharField(max_length=32) ctime = models.DateTimeField(auto_now=True) #每當你創建一行數據時,Django就會在該行數據中增加一個ctime字段
    uptime = models.DateTimeField(auto_now_add=True) #當前表任何一行數據有更新時,Django就會自動更新該字段.
    #下面兩項是新增的字段,注意新增時參數的設置,否則在命令行創建數據庫時報錯,null=True表示在數據庫中該字段可以為空,default='xxx'表示默認值
    email_1 = models.EmailField(max_length=32,null=True) email_2 = models.EmailField(max_length=32,default='aaa@qq.com') #新增字段,blank=True表示admin后台可以為空
    ip = models.GenericIPAddressField(protocol='ipv4',null=True,blank=True) #upload_to='upload'表示用戶上傳數據存儲的位置,這里需要注意:在數據庫中實際保存的並不是文件,而是文件存放的路徑
    img = models.ImageField(null=True,blank=True,upload_to='upload') def __unicode__(self): return self.name
Model類
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>

<body> {#注意form表單提交文件時,form中的enctype="multipart/form-data"參數表示分片上傳#} <form action="/upload/" method="post" enctype="multipart/form-data">
        <p><input type="file" name="f1"/></p>
        <p><input type="file" name="f2"/></p>
        <p><input type="text" name="hostname"/></p>
        <input type="submit" value="upload"/>
    </form>
</body>
</html>
HTML頁面
def upload(request):
    if request.method == 'POST':
        # 這里只會獲取type='text'的內容
        inp_post = request.POST
        # 這里獲取提交文件的文件名,字典形式
        inp_files = request.FILES
        # 獲取name='f1'對應的文件對象
        file_obj1 = inp_files.get('f1')
        print file_obj1,type(file_obj1)
        # from django.core.files.uploadedfile import InMemoryUploadedFile
        # 獲取對應的文件名
        print file_obj1.name
        # 注意在windows下,打開模式為'wb',否則出錯
        f = open(file_obj1.name,'wb')
        # 分片傳輸,每64k寫一次,chunks方法中利用了yield,生成器
        print file_obj1.chunks()
        for line in file_obj1.chunks():
            f.write(line)
        f.close()
    return render(request,'home/upload.html')
Views中的upload方法

2 注冊APP(settings.py文件)

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

 3 執行命令(Django 1.9)

python manage.py makemigrations
python manage.py migrate

   當執行python manage.py makemigrations命令時,在Django工程中會生成如圖所示的文件(其中migrations為新生成的模塊,紅框中為新生成的文件)

   其中0001_initial.py文件的內容如下(相當於生成一個數據庫源,后面生成數據庫表會按照這個數據庫源來生成)

# -*- coding: utf-8 -*- # Generated by Django 1.9.2 on 2016-03-11 12:46

from __future__ import unicode_literals from django.db import migrations, models class Migration(migrations.Migration): initial = True dependencies = [] operations = [ migrations.CreateModel( name='UserInfo', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('username', models.CharField(max_length=16)), ('password', models.CharField(max_length=32)), ], ), ]

   然后執行python manage.py migrate命令,它會讀取0001_initial.py這個數據庫結構文件從而生成數據庫表。

 4 通過admin來查看數據庫

   先創建超級用戶,然后在admin.py文件中按照如下進行配置

#/usr/bin/env python #-*- coding:utf-8 -*-

from django.contrib import admin # Register your models here.
from app01 import models #注冊models.py文件中創建的類
admin.site.register(models.UserInfo)

    然后可以通過頁面訪問到如下信息

二 操作數據庫表

 1 基本操作

# --3種方法
# 1種方法
models.tb.objects.create(c1='xx', c2='oo')
# 2種方法
obj = models.tb(c1='xx', c2='oo')
obj.save()
# 3種方法--可以接受字典類型數據 **kwargs
dic = {'c1':'xx','c2':'oo'}
models.tb.objects.create(**dic)

#
models.tb.objects.get(id=123) #獲取單條數據,不存在則報錯(不建議)
models.tb.objects.all() #獲取全部數據
models.tb.objects.all().first() #獲取全部數據的第1條數據
models.tb.objects.filter(name='seven') #1個參數,獲取指定條件的數據
models.tb.objects.filter(name='seven',password='123') #2個參數,獲取指定條件的數據
dic = {'name':'seven','password':'123'}
models.tb.objects.filter(**dic) #參數可以是字典形式,獲取指定條件的數據

#
models.tb.objects.filter(name='seven').delete() # 刪除指定條件的數據
dic = {'name':'seven','password':'123'}
models.tb.objects.filter(**dic).delete() #參數是字典形式

#
# 1種方法
models.tb.objects.filter(name='seven').update(password='123') #將指定條件的數據更新
# 2種方法
obj = models.tb.objects.get(id=1)
obj.c1 = '111'
obj.save() # 修改單條數據
# 3種方法--字典參數
dic = {'name':'seven','password':'123'}
models.tb.objects.filter(**dic).update(**dic) #
參數是字典形式

 數據庫創建數據實例

#hmtl文件
<form action="/add_user/" method="post">
    <p>用戶名:{{ obj.username }}</p>
    <p>密碼:{{ obj.password }}</p>
    <input type="submit" value="submit"/>
</form>

#forms模塊中的account.py文件
class AddUser(forms.Form): username = forms.CharField() password = forms.CharField(widget=forms.PasswordInput()) #views模塊中的login.py文件
def add_user(request): obj = AccountForm.AddUser(request.POST) if request.method == 'POST': if obj.is_valid(): user_input = obj.clean() print user_input #用戶輸入的就是字典類型,所以參數為**user_input
            models.UserInfo.objects.create(**user_input) print models.UserInfo.objects.all() return render(request,'account/add_user.html',{'obj':obj}) return render(request,'account/add_user.html',{'obj':obj}) #結果
    --print user_input {'username': u'xxx', 'password': u'123'} --print models.UserInfo.objects.all() 返回值 [<UserInfo: xxx>, <UserInfo: alex>,]  #Model類中添加了__unicode__方法
數據庫創建數據實例

 數據庫查找數據實例

from django import forms
from app01 import models

class ImportForm(forms.Form):
    # 優化后的寫法,設置select的數據為空
    admin = forms.IntegerField(
        widget=forms.Select()
    )
    # 為了實時的獲取文件中的數據,重新寫了構造方法,這樣當修改了文件數據,重新請求時(不需要重啟)
    # 實時的獲取文件中的數據,因為每次請求時都會把類實例化,那么就會執行類的構造方法,這里利用了
    # 面向對象編程的思想(靜態字段屬於類),好好體會這里面的思想
    def __init__(self,*args,**kwargs):
        super(ImportForm,self).__init__(*args,**kwargs)
        # 1、從文件中獲取數據,然后賦值給self.fields['admin'].widget.choices
        # import json
        # f = open('db_admin')
        # data = f.read()
        # data_tuple = json.loads(data)
        # self.fields是深拷貝的結果self.fields = copy.deepcopy(self.base_fields)
        # self.fields['admin'].widget.choices = data_tuple

        # 2、直接從數據庫中獲取self.fields['admin'].widget.choices
        self.fields['admin'].widget.choices = models.SimpleModel.objects.all().values_list('id','username')
forms模塊中的ImportForm類
from django.shortcuts import render,HttpResponse
from app01.forms import home as HomeForm
from app01 import models

def index(request):
    # 創建一行數據
    # dic = {'username':'alex','password':'123'}
    # models.SimpleModel.objects.create(**dic)

    res = models.SimpleModel.objects.all()
    #對應的sql語句"SELECT "app01_simplemodel"."id", "app01_simplemodel"."username", "app01_simplemodel"."password" FROM "app01_simplemodel""
    print res.query
    #[<SimpleModel: SimpleModel object>] 列表
    print res
    # <class 'django.db.models.query.QuerySet'> 類
    print type(res)
    # 取某個字段值,字典
    ret = models.SimpleModel.objects.all().values('username')
    # [{'username': u'alex'}] 字典
    print ret
    # <class 'django.db.models.query.QuerySet'>
    print type(ret)
    # 取某個字段值,列表
    ref1 = models.SimpleModel.objects.all().values_list('username')
    # [(u'alex',)] 元組組成的列表
    print ref1
    # <class 'django.db.models.query.QuerySet'>
    print type(ref1)
    # [(1, u'alex')] 獲取(id,username)元組組成的列表
    ref2 = models.SimpleModel.objects.all().values_list('id','username')
    print ref2

    obj = HomeForm.ImportForm()
    return render(request,'home/index.html',{'obj':obj})
Views模塊中的index函數
class SimpleModel(models.Model):
    username = models.CharField(max_length=64)
    password = models.CharField(max_length=64)
models模塊中的SimpleModel類
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>錄入數據</h1>
    <form action="/index/">
       <p>{{ obj.host_type }} </p>
       <p>{{ obj.hostname }}</p>
       <p>{{ obj.admin }}</p>
    </form>
    <h1>數據列表</h1>
</body>
</html>
index.html文件

值得注意的地方:

#獲取指定列的值,可以傳多個參數,它的結果為字典形式
models.UserInfo.objects.all().values('password')
#結果  
[{'password': u'aaa'}, {'password': u'bbb'}, {'password': u'ccc'}]

#獲取指定列的值,可以傳多個參數,它的結果為指定列的值先組成元組,然后再由這些元組組成列表
models.UserInfo.objects.all().values_list('password')
#結果
[(u'alex',), (u'eric',), (u'rain',),]

#在form中生成select標簽時,可以通過它來獲取值然后給choices
models.UserInfo.objects.all().values_list('id','username')
#結果
[(1, u'alex'), (2, u'eric'), (3, u'rain'),]

 2 進階操作(了不起的雙下划線)

   利用雙下划線將字段和對應的操作連接起來

# 獲取個數
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等於112233的數據
models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in

# contains(類似於數據庫中like的語法)
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

#以什么開始,以什么結束,和上面一樣帶i的是大小寫不敏感
# startswithistartswith, endswith, iendswith

#排序
models.Tb1.objects.filter(name='seven').order_by('id') # asc正序
models.Tb1.objects.filter(name='seven').order_by('-id') # desc反序

#分頁時使用
models.Tb1.objects.all()[10:20] #取所有數據的10條到20條,分頁的時候用的到

#分組使用
from django.db.models import Count, Min, Max, Sum
models.Tb1.objects.all().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"

 

 

參考資料:

     http://www.cnblogs.com/wupeiqi/articles/5237704.html

     http://www.cnblogs.com/wupeiqi/articles/5246483.html


免責聲明!

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



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