02:django model數據庫操做

Django其餘篇

目錄:

1.1 Django中使用MySQL     返回頂部

  一、先寫類:在 app01/models.py中寫類html

from django.db import models


class Student(models.Model):
    name = models.CharField(max_length=64,verbose_name='姓名')
    age = models.IntegerField(verbose_name='年紀')

    class Meta:
        db_table = 'student'
        verbose_name_plural = '學生表'

    def __str__(self):
        return self.name
app01/models.py

  二、在Django項目中使用MySQLpython

    1. 建立管理員密碼,與數據庫
mysql

        1.  mysqladmin -uroot password 123456                 #  用戶名:root         密碼:123456linux

        2.   mysql -uroot -p                                               #  dos下登陸MySQLgit

        3.  create database MyCRM charset utf8;                #  建立數據庫MyCRMsql

        4.  drop database MyCRM;                                    # 若是須要也能夠把數據庫刪除數據庫

        5.  show databases;                                             #  查看現有數據庫express

    2. 配置使用MySQL(修改settings.py配置文件)django

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'MyCRM',              # 指定數據庫名稱:MyCRM
        'USER': 'root',
        'PASSWORD': '123456',
        'HOST': '127.0.0.1',
        'PORT': '3306',
    }
}

'''註釋默認數據庫配置'''
# DATABASES = {
#     'default': {
#         'ENGINE': 'django.db.backends.sqlite3',
#         'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
#     }
# }
配置使用MySQL

    3. 主動修改成pymysqlapp

        1. Django默認使用MySQLdb模塊連接MySQL,但在python3中尚未MySQLdb

        2. 主動修改成pymysql,在project同名文件夾下的__init__文件中添加以下代碼便可

import pymysql
pymysql.install_as_MySQLdb()
主動修改成pymysql

    4. 建立表  (記得註冊APP)

        python manage.py makemigrations
        python manage.py migrate --fake 

  三、使用django admin

    1. 建立django admin管理員帳號

        python manage.py createsuperuser

    二、配置django admin顯示    

from django.contrib import admin
from app01 import models

class StudentAdmin(admin.ModelAdmin):
    list_display = ('name','age',)
    search_fields = ('name','age',)

admin.site.register(models.Student, StudentAdmin)
app01/admin.py

1.2 建立表     返回頂部

  一、建立表基本語法

from django.db import models

class Student(models.Model):
    name = models.CharField(max_length=64,verbose_name='姓名')
    age = models.IntegerField(verbose_name='年紀')

    class Meta:
        db_table = 'student'
        verbose_name_plural = '學生表'

    def __str__(self):
        return self.name
app01/models.py

  二、元信息Meta

from django.db import models

class Student(models.Model):
    name = models.CharField(max_length=64,verbose_name='姓名')
    age = models.IntegerField(verbose_name='年紀')

    class Meta:
        # 1 數據庫中生成的表名稱 默認 app名稱 + 下劃線 + 類名
        db_table = "student"  # 本身指定建立的表名

        # 2 verbose_name加s
        verbose_name_plural = '學生表'  # 若果這個字段也是user那麼4中表名才顯示user

        # 3 聯合惟一索引
        unique_together = (("name", "password"),)

        # 4 聯合索引   (缺點是最左前綴,寫SQL語句基於password時不能命中索引,查找慢)
        #  如:select * from tb where password = ‘xx’    就沒法命中索引
        index_together = [
            ("name", "password"),
        ]

    def __str__(self):
        return self.name
元信息Meta

  三、字段

from django.db import models

class UserGroup(models.Model):
    uid = models.AutoField(primary_key=True)

    name = models.CharField(max_length=32,null=True, blank=True)
    email = models.EmailField(max_length=32)
    text = models.TextField()

    ctime = models.DateTimeField(auto_now_add=True)      # 只有添加時纔會更新時間
    uptime = models.DateTimeField(auto_now=True)         # 只要修改就會更新時間

    ip1 = models.IPAddressField()                  # 字符串類型,Django Admin以及ModelForm中提供驗證 IPV4 機制
    ip2 = models.GenericIPAddressField()           # 字符串類型,Django Admin以及ModelForm中提供驗證 Ipv4和Ipv6

    active = models.BooleanField(default=True)

    data01 = models.DateTimeField()                      # 日期+時間格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ
    data02 = models.DateField()                          # 日期格式      YYYY-MM-DD
    data03 = models.TimeField()                          # 時間格式      HH:MM[:ss[.uuuuuu]]

    age = models.PositiveIntegerField()           # 正小整數 0 ~ 32767
    balance = models.SmallIntegerField()          # 小整數 -32768 ~ 32767
    money = models.PositiveIntegerField()         # 正整數 0 ~ 2147483647
    bignum = models.BigIntegerField()             # 長整型(有符號的) -9223372036854775808 ~ 9223372036854775807
    
    user_type_choices = (
        (1, "超級用戶"),
        (2, "普通用戶"),
        (3, "普普通用戶"),
    )
    user_type_id = models.IntegerField(choices=user_type_choices, default=1)
經常使用字段
    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   上傳圖片的寬度保存的數據庫字段名(字符串)


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

    FloatField(Field)
        - 浮點型

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

    BinaryField(Field)
        - 二進制類型
