python_day18_Django-2(ORM)

python 對象查找 接上章-python_day17_Django-1

3、字段及字段參數

3.1、字段屬性

3.1.1、常用的

AutoField: int自增列,必須填入參數 primary_key=True。當model中如果沒有自增列,則自動會創建一個列名爲id的列。
IntegerField: 一個整數類型,範圍在 -2147483648 to 2147483647。
CharField: 字符類型,必須提供max_length參數, max_length表示字符長度。

DateField: 日期字段,日期格式  YYYY-MM-DD,相當於Python中的datetime.date()實例。
DateTimeField: 日期時間字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相當於Python中的datetime.datetime()實例。
ForeignKey: 外鍵
ManyToManyField: 多表關連

3.1.2、不常用的

BooleanField: 布爾類型
IPAddressField(Field): 字符串類型,Django Admin以及ModelForm中提供驗證 IPV4 機制
URLField(CharField): 字符串類型,Django Admin以及ModelForm中提供驗證 URL
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   上傳圖片的寬度保存的數據庫字段名(字符串)

3.1.3、字段參數

DecimalField:    models.DecimalField(max_digits=5,decimal_places=2, default=99.99)
    max_digits: 最大長度
    decimal_places: 小數點的位數
null: 用於表示某個字段可以爲空。
unique:  如果設置爲unique=True 則該字段在此表中必須是唯一的 。
db_index: 如果db_index=True 則代表着爲此字段設置索引。
default: 爲該字段設置默認值。

DateField和DateTimeField 參數
auto_now_add: 配置auto_now_add=True,創建數據記錄的時候會把當前時間添加到數據庫。
auto_now: 配置上auto_now=True,每次更新數據記錄的時候會更新該字段。

3.2、查詢

1、配置數據庫   項目下的settings.py
        DATABASES = {
                'default': {
                        'ENGINE': 'django.db.backends.mysql',
                        'NAME': "數據庫名",
                        "USER": "帳號",
                        'PASSWORD':  "密碼",
                        "HOST": "地址",
                        "POST": 端口,
                }
        }

2、應用下的__init__.py文件 初始化db
import pymysql
pymysql.install_as_MySQLdb()

3、應用下的moduls.py    初始化表結構
類 = 表
字段 = 表結構
class Book(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=30, null=False)
    data = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return "id: {}  name: {}".format(self.id, self.name)

# 學生表
class Student(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=25, null=False)
    borrow = models.ForeignKey(to=Book, on_delete=models.CASCADE)

    def __str__(self):
        return "id: {}  name: {}".format(self.id, self.name)

4、根目錄下創建一個py文件,用於直接查詢數據庫
import os

if __name__ == "__main__":
    # 加載django項目配置信息
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "select_test.settings")

    # 導入django,啓動django    
        # 注意: 一定要先啓動django項目,然後在運行這個py文件
    import django
    django.setup()

        # 導入數據庫models
    from app01 import models