不經常使用字段

   四、參數

    null                數據庫中字段是否能夠爲空
    default             數據庫中字段的默認值
    primary_key         數據庫中字段是否爲主鍵    
    db_index            數據庫中字段是否能夠創建索引
    unique              數據庫中字段是否能夠創建惟一索引
    verbose_name        Admin中顯示的字段名稱
    blank               Admin中是否容許用戶輸入爲空
    editable            Admin中是否能夠編輯
    help_text           Admin中該字段的提示信息
    error_messages      自定義錯誤信息(字典類型),從而定製想要顯示的錯誤信息;
                        字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
                        如:{'null': "不能爲空.", 'invalid': '格式錯誤'}


    db_column           數據庫中字段的列名
    db_tablespace


    unique_for_date     數據庫中字段【日期】部分是否能夠創建惟一索引
    unique_for_month    數據庫中字段【月】部分是否能夠創建惟一索引
    unique_for_year     數據庫中字段【年】部分是否能夠創建惟一索引


    choices             Admin中顯示選擇框的內容,用不變更的數據放在內存中從而避免跨表操做
                        如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)



    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'), ]
                            )
參數

1.3 Django一對多表結構操做     返回頂部

  一、一對多基本增刪改查

       

from django.db import models

class Student(models.Model):
    name = models.CharField(max_length=64,verbose_name='姓名')
    age = models.IntegerField(verbose_name='年紀')
    clsname = models.ForeignKey(to='ClassName', to_field='id',on_delete=models.CASCADE)

    class Meta:
        db_table = 'student'
        verbose_name_plural = '學生表'

    def __str__(self):
        return self.name
    

class ClassName(models.Model):
    clsname = models.CharField(max_length=64, verbose_name='班級名稱')

    class Meta:
        db_table = 'classname'
        verbose_name_plural = '班級表'

    def __str__(self):
        return self.clsname
app01/models.py
from django.shortcuts import render,HttpResponse
from app01 import models

def orm(request):
    # 1 建立
    # 建立數據方法一
    models.Student.objects.create(name='root', age=2, clsname_id=1)
    # 建立數據方法二
    obj = models.Student(name='root2', age=2, clsname_id=1)
    obj.save()
    # 建立數據庫方法三(傳入字典必須在字典前加兩個星號)
    dic = {'name': 'root3', 'age': 2, 'clsname_id': 1}
    models.Student.objects.create(**dic)

    # 2 刪除
    # models.UserInfo.objects.all().delete()  # 刪除全部
    models.Student.objects.filter(name='root').delete()  # 刪除指定

    # 3 更新
    models.Student.objects.all().update(age=100)  # 將全部用戶的年紀修改爲 100
    models.Student.objects.filter(name='root2').update(age=99)  # 將root2年紀修改成 99

    # 4.1 正向查找
    print( models.Student.objects.get(name='zhangsan').clsname.clsname )  # 查找學生zhangsan所在班級
    print( models.Student.objects.filter(clsname__clsname='1812A') )  # 查詢1812A班級全部學生

    # 4.2 反向查找 ClassNameObj.userinfo_set.all()   表名_set.all()
    print( models.ClassName.objects.get(clsname='1812A').student_set.all() )   # 查詢1812A班級全部學生

    return HttpResponse('orm')
app01/views.py
from django.contrib import admin
from django.urls import path, re_path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    re_path(r'orm/$', views.orm, name='orm')
]
urls.py

  二、一對多更多查詢操做

from django.db import models

class UserType(models.Model):
    user_type_name = models.CharField(max_length=32)
    def __str__(self):
        return self.user_type_name            #只有加上這個,Django admin纔會顯示錶名

class User(models.Model):
    username = models.CharField(max_length=32)
    pwd = models.CharField(max_length=64)
    ut = models.ForeignKey(
        to='UserType',
        to_field='id',

        # 一、反向操做時,使用的鏈接前綴,用於替換【表名】
        # 如: models.UserGroup.objects.filter(a__字段名=1).values('a__字段名')
        related_query_name='a',

        #二、反向操做時,使用的字段名,用於代替 【表名_set】 如: obj.b_set.all()
        # 使用時查找報錯
        # related_name='b',
    )
/app01/models.py建立一對多表
from django.shortcuts import HttpResponse
from app01 import models

def orm(request):
    # 1 正向查找
    #1.1 正向查找user表用戶名
    print(models.User.objects.get(username='zhangsan').username)           # zhangsan

    #1.2 正向跨表查找用戶類型
    print(models.User.objects.get(username='zhangsan').ut.user_type_name)  # student

    #1.3 雙下劃線正向跨表正向查找
    print( models.User.objects.all().values('ut__user_type_name','username') )


    # 2 反向查找
    # 2.1:【表名_set】,反向查找user表中用戶類型爲student 的全部用戶
    print( models.UserType.objects.get(user_type_name='student').user_set.all() )           # [<User: lisi>, <User: wangwu>]

    # 2.2:【a__字段名】反向查找user表中張三在UserType表中的類型:([<UserType: teacher>])
    print( models.UserType.objects.filter(a__username='zhangsan') )                         # student
    # 這裏的a是user表的ForeignKey字段的參數:related_query_name='a'

    # 2.3: 雙下劃線跨表反向查找
    print( models.UserType.objects.all().values('a__username', 'user_type_name') )


    # 3 自動建立User表和UserType表中的數據
    '''
    username = [{'username':'zhangsan','pwd':'123','ut_id':'1'},
                {'username':'lisi','pwd':'123','ut_id':'1'},
                {'username':'wangwu','pwd':'123','ut_id':'1'},]

    user_type = [{'user_type_name':'student'},{'user_type_name':'teacher'},]

    for type_dic in user_type:
        models.UserType.objects.create(**type_dic)

    for user_dic in username:
        models.User.objects.create(**user_dic)
    '''
    return HttpResponse('orm')
/app01/views.py一對多中正向反向查找

  三、一對多使用values和values_list結合雙下劃線跨表查詢

from django.shortcuts import HttpResponse
from app01 import models

def orm(request):
    # 第一種:values-----獲取的內部是字典  拿固定列數
    # 1.1 正向查找: 使用ForeignKey字段名ut結合雙下劃線查詢
    models.User.objects.filter(username='zhangsan').values('username', 'ut__user_type_name')

    # 1.2 向查找: 使用ForeignKey的related_query_name='a',的字段
    models.UserType.objects.all().values('user_type_name', 'a__username')


    # 第二種:values_list-----獲取的是元組  拿固定列數
    # 1.1 正向查找: 使用ForeignKey字段名ut結合雙下劃線查詢
    stus = models.User.objects.filter(username='zhangsan').values_list('username', 'ut__user_type_name')

    # 1.2 反向查找: 使用ForeignKey的related_query_name='a',的字段
    utype = models.UserType.objects.all().values_list('user_type_name', 'a__username')


    # 3 自動建立User表和UserType表中的數據
    '''
    username = [{'username':'zhangsan','pwd':'123','ut_id':'1'},
                {'username':'lisi','pwd':'123','ut_id':'1'},
                {'username':'wangwu','pwd':'123','ut_id':'1'},]

    user_type = [{'user_type_name':'student'},{'user_type_name':'teacher'},]

    for type_dic in user_type:
        models.UserType.objects.create(**type_dic)

    for user_dic in username:
        models.User.objects.create(**user_dic)
    '''

    return HttpResponse('orm')
一對多使用values和values_list結合雙下劃線跨表查詢

  四、一對多ForeignKey可選參數

一、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                        # ,刪除關聯數據,
四、related_name=None,                           # 反向操做時,使用的字段名,用於代替 【表名_set】 如: obj.表名_set.all()
                                                # 在作自關聯時必須指定此字段,防止查找衝突
五、delated_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}
七、db_constraint=True                           # 是否在數據庫中建立外鍵約束
八、parent_link=False                            # 在Admin中是否顯示關聯數據
一對多ForeignKey可選參數