5、查詢
    print("all".center(50,"*"))
    alls = models.Student.objects.all()
    print(alls)
    # 如果沒有增加類 str 查找出來的是對象 字典形式
    # <QuerySet [<Student: Student object (1)>, <Student: Student object (2)>, <Student: Student object (4)>]>
    # for a in alls:       可以使用for 查看每個字典的內容
    #     print(a.name)

    print("filter".center(50,"*"))
    filters = models.Student.objects.filter(name="小熊")
    print(filters)   # <QuerySet [<Student: id: 1  name: 小熊>]>
    filters2 = models.Student.objects.filter(name="小熊333")
    print(filters2)  # <QuerySet []>
    # 如果查找的內容存在,那就返回列表,如果不存在那就直接爲空,不報錯

    print("get".center(50,"*"))
    gets = models.Student.objects.get(name="小熊")
    print(gets)   # id: 1  name: 小熊
    # gets2 = models.Student.objects.get(name="小熊33")
    # print(gets2)  # 報錯 app01.models.DoesNotExist: Student matching query does not exist.
    # 如果查找的內容存在,直接返回內容,不存在就返回錯誤

    print("exclude".center(50, "*"))
    excludes = models.Student.objects.exclude(name="小熊")
    print(excludes)   # 如果存在這個值,取相反的結果
    # <QuerySet [<Student: id: 2  name: 小熊2>, <Student: id: 4  name: 小1>]>

    excludes2 = models.Student.objects.exclude(name="小熊33")
    print(excludes2)  # 當結果不存在就全部返回
    # <QuerySet [<Student: id: 1  name: 小熊>, <Student: id: 2  name: 小熊2>, <Student: id: 4  name: 小1>]>

    print("values".center(50, "*"))
    values = models.Student.objects.values()
    print(values) # 得到的是一個字典,跟all一樣
    # <QuerySet [{'id': 1, 'name': '小熊', 'borrow_id': 1}, {'id': 2, 'name': '小熊2', 'borrow_id': 1}, {'id': 4, 'name': '小1', 'borrow_id': 2}]>

    print("values_list".center(50, "*"))
    values_list = models.Student.objects.values_list()
    print(values_list)   # 得到的是元組,直接返回結果
    # <QuerySet [(1, '小熊', 1), (2, '小熊2', 1), (4, '小1', 2)]>

    print("order".center(50, "*"))
    # 根據時間做出排序
    order = models.Book.objects.all().order_by("date")
    print(order)
    # 對查詢的結果進行排序
    # <QuerySet [<Book: id: 1  name: 小熊的python自動化>, <Book: id: 2  name: 自動化python>, <Book: id: 3  name: flask>]>

    print("reverse".center(50, "*"))
    # 必須先做出有序的排序,然後才能用reverse進行倒序查詢
    order2 = models.Book.objects.all().order_by("date").reverse()
    print(order2)
    # <QuerySet [<Book: id: 3  name: flask>, <Book: id: 2  name: 自動化python>, <Book: id: 1  name: 小熊的python自動化>]>

    print("count".center(50, "*"))
    count = models.Book.objects.count()
    print(count)   # 統計表總共有多少行 3

    print("first".center(50, "*"))
    first = models.Book.objects.first()
    print(first)    # 打印出第一行,直接顯示結果 id: 1  name: 小熊的python自動化

    print("last".center(50, "*"))
    last = models.Book.objects.last()
    print(last)    # 打印出最後一行,直接顯示結果 id: 3  name: flask

    print("exists".center(50, "*"))
    exists = models.Book.objects.exists()
    print(exists)    # 結果爲bule值, True或者False

返回QuerySet對象的方法有
    all()
    filter()
    exclude()
    order_by()
    reverse()
    distinct()

特殊的QuerySet
    values()       返回一個可迭代的字典序列
    values_list() 返回一個可迭代的元祖序列

返回具體對象的
    get()
    first()
    last()

返回布爾值的方法有:
    exists()

返回數字的方法有
    count()

6、下劃線的使用
    # gte : 大於等於
    # lte : 小於等於

    #  過濾掉大於等於1  小於3的值
    lg_mod = models.Book.objects.filter(id__gte=1,id__lt=3)
    print(lg_mod)  # <QuerySet [<Book: id: 1  name: 小熊的python自動化>, <Book: id: 2  name: 自動化python>]>

    # 包含這個值的內容,
    ld_mod = models.Book.objects.filter(id__in=[1,3])
    print(ld_mod)    # <QuerySet [<Book: id: 1  name: 小熊的python自動化>, <Book: id: 3  name: flask>]>

    # 反向查找
    ld_exclude = models.Book.objects.exclude(id__in=[1,3])
    print(ld_exclude)    # <QuerySet [<Book: id: 2  name: 自動化python>]>

    # 模糊匹配 ,查找包含py的內容    加上 name__icontaion 不區分大小寫
    ld_contains = models.Book.objects.filter(name__contains="py")
    print(ld_contains)  # <QuerySet [<Book: id: 1  name: 小熊的python自動化>, <Book: id: 2  name: 自動化python>]>

    # 查找這個範圍內的值
    ld_range = models.Book.objects.filter(id__range=[2,3])
    print(ld_range)
    # <QuerySet [<Book: id: 2  name: 自動化python>, <Book: id: 3  name: flask>]>