1.4 Django多對多表結構操做     返回頂部

   一、建立並操做多對多表

        

      1. 第一種: 本身不建立第三張關係表,有m2m字段: 根據queryset對象增刪改查(推薦

from django.db import models

class Student(models.Model):
    name = models.CharField(max_length=64,verbose_name='姓名')
    age = models.IntegerField(verbose_name='年紀')
    clsname = models.ForeignKey(to='ClassName', to_field='id',on_delete=models.CASCADE)

    class Meta:
        db_table = 'student'
        verbose_name_plural = '學生表'

    def __str__(self):
        return self.name


class ClassName(models.Model):
    clsname = models.CharField(max_length=64, verbose_name='班級名稱')
    lsname = models.ManyToManyField(to='Lesson', related_query_name='cls')

    class Meta:
        db_table = 'classname'
        verbose_name_plural = '班級表'

    def __str__(self):
        return self.clsname


class Lesson(models.Model):
    name = models.CharField(max_length=64, verbose_name='課程名稱')

    class Meta:
        db_table = 'lesson'
        verbose_name_plural = '課程表'

    def __str__(self):
        return self.name
第一種:models.py 建立多對多表
from django.shortcuts import render,HttpResponse from app01 import models def orm(request): class_obj = models.ClassName.objects.get(clsname='1812A') class_objs = models.ClassName.objects.all() lesson_obj = models.Lesson.objects.get(name='django') lesson_objs = models.Lesson.objects.all() # 1.1 添加: 正向
 class_obj.lsname.add(lesson_obj) class_obj.lsname.add(*lesson_objs) # 1.2 刪除:正向
 class_obj.lsname.remove(lesson_obj) class_obj.lsname.remove(*lesson_objs) # 2.1 添加: 反向
 lesson_obj.classname_set.add(class_obj) lesson_obj.classname_set.add(*class_objs) # 2.2 刪除:反向
 lesson_obj.classname_set.remove(class_obj) lesson_obj.classname_set.remove(*class_objs) # 3.1 查找:正向
    print(class_obj.lsname.all())                                # 查找1812A 班級中全部課程
    # 3.2 查找:反向
    print(lesson_obj.classname_set.all())                        # 查找那些班級有django課程
    return HttpResponse('orm')
第一種views.py 根據queryset對象增刪改查
from django.contrib import admin
from app01 import models

class StudentAdmin(admin.ModelAdmin):
    list_display = ('id','name','age',)
    search_fields = ('name','age',)

class ClassNameAdmin(admin.ModelAdmin):
    list_display = ('clsname',)
    search_fields = ('clsname',)

class LessonAdmin(admin.ModelAdmin):
    list_display = ('name',)
    search_fields = ('name',)

admin.site.register(models.Student, StudentAdmin)
admin.site.register(models.ClassName, ClassNameAdmin)
admin.site.register(models.Lesson, LessonAdmin)
app01/admin.py

      2. 第二種: 本身建立第三張關係表,無 m2m 字段,本身鏈表查詢

from django.db import models

#表1:主機表
class Host(models.Model):
    nid = models.AutoField(primary_key=True)
    hostname = models.CharField(max_length=32,db_index=True)

#表2:應用表
class Application(models.Model):
    name = models.CharField(max_length=32)

#表3:自定義第三張關聯表
class HostToApp(models.Model):
    hobj = models.ForeignKey(to="Host",to_field="nid")
    aobj = models.ForeignKey(to='Application',to_field='id')

# 向第三張表插入數據,創建多對多外鍵關聯
HostToApp.objects.create(hobj_id=1,aobj_id=2)
第二種: 有第三張表,無m2m字段 models.py

      3. 第三種: 本身不建立第三張關係表,有m2m字段: 根據數字id增刪改查

from django.db import models

class Host(models.Model):
    hostname = models.CharField(max_length=32,db_index=True)

class Group(models.Model):
    group_name = models.CharField(max_length=32)
    m2m = models.ManyToManyField("Host")
第三種: models.py建立多對多表
from django.shortcuts import HttpResponse
from app01 import models

def orm(request):
    # 使用間接方法對第三張表操做
    obj = models.Group.objects.get(id=1)

    # 一、添加
    obj.m2m.add(1)           # 在第三張表中增長一個條目(1,1)
    obj.m2m.add(2, 3)        # 在第三張表中增長條目(1,2)(1,3)兩條關係
    obj.m2m.add(*[1,3])        # 在第三張表中增長條目(1,2)(1,3)兩條關係

    # 二、刪除
    obj.m2m.remove(1)             # 刪除第三張表中的(1,1)條目
    obj.m2m.remove(2, 3)          # 刪除第三張表中的(1,2)(1,3)條目
    obj.m2m.remove(*[1, 2, 3])    # 刪除第三張表中的(1,1)(1,2)(1,3)條目

    # 三、清空
    obj.m2m.clear()                 # 刪除第三張表中application條目等於1的全部條目

    # 4 更新
    obj.m2m.set([1, 2,])             # 第三張表中會刪除全部條目,而後建立(1,1)(1,2)條目

    # 5 查找
    print( obj.m2m.all() )           # 等價於 models.UserInfo.objects.all()

    # 6 反向查找: 雙下劃線
    hosts = models.Group.objects.filter(m2m__id=1)         # 在Host表中id=1的主機同時屬於那些組


    # 自動建立Host表和Group表中的數據
    '''
    hostname = [{'hostname':'zhangsan'},
                {'hostname':'lisi'},
                {'hostname':'wangwu'},]
    group_name = [{'group_name':'DBA'},{'group_name':'public'},]

    for h in hostname:
        models.Host.objects.create(**h)
    for u in group_name:
        models.Group.objects.create(**u)
    '''

    return HttpResponse('orm')
第三種:views.py 根據id增刪改查

  二、多對多使用values和values_list結合雙下劃線跨表查詢

from django.shortcuts import HttpResponse
from app01 import models

def orm(request):
    # 第一種:values-----獲取的內部是字典,拿固定列數
    # 1.1 正向查找: 使用ManyToManyField字段名user_info結合雙下劃線查詢
    models.UserGroup.objects.filter(group_name='group_python').values('group_name', 'user_info__username')

    # 1.2 反向查找: 使用ManyToManyField的related_query_name='m2m',的字段
    models.UserInfo.objects.filter(username='zhangsan').values('username', 'm2m__group_name')


    # 第二種:values_list-----獲取的是元組  拿固定列數
    # 2.1 正向查找: 使用ManyToManyField字段名user_info結合雙下劃線查詢
    models.UserGroup.objects.filter(group_name='group_python').values_list('group_name', 'user_info__username')

    # 2.2 反向查找: 使用ManyToManyField的related_query_name='m2m',的字段
    lesson = models.UserInfo.objects.filter(username='zhangsan').values_list('username', 'm2m__group_name')



    # 自動建立UserInfo表和UserGroup表中的數據
    '''
    # user_info_obj = models.UserInfo.objects.get(username='lisi')
    # user_info_objs = models.UserInfo.objects.all()
    #
    # group_obj = models.UserGroup.objects.get(group_name='group_python')
    # group_objs = models.UserGroup.objects.all()
    #
    # group_obj.user_info.add(*user_info_objs)
    # user_info_obj.usergroup_set.add(*group_objs)

    user_list = [{'username':'zhangsan'},
                {'username':'lisi'},
                {'username':'wangwu'},]
    group_list = [{'group_name':'group_python'},
               {'group_name':'group_linux'},
               {'group_name':'group_mysql'},]

    for c in user_list:
        models.UserInfo.objects.create(**c)

    for l in group_list:
        models.UserGroup.objects.create(**l)
    '''

    return HttpResponse('orm')
多對多使用values和values_list結合雙下劃線跨表查詢

  三、建立m2m多對多時ManyToManyField能夠添加的參數

一、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}
五、symmetrical=None,          # 用於多對多自關聯,symmetrical用於指定內部是否建立反向操做字段
六、through=None,              # 自定義第三張表時,使用字段用於指定關係表
七、through_fields=None,       # 自定義第三張表時,使用字段用於指定關係表中那些字段作多對多關係表
八、db_constraint=True,        # 是否在數據庫中建立外鍵約束
   db_table=None,             # 默認建立第三張表時,數據庫中表的名稱