3.3、正反向查詢

1、數據庫 modules.py
# 出版社
class Press(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=50)

class Books(models.Model):
    '''
        id 書編號
        name: 書名
        publish_time: 出版時間
        press: 出版社
    '''
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=25)
    publish_time = models.DateTimeField(auto_now_add=True)
    press = models.ForeignKey(to=Press, on_delete=models.CASCADE)

    def __str__(self):
        return "id: {} --  name: {} --  publish_time: {} -- press: {}".format(self.id,
                                                                   self.name,self.publish_time, self.press)

class Auther(models.Model):
    '''
        boos  作者關連的書
    '''
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=25)
    books = models.ManyToManyField(to=Books)

2、sql語法:
INSERT INTO `test`.`app01_books` (`id`, `name`, `publish_time`, `press_id`) VALUES ('1', 'linux集羣自動化', '2018-07-25 09:31:22.000000', '1');
INSERT INTO `test`.`app01_books` (`id`, `name`, `publish_time`, `press_id`) VALUES ('2', 'linux shell編程', '2018-07-25 09:31:47.000000', '2');
INSERT INTO `test`.`app01_books` (`id`, `name`, `publish_time`, `press_id`) VALUES ('3', 'python django開發編程', '2018-07-25 10:08:23.000000', '1');

INSERT INTO `test`.`app01_press` (`id`, `name`) VALUES ('1', '北京第一齣版社');
INSERT INTO `test`.`app01_press` (`id`, `name`) VALUES ('2', '北京第二齣版社');

INSERT INTO `test`.`app01_auther` (`id`, `name`) VALUES ('1', 'xiong');
INSERT INTO `test`.`app01_auther` (`id`, `name`) VALUES ('2', 'yu');

INSERT INTO `test`.`app01_auther_books` (`id`, `auther_id`, `books_id`) VALUES ('1', '1', '1');
INSERT INTO `test`.`app01_auther_books` (`id`, `auther_id`, `books_id`) VALUES ('2', '1', '2');
INSERT INTO `test`.`app01_auther_books` (`id`, `auther_id`, `books_id`) VALUES ('3', '2', '1');

數據表關係 大致
python_day18_Django-2(ORM)

3、創建一個py文件,用於直接查詢數據庫
import os

if __name__ == "__main__":
    # 加載django項目配置信息
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "select_test.settings")

    # 導入django
    import django
    django.setup()   # 啓動django項目

    from app01 import models   導入模塊

    # 正向查找    書查找出版社    由對象直接查找
    books = models.Books.objects.first()
    # 必須是要 queryset對象,必須會報這個錯:AttributeError: 'QuerySet' object has no attribute 'name'
    print(books.press)  # 得到關聯的出版社對象
    print(books.press.name) # 得到這本書的出版社

    # 正向查找, 字段查找
    # 注意  這裏是關聯字段義外鍵的名稱,而不是表的名稱, 雙下劃線就表示跨了一張表
    ret = models.Books.objects.values_list("press__name")
    print(ret)
    # < QuerySet[('北京第一齣版社',), ('北京第二齣版社',)] >

    print("反向對象查找".center(50,"*"))
    publisher_obj = models.Press.objects.first()
    books2 = publisher_obj.books_set.all()
    print(books2)   # 查找第一個出版社對應書籍,對應多少本書,都會打印出來
    # <QuerySet [<Books: id: 1 --  name: linux集羣自動化 --  publish_time: 2018-07-25 09:31:22+00:00 -- press: Press object (1)>,
    # <Books: id: 3 --  name: python django開發編程 --  publish_time: 2018-07-25 10:08:23+00:00 -- press: Press object (1)>]>

    # 反向對象查找,  出版社所有的列表對應的書藉, queryset對象
    print(models.Press.objects.values_list("books__name"))
    # <QuerySet [('linux集羣自動化',), ('linux shell編程',), ('python django開發編程',)]>

        將modules添加這個屬性:related_name, 在反向處理時就不需要加上 **_set了 

        class Books(models.Model):
    '''
        id 書編號
        name: 書名
        publish_time: 出版時間
        press: 出版社
    '''
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=25)
    publish_time = models.DateTimeField(auto_now_add=True)
    press = models.ForeignKey(to=Press, on_delete=models.CASCADE, related_name="book")

        # 添加 related_name 反向對象操作
        publisher_obj = models.Press.objects.first()
        books3 = publisher_obj.book.all()
        print("books3: {}".format(books3))

        # 反向字段操作
        print(models.Press.objects.values_list("book__name"))
        # <QuerySet [('linux集羣自動化',), ('linux shell編程',), ('python django開發編程',)]>    可迭代的對象

    # 例
    ret = models.Press.objects.filter(id=1).values_list("book__name")
    print(ret)   # 只獲取出版社爲 第一齣版社的書
    # <QuerySet [('linux集羣自動化',), ('python django開發編程',)]>

    對應sql語句爲:SELECT `app01_books`.`name` FROM `app01_press` LEFT OUTER JOIN `app01_books` ON (`app01_press`.`id` = `app01_books`.`press_id`) WHERE `app01_press`.`id` = 1 LIMIT 21; args=(1,)