建立m2m多對多時ManyToManyField能夠添加的參數

1.5 一大波Model操做     返回頂部

from django.shortcuts import HttpResponse
from app01 import models

def orm(request):
    # 1 建立
    # 建立數據方法一
    models.UserInfo.objects.create(username='root', password='123')
    # 建立數據方法二
    obj = models.UserInfo(username='alex', password='123')
    obj.save()
    # 建立數據庫方法三(傳入字典必須在字典前加兩個星號)
    dic = {'username': 'eric', 'password': '666'}
    models.UserInfo.objects.create(**dic)

    # 2 查
    result = models.UserInfo.objects.all()  # 查找全部條目
    result = models.UserInfo.objects.filter(username='alex', password='123')
    for row in result:
        print(row.id, row.username, row.password)

    # 3 刪除
    models.UserInfo.objects.all().delete()  # 刪除全部
    models.UserInfo.objects.filter(username='alex').delete()  # 刪除指定

    # 4 更新
    models.UserInfo.objects.all().update(password='12345')
    models.UserInfo.objects.filter(id=4).update(password='15')

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

    # 6 執行原生SQL
    # 6.1 執行原生SQL
    models.UserInfo.objects.raw('select * from userinfo')

    # 6.2 若是SQL是其餘表時,必須將名字設置爲當前UserInfo對象的主鍵列名
    models.UserInfo.objects.raw('select id as nid from 其餘表')

    # 6.3 指定數據庫
    models.UserInfo.objects.raw('select * from userinfo', using="default")

    return HttpResponse('orm')
基本操做
1、大於,小於
        # 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
3、isnull
        # Entry.objects.filter(pub_date__isnull=True)         #雙下劃線isnull,查找pub_date是null的數據
四、contains                                                    #就是原生sql的like操做:模糊匹配
        # models.Tb1.objects.filter(name__contains="ven")
        # models.Tb1.objects.filter(name__icontains="ven")    # icontains大小寫不敏感
        # models.Tb1.objects.exclude(name__icontains="ven")
5、range
       # models.Tb1.objects.filter(id__range=[1, 2])          # 範圍bettwen and
6、order by
        # models.Tb1.objects.filter(name='seven').order_by('id')      # asc     沒有減號升續排列
        # models.Tb1.objects.filter(name='seven').order_by('-id')     # desc      有減號升續排列
7、group by
        # from django.db.models import Count, Min, Max, Sum
        # models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num'))        #根據id列進行分組
        # 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]
9、regex正則匹配,iregex 不區分大小寫
        # Entry.objects.get(title__regex=r'^(An?|The) +')
        # Entry.objects.get(title__iregex=r'^(an?|the) +')

        
10、date
        # Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))          #__data表示日期查找,2005-01-01
        # Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))
11、year
        # Entry.objects.filter(pub_date__year=2005)                               #__year根據年查找
        # Entry.objects.filter(pub_date__year__gte=2005)
12、month
        # Entry.objects.filter(pub_date__month=12)
        # Entry.objects.filter(pub_date__month__gte=6)
13、day
        # Entry.objects.filter(pub_date__day=3)
        # Entry.objects.filter(pub_date__day__gte=3)
14、week_day
        # Entry.objects.filter(pub_date__week_day=2)
        # Entry.objects.filter(pub_date__week_day__gte=2)
15、hour
        # Event.objects.filter(timestamp__hour=23)
        # Event.objects.filter(time__hour=5)
        # Event.objects.filter(timestamp__hour__gte=12)
16、minute
        # Event.objects.filter(timestamp__minute=29)
        # Event.objects.filter(time__minute=46)
        # Event.objects.filter(timestamp__minute__gte=29)
17、second
        # Event.objects.filter(timestamp__second=31)
        # Event.objects.filter(time__second=2)
        # Event.objects.filter(timestamp__second__gte=31)
進階操做:牛掰掰的雙下劃線
from django.utils import timezone
from report.models import *

now = timezone.now()
# start_time = now - timezone.timedelta(days=7)
start_time = now - timezone.timedelta(hours=240)  # 查詢10天前的數據
end_time = now

qs = AllClarm.objects.filter(start_tm__range=(start_time, end_time))
根據天/小時進行過濾
#! /usr/bin/env python
# -*- coding: utf-8 -*-
from django.db import models
from django.shortcuts import render, get_object_or_404

class SLAGroup(models.Model):
    name = models.CharField(max_length=100, verbose_name='組名')
    weight = models.FloatField(verbose_name='權重')
    description = models.CharField(max_length=255, verbose_name='描述', null=True, blank=True)


group = get_object_or_404(SLAGroup, id=1)  # 查詢id=1的數據,不然就顯示404頁面
SLAGroup.objects.get_or_create(name='hadoop',weight='15')  # 獲取或建立
get_object_or_404獲取或返回404頁面

1.6 Model性能相關操做:select_related、prefetch_related     返回頂部

   一、普通查詢的缺點

      1. 例:如今有兩張表user,和group兩張表,在user表中使用m做爲ForeignKey與group表進行一對多關聯

      2. 若是經過user表中的實例查找對應的group表中的數據,就必須重複發sql請求

      3. prefetch_related()和select_related()的設計目,都是爲了減小SQL查詢的數量,可是實現的方式不同 

   二、select_related做用

      1. select_related主要針一對一和多對一關係進行優化。

      2. select_related使用SQL的JOIN語句進行優化,經過減小SQL查詢的次數來進行優化、提升性能。

  三、prefetch_related()做用

      1. prefetch_related()主要對於多對多字段和一對多字段進行優化

      2. 進行兩次sql查詢,將查詢結果拼接成一張表放到內存中,再查詢就不用發sql請求

  四、select_related與prefetch_related 使用原則

      1. prefetch_related()和select_related()的設計目的很類似,都是爲了減小SQL查詢的數量,可是實現的方式不同

      2. 由於select_related()老是在單次SQL查詢中解決問題,而prefetch_related()會對每一個相關表進行SQL查詢,所以select_related()的效率高

      3. 因此儘量的用select_related()解決問題。只有在select_related()不能解決問題的時候再去想prefetch_related()。

  五、select_related舉例說明

      做用:使用SQL的JOIN語句進行優化,經過減小SQL查詢的次數來進行優化

def index(request):
    #1 這種方法低效
    users = models.User.objects.all()    #拿到的僅僅是user表中內容
    for row in users:
        print(row.user,row.ut_id)        #這裏打印user表中的內容沒必要再次sql請求
        print(row.ut.name)               #第一次查表,沒有拿到關聯表ut字段中的內容
                                         #因此每次循環都會再次發sql請求,拿到ut.name的值,低效

    #2 使用這種方法也僅須要一次數據庫查詢(拿到的是字典),可是若是查找的不在那些字段中直接報錯
    users = models.User.objects.all().values('user','pwd','ut__name')

    #3 select_related()能夠一次sql查詢拿到全部關聯表信息
    users = models.User.objects.all().select_related()
    
    # 這裏還支持指定只拿到那個關聯表的全部信息,好比:有多個外鍵關聯,只拿到與ut外鍵關聯的表
    users = models.User.objects.all().select_related('ut')


# select_related() 接受depth參數,depth參數能夠肯定select_related的深度。
# Django會遞歸遍歷指定深度內的全部的OneToOneField和ForeignKey。以本例說明:
# zhangs = Person.objects.select_related(depth = d)
# d=1  至關於 select_related(‘hometown’,'living’)
# d=2  至關於 select_related(‘hometown__province’,'living__province’)
select_related舉例說明

  六、prefetch_related舉例說明

      做用:進行兩次sql查詢,將查詢結果拼接成一張表

def index(request):
    users = models.User.objects.filter(id__gt=30).prefetch_related('ut')
                       #ut和tu是user表的兩個foreign key,分別關聯不一樣的表

    users = models.User.objects.filter(id__gt=30).prefetch_related('ut','tu')
    #1 先執行第一次sql查詢:select * from users where id > 30;
    #2 好比:第一次查詢結果,獲取上一步驟中全部ut_id=[1,2]
    #3 而後執行第二次sql查詢:select * from user_type where id in [1,2]
    #4 這樣就僅執行了兩次sql查詢將兩個表的數據拼到一塊兒,放到內存中,再查詢就不用發sql請求
    for row in users:
        print(row.user,row.ut_id)       #這裏打印user表中的內容沒必要再次sql請求
prefetch_related舉例說明

1.7 F()和Q()查詢語句     返回頂部