3.4、多表關連 ManyToManyField

"關聯管理器"是在一對多或者多對多的關聯上下文中使用的管理器。
它存在於下面兩種情況:
  外鍵關係的反向查詢
  多對多關聯關係

1、create 方法
auther_obj = models.Auther.objects.first()
    print(auther_obj)
    # 給第一個作者  創建一本書並關連  注意:publish_time 測試過程中我刪了
        # 注意 press不是model.py創建的字段,而是數據庫中的字段,
    auther_obj.books.create(name="flask web開發",press_id=2)
    # auther.books.create(name="flask web開發",publish_time=datetime.datetime.now(),press_id=1)

python_day18_Django-2(ORM)

查詢: print(models.Auther.objects.filter(name="xiong").values_list("books__name"))
結果: <QuerySet [('linux集羣自動化',), ('linux shell編程',), ('flask web開發',)]>
2、add 方法
    # 獲取返回具體對象的值
    # 在yu關聯的書裏面,加一本id爲1的書
    auther_obj = models.Auther.objects.get(id=2)
    book_obj = models.Books.objects.get(id=1)
    auther_obj.books.add(book_obj)

    print(models.Auther.objects.filter(id=2).values_list("books__name"))
    # <QuerySet [('linux集羣自動化',)]>

    # 查找編號爲2的作者,書籍編號大於2的 然後展開寫入到作者的第三張表中
    auther_obj = models.Auther.objects.get(id=2)
    book_objs = models.Books.objects.filter(id__gt=2)
    auther_obj.books.add(*book_objs)
    print(models.Auther.objects.filter(id=2).values_list("books__name"))
    # < QuerySet[('linux集羣自動化',), ('python django開發編程',), ('flask web開發',)] >

3、remove方法
        # 將作者爲2的 linux集羣這本書刪除
    auther_obj = models.Auther.objects.get(id=2)
    book_obj = models.Books.objects.get(name="linux集羣自動化")
    auther_obj.books.remove(book_obj)

4、clear 方法
        # 將作者爲2的 所有的書全部刪除
    book_clear = models.Auther.objects.get(id=2)
    book_clear.books.clear()

3.5、聚合查詢和分組查詢

aggregate()是QuerySet 的一個終止子句,意思是說,它返回一個包含一些鍵值對的字典。
鍵的名稱是聚合值的標識符,值是計算出來的聚合值。鍵的名稱是按照字段和聚合函數的名稱自動生成出來的。

聚合

1、數據庫表 Books 字段 增加, 然後進 Book表修改下數據
        price = models.DecimalField(max_digits=5,decimal_places=2, default=99.99)

2、查詢
    from django.db.models import Avg, Sum, Max, Min, Count

    avg_ret = models.Books.objects.all().aggregate(avg_price = Avg("price"))
    print(avg_ret)  # 平均值

    ret = models.Books.objects.all().aggregate(sum = Sum("price"),max = Max("price"), min = Min("price"), count = Count("price") )
    print(ret)  # {'sum': Decimal('96.97'), 'max': Decimal('44.99'), 'min': Decimal('6.99'), 'count': 4}

分組

1、統計每一本書分別有多少個作者
    ret = models.Books.objects.all().annotate(aaa = Count("auther"))
        # ret 打印結果爲: <QuerySet [<Books: id: 1 --  name: linux集羣自動化 --  -- press: Press object (1)>, <Books: id: 2 --  name: linux shell編程 --  -- press: Press object (2)>, <Books: id: 3 --  name: python django開發編程 --  -- press: Press object (1)>, <Books: id: 4 --  name: flask web開發 --  -- press: Press object (2)>]>

    for book in ret:
        print(book.id,book.aaa)
    # 作者id號,以及對應有多少書
        1 2
        2 2

2、顯示每個出版社最便宜的書
    min_publish = models.Press.objects.annotate(mins = Min("book__price"))
    for min_pub in min_publish:
        print(min_pub.mins)
        結果: 6.99  \n 33.00
方法二:     xx= models.Books.objects.values("press__name").annotate(mins = Min("price"))   \n  print(xx)

3、取出作者大寫兩本的書
    book_obj = models.Books.objects.annotate(auther_num=Count("auther")).filter(auther_num__gt=1)
    for books in book_obj:
        print(books.name,books.auther_num)
        結果:linux shell編程 2

4、根據圖書進行排序
    ret = models.Books.objects.annotate(author_num=Count("auther")).order_by("author_num")
    print(ret)
# <QuerySet [<Books: id: 3 --  name: python django開發編程 -- >, <Books: id: 4 --  name: flask web開發 -- >, <Books: id: 2 --  name: linux shell編程 -- >, <Books: id: 1 --  name: linux集羣自動化 -- >]>

5、  查詢出每個作者書本的總價
   ret = models.Auther.objects.annotate(sum_price=Sum("books__price")).values("name","sum_price")
    print(ret)

3.6、F查詢和Q查詢

F查詢

from django.db.models import F,Q
    # 查詢倉庫數大於銷售數的書藉
    print(models.Books.objects.filter(depot__gt=F("sale")).values_list())
    # <QuerySet [(1, 'linux集羣自動化', 80, 20, Decimal('6.99'), 1), (2, 'linux shell編程', 60, 40, Decimal('44.99'), 2)]>

    # 單個用戶的值乘以三
    models.Books.objects.filter(id=1).update(sale=F("sale")*3)

    # 更新,將所有的書都乘以三,必須是queryset對象的才能操作
    models.Books.objects.update(sale=F("sale")*3)

   # 在書藉後面加上第一版
         from django.db.models.functions import Concat
    from django.db.models import Value

    models.Books.objects.filter(id=1).update(name=Concat(F("name"),Value("第一版")))

Q查詢

| and,  , or     ~ 取反  & 或者
# 查找出 作者爲xiong或者xx的書藉
    auth_obj = models.Books.objects.filter(Q(auther__name="xiong")|Q(auther__name="xx"))
    print(auth_obj)

# 查找作者爲xiong,價格小於10的
    方法一: print(models.Books.objects.filter(Q(auther__name="xiong") &~ Q(price__gt=10)).values_list())

* console打印sql語句

項目中的settings.py中最後一行添加,   並重啓項目

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
}

小知識

數據庫中時間格式化
extra   使用原生的sql  語法 extra=( select = {"xx": "xx"})
如extra(select={"c": "age > 30"})

    # sqlite3 時間格式化
    # select strftime('%Y/%m/%d', '2018-01-01 11:22:22');

   ret = models.Article.objects.filter(user=user).extra(select={"c": "strftime('%%Y-%%m',create_time)"}).values("c")
    結果爲 <QuerySet [{'c': '2018-12'}, {'c': '2018-12'}]>

select strftime('%Y/%m/%d', '2018-12-06 11:04:24');

python_day18_Django-2(ORM)

mysql時間格式化     date_format(字段, "格式化")
   ret = models.Article.objects.filter(user=user).extra(select={"c": "date_format(create_time, '%%Y-%%m')"}).values("c")
結果跟sqlite3一樣    注意的是create_time傳遞的參數不需要加引號
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章