from django.db import models
class Student(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    def __str__(self):
        return self.name
models.py建立表

  一、F() ---- 專門取對象中某列值的操做

      做用:F()容許Django在未實際連接數據的狀況下具備對數據庫字段的值的引用

from django.shortcuts import HttpResponse
from app01 import models
from django.db.models import F,Q

def orm(request):
    # 每訪問一次數據庫中zhangsan的年紀就會自動增長1

    models.Student.objects.filter(name='zhangsan').update(age=F("age") + 1)



    # 自動生成Student表中數據
    '''
    stu_list = [{'name':'zhangsan','age':11},
                 {'name': 'lisi', 'age': 22},
                 {'name': 'wangwu', 'age': 33},]
    for u in stu_list:
        models.Student.objects.create(**u)
    '''
    return HttpResponse('orm')
F()將指定字段自動加1

   2.一、Q() ---- 複雜查詢(用法1

      一、Q對象(django.db.models.Q)能夠對關鍵字參數進行封裝,從而更好地應用多個查詢

      二、能夠組合使用 &(and),|(or),~(not)操做符,當一個操做符用於兩個Q的對象,它產生一個新的Q對象

      三、如: Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')

from django.shortcuts import HttpResponse
from app01 import models
from django.db.models import F,Q

def orm(request):
    # 查找學生表中年級大於1小於30姓zhang的全部學生
    stus = models.Student.objects.filter(
        Q(age__gt=1) & Q(age__lt=30),
        Q(name__startswith='zhang')
    )
    print('stu',stus)   #運行結果:[<Student: zhangsan>]


    # 自動生成Student表中數據
    '''
    stu_list = [{'name':'zhangsan','age':11},
                 {'name': 'lisi', 'age': 22},
                 {'name': 'wangwu', 'age': 33},]
    for u in stu_list:
        models.Student.objects.create(**u)
    '''
    return HttpResponse('orm')
複雜查詢

  2.二、Q() ---- 動態添加多個and和or查詢條件(用法2

def table_search(request,admin_class,object_list):
   search_key = request.GET.get('_q','')
   q_obj = Q()
   q_obj.connector = 'OR'
   for column in admin_class.search_fields:
      q_obj.children.append(('%s__contains'%column,search_key))
   res = object_list.filter(q_obj)
   return res
crm項目中動態添加or查詢條件
# or動態添加多個查詢條件
>>> from crm import models
>>> from django.db.models import Q
>>> con = Q()                                               #1. 實例化一個Q()查詢類
>>> con.connector = "OR"                                    #2. 指定使用‘OR’條件
>>> con.children.append(('qq__contains','123'))             #3. qq字段中包含‘123’
>>> con.children.append(('name__contains','name0'))         #4. name字段中包含‘naem0’
>>> con
<Q: (OR: ('qq__contains', '123'), ('name__contains', 'name0'))>   
                                                            #5. 查找name字段中包含‘naem0’或qq字段包含‘123’的全部條目
>>> models.Customer.objects.values('qq','name').filter(con)    
or動態添加多個查詢條件
# and和or結合查詢
#1. 導入模塊
>>> from crm import models
>>> from django.db.models import Q

#2. q1:查詢id=1或者id=2的全部條目  (or條件)
>>> q1 = Q()
>>> q1.connector = 'OR'
>>> q1.children.append(('id',1))
>>> q1.children.append(('id',2))

#3. q2:查詢id=1的全部條目  (or條件)
>>> q2 = Q()
>>> q2.connector = 'OR'
>>> q2.children.append(('id',1))

#4. con:結合q1和q2條件結果是查詢id=1的全部條目     (結合q1,q2的and條件)
>>> con = Q()
>>> con.add(q1,'AND')
   <Q: (OR: ('id', 1), ('id', 2))>
>>> con.add(q2,'AND')
   <Q: (AND: (OR: ('id', 1), ('id', 2)), ('id', 1))>
>>> models.Customer.objects.values('qq','name').filter(con)
   <QuerySet [{'qq': '123456765432', 'name': 'haha'}]>
and和or結合查詢

1.8 aggregate和annotate聚合函數 : 求平均值、最大值、最小值等     返回頂部

  一、aggregate聚合函數

      做用:從數據庫中取出一個彙總的集合

from django.db.models import Count,Avg,Max,Sum
def orm(request):

    stus = models.Student.objects.aggregate(
        stu_num=Count('age'),     #計算學生表中有多少條age條目
        stu_avg=Avg('age'),       #計算學生的平均年紀
        stu_max=Max('age'),       #找到年紀最大的學生
        stu_sum=Sum('age'))       #將表中的全部年紀相加

    print('stu',stus)
    return HttpResponse('ok')
#運行結果:{'stu_sum': 69, 'stu_max': 24, 'stu_avg': 23.0, 'stu_num': 3}
aggregate求最大值、最小值、平局值等

   二、annotate實現聚合group by查詢

      做用:對查詢結果進行分組,好比分組求出各年齡段的人數

      注:    annotate後面加filter過濾至關於原生sql語句中的having

from django.db.models import Count, Avg, Max, Min, Sum
def orm(request):
    #1 按年紀分組查找學生表中各個年齡段學生人數:(22歲兩人,24歲一人)
    # 查詢結果:[{'stu_num': 2, 'age': 22}, {'stu_num': 1, 'age': 24}]

    stus1 = models.Student.objects.values('age').annotate(stu_num=Count('age'))

    #2 按年紀分組查找學生表中各個年齡段學生人數,並過濾出年紀大於22的:
    # 查詢結果:[{'stu_num': 1, 'age': 24}] (年級大於22歲的僅一人,年級爲24歲)

    stus2 = models.Student.objects.values('age').annotate(stu_num=Count('age')).filter(age__gt=22)

    #3 先按年紀分組,而後查詢出各個年齡段學生的平均成績
    # 查詢結果:[{'stu_Avg': 86.5, 'age': 22}, {'stu_Avg': 99.0, 'age': 24}]
    # 22歲平均成績:86.5      24歲平均成績:99

    stus3 = models.Student.objects.values('age').annotate(stu_Avg=Avg('grade'))

    return HttpResponse('ok')
annotate實現聚合group by查詢

  三、aggregateannotate區別

      1. Aggregate做用是從數據庫取出一個彙總的數據(好比,數量,最大,最小,平均等)

      2.   而annotate是先按照設定的條件對數據進行分組,而後根據不一樣組分別對數據進行彙總

1.9 Trunc函數處理日期格式數據     返回頂部

  一、Trunc函數做用 及 參數說明

      1、做用:Trunk能夠將時間處理成,只有年,或月或日等格式,那些不關心的部分都會變成0

      2Trunk函數能夠傳入下面四個參數:

          a、expression :傳入數據庫表中對應要處理的時間那個字段名字

          b、kind :是時間格式的一部分,能夠是 year,month,day,hour,minute,second  

                        ,kind指定最後處理後的時間精確到哪個部分

          c、output_field :只能是這三個格式:DateTimeField(), TimeField(), or DateField()

                                  最後返回的是datetime,date,或則time 就取決於 output_field 字段是如何指定的

          d、tzinfosubclass:一般由pytz提供,能夠傳遞給截斷值指定一個特定的時區。

      3若是給出的時間是 datetime 2015-06-15 14:30:50.000321+00:00, 使用下面六種 kinds 最後返回結果以下

          「year」: 2015-01-01 00:00:00+00:00

          「month」: 2015-06-01 00:00:00+00:00

          「day」: 2015-06-15 00:00:00+00:00

          「hour」: 2015-06-15 14:00:00+00:00

          「minute」: 2015-06-15 14:30:00+00:00

          「second」: 2015-06-15 14:30:50+00:00

  二、解決時差配置問題的報錯 

      1. 錯誤:Are time zone definitions for your database and pytz installed?

      2. 解決方法:安裝pytz模塊,在Django settings中配置數據庫的時區:  pip3 install pytz

# 註釋的是數據庫默認的配置
# LANGUAGE_CODE = 'en-us'
# TIME_ZONE = 'UTC'
# USE_TZ = True

USE_TZ = False
LANGUAGE_CODE = 'zh-Hans'
TIME_ZONE = 'Asia/Chongqing'
在settings中配置數據庫時區

   三、Trunk函數基本使用

from django.db import models

class Experiment(models.Model):
    start_datetime = models.DateTimeField()
models.py中建立數據庫表
from django.shortcuts import HttpResponse
from .models import *

from datetime import datetime
from django.db.models import Count, DateTimeField
from django.db.models.functions import Trunc

def orm(request):
    #1 首先向Experiment表中插入三條數據
    Experiment.objects.create(start_datetime=datetime(2015, 6, 15, 14, 30, 50, 321))
    Experiment.objects.create(start_datetime=datetime(2015, 6, 15, 14, 40, 2, 123))
    Experiment.objects.create(start_datetime=datetime(2015, 12, 25, 10, 5, 27, 999))

    #2 使用Trunk過濾出start_datetime字段,僅保存到日,後面的時分秒所有變成0
    #3 annotate(experiments=Count('id'))能夠根據天進行分組

    experiments_per_day = Experiment.objects.annotate(
         start_day=Trunc('start_datetime', 'day', output_field=DateTimeField())
         ).values('start_day').annotate(experiments=Count('id'))

    for exp in experiments_per_day:
       print(exp['start_day'], exp['experiments'])
    return HttpResponse('orm')
# 運行結果:
# 2015-06-15 00:00:00+00:00  2
# 2015-12-25 00:00:00+00:00  1
# 從運行結果中能夠看出,2015-06-15日有兩條記錄,2015-12-25日有1條記錄
views.py使用

  四、Trunk函數應用:查詢當天簽到同窗的id

def attendance(request):
    """簽到頁面"""
    current_datetime = datetime.now()
    year = current_datetime.year
    month = current_datetime.month
    day = current_datetime.day
    if request.method == 'GET':
        if course_id:
            # 獲取當天已簽到的記錄
            attended_students = models.Attendance.objects.annotate(
                attend_day=functions.Trunc('attend_time','day',output_field=DateTimeField(), )
            ).filter(attend_day=datetime(year, month, day), course_id=course_id).values_list('student_id', flat=True)

            #Trunc函數的做用是將'attend_time'中的時間過濾成「day」: 2015-06-15 00:00:00+00:00 這種格式

            tt = datetime(2016, 3, 12)      #運行結果:2016-03-12 00:00:00

# 運行結果:  <QuerySet [1, 2]>    #這裏的1,2 是數字表示當天只有id=1,和2的學生簽到


# 注:使用這個查詢語法和上面的查詢結果徹底同樣
attended_students = models.Attendance.objects\
    .filter(attend_time__date=datetime(year, month, day),course_id=course_id)\
    .values_list('student_id', flat=True)
trunk函數應用

1.10 Django其餘查詢語句     返回頂部

  一、extra構造額外的查詢條件或者映射,如:子查詢

    1. extra做用

        一、extra 中可實現別名,條件,排序等

        二、後面兩個用 filter, exclude 通常都能實現,排序用 order_by 也能實現

    2. extra條件查詢

def extra(self, select=None, where=None, params=None,tables=None, order_by=None, select_params=None):
    #1 select參數操做
    Entry.objects.extra(select=
                        {'new_id': "select col from sometable where othercol = %s"},
                        select_params=(1,))
    Entry.objects.extra(select={'new_id': "func(id)"})                         #也能夠定義函數處理
    # %s就會替換成1了

    Entry.objects.extra(select={'new_id': "select id from tb where id > %s"},
                        select_params=(1,), order_by=['-nid'])
    #2 where參數操做
    Entry.objects.extra(where=['headline=%s'], params=['Lennon'])             # 相似filter過濾
    Entry.objects.extra(where=['headline=%s','nid>1'], params=['Lennon'])    # and操做
    Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])         #or操做
    Entry.objects.extra(where=['func(ctime)=1 or nid=1'])                    #在這裏也能夠傳入MySQL的函數
extra條件查詢

    3. extra實現別名

from django.db.models import Count, Avg, Max, Min, Sum
def orm(request):
    #一、extra 中可實現別名
    tags = models.Student.objects.filter(name='zhangsan')\
        .extra(select={'tag_name': 'name'}).first()
    print('name:',tags.name)               # name: zhangsan
    print('tag_name:',tags.tag_name)     # tag_name: zhangsan
    return HttpResponse('ok')
extra實現別名
相關文章
相關標籤/搜索