Django進階(三)

来源:http://www.cnblogs.com/idontknowthisperson/archive/2016/12/03/6120052.html
-Advertisement-
Play Games

ORM 眾所周知有很多不同的資料庫系統,並且其中的大部分系統都包含Python介面,能夠讓我們更好的利用它們的功能,而這些系統唯一的缺點就是需要你瞭解SQL,如果你是一個更願意操縱Python對象,而不是SQL查詢的程式員,並且仍然希望使用關係資料庫作為你的數據後端,那麼我們可以使用ORM。 這些O ...


ORM

眾所周知有很多不同的資料庫系統,並且其中的大部分系統都包含Python介面,能夠讓我們更好的利用它們的功能,而這些系統唯一的缺點就是需要你瞭解SQL,如果你是一個更願意操縱Python對象,而不是SQL查詢的程式員,並且仍然希望使用關係資料庫作為你的數據後端,那麼我們可以使用ORM。

這些ORM系統的作者將純SQL語句進行了抽象化處理,將其實現為Python中的對象,這樣我們只操作對象就能完成與生成SQL語句相同的任務。就是用面向對象的方式去操作資料庫的創建表以及增刪改查等操作。

ORM優點:

1 ORM使得我們的通用資料庫交互變得簡單易行,而且完全不用考慮該死的SQL語句。快速開發,由此而來。

 2 可以避免一些新手程式猿寫sql語句帶來的性能問題。

ORM缺點:

1  性能有所犧牲,不過現在的各種ORM框架都在嘗試各種方法,比如緩存,延遲載入登來減輕這個問題。效果很顯著。

2  對於個別複雜查詢,ORM仍然力不從心,為瞭解決這個問題,ORM一般也支持寫raw sql。

3  通過QuerySet的query屬性查詢對應操作的sql語句

Model

下麵要開始學習Django ORM語法了

單表的操作(增刪改查)

--------------------增

from blog.models import *  # 首先導入應用里的models.py里的所有class(資料庫里的各個表)


def base(request): 
    # 增:
    # 方法一(推薦)
    # 固定結構: 類名(表名).objectes.create(**{"欄位名1":"插入的欄位內容","欄位名2":"插入的欄位內容"})
    Author.objects.create(**{"name": "liu"})

    # 方法二
    # 固定結構: 類名(表名).objectes.create(欄位名1="插入的欄位內容",欄位名2="插入的欄位內容")
    # 註意:欄位名不加引號
    Author.objects.create(name="liu2")

    # 方法三
    author = Author(name="liu3")  # 實例化類(要操作的表)的對象並直接賦值
    author.save()  # 保存表的內容

    # 方法四
    author = Author()  # 實例化類(要操作的表)的對象
    author.name = "liu4"  # 逐個給對象的屬性賦值
    author.save()  # 最後保存

 

--------------------查

# User2是blog.models中的一個類(表)


    # 方法一 filter
    # 固定結構: 類名(表名).objectes.filter(判斷條件)
    user2_list = User2.objects.filter(name = "liu",sex="")
    # filter括弧內添加查詢條件,多個條件用逗號隔開User2.objects.filter(name = "liu2",sex = "男")
    # 將所有滿足條件的對象集合成QuerySet對象返回:<QuerySet [<User2: User2 object>, <User2: User2 object>]>
    # 即使只有一個對象滿足條件也會返回QuerySet對象<QuerySet [<User2: User2 object>]>
    # 可以將QuerySet對象理解成一個list 可以通過索引獲取單個對象:user2_list[0]
    # 當沒有滿足條件的對象則會返回一個空的QuerySet對象:<QuerySet []>
    # 獲取到單個對象後可以通過 .欄位名 獲取該欄位對應的內容 user2_list[0].name

    # 方法二 get
    # 固定結構: 類名(表名).objectes.get(判斷條件)
    user2 = User2.objects.get(name = "liu2")
    # 只能獲取到單個滿足條件的對象,返回結果有且只有一個
    # 如果符合篩選條件的對象超過一個,或者沒有都會拋出錯誤
    # 直接通過 .欄位名 獲取該欄位對應的內容

    # 方法三 all
    # 固定結構: 類名(表名).objectes.all()
    user2_list = User2.objects.all()
    # 將該表(User2)的所有數據集合成queryset對象返回

    # 方法四 exclude
    # 固定結構: 類名(表名).objectes.exclude(判斷條件)
    user2_list = User2.objects.exclude(name = "liu2")
    # 與filter正好相反,返回的結果是所有不滿足括弧內條件的對象的集合,返回的是QuerySet對象


    # -----------下麵的方法都是對查詢的結果進行處理再返回

    # values("欄位名")
    User2.objects.filter(name = "liu2").values("sex")
    # QuerySet對象中只是想要獲取某個欄位,而不是全部的欄位,將該欄位放入 values("欄位名")
    # 獲取到QuerySet對象 列表包含字典的形式 < QuerySet[{'sex': '男'}, {'sex': '男'}]>

    # order_by("欄位名")
    # 對查詢結果按照 括弧內的欄位 從大到小排序,如果想要從小到大排序,則在引號內的欄位名前添加一個減號
    User2.objects.filter(name="liu").order_by("-sex")

    # .reverse()
    User2.objects.filter(name="liu").reverse()
    # 對查詢結果進行倒序,可以配合order_by使用

    # distinct()
    User2.objects.filter(name="liu").values("sex").distinct()
    # 剔除查詢結果中完全相同的數據

    # count()
    User2.objects.filter(name="liu").count()
    # 返回查詢結果(QuerySet)中包含的對象數量

    # first():  返回查詢結果(QuerySet)中第一個對象

    # last():   返回查詢結果(QuerySet)中最後一個對象

    # exists():  如果QuerySet包含數據,就返回True,否則返回False。

 

--------------------刪

基於查的基礎上進行刪除,先查找到要刪除的數據,然後進行刪除

delete()
Author.objects.filter(name = "liu").delete()

刪除一條數據,那麼資料庫中所有與該條數據相關的數據都會被刪除,級聯刪除

--------------------改

基於查的基礎上進行修改,先查找到要修改的數據,然後進行修改

    # update() 括弧內添加要修改的欄位及內容 sex = "aaa" 修改多個欄位用逗號分隔開
    User2.objects.filter(name="liu2").update(sex = "")

 

 關聯表操作

實例:我們來假定下麵這些概念,欄位和關係

作者模型:一個作者有姓名。

作者詳細模型:把作者的詳情放到詳情表,包含性別,email地址和出生日期,作者詳情模型和作者模型之間是一對一的關係(one-to-one)(類似於每個人和他的身份證之間的關係),在大多數情況下我們沒有必要將他們拆分成兩張表,這裡只是引出一對一的概念。

出版商模型:出版商有名稱,地址,所在城市,省,國家和網站。

書籍模型:書籍有書名和出版日期,一本書可能會有多個作者,一個作者也可以寫多本書,所以作者和書籍的關係就是多對多的關聯關係(many-to-many),一本書只應該由一個出版商出版,所以出版商和書籍是一對多關聯關係(one-to-many),也被稱作外鍵。

書籍與作者:多對多關係,書籍與出版商:一對多關係,作者與出版商:無關係

創建表

from django.db import models



class Publisher(models.Model):
    name = models.CharField(max_length=30, verbose_name="名稱")
    address = models.CharField("地址", max_length=50)
    city = models.CharField('城市', max_length=60)
    state_province = models.CharField(max_length=30)
    country = models.CharField(max_length=50)
    website = models.URLField()

    class Meta:
        verbose_name = '出版商'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name


class Author(models.Model):
    name = models.CharField(max_length=30)

    def __str__(self):
        return self.name


class AuthorDetail(models.Model):
    sex = models.BooleanField(max_length=1, choices=((0, ''), (1, ''),))
    email = models.EmailField()
    address = models.CharField(max_length=50)
    birthday = models.DateField()
    author = models.OneToOneField(Author)
    # 一對一的關係 當表中存在兩個相同的author時會報錯


class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField("Author")
    # 創建多對多關係的第三章表
    # models.ManyToManyField(Author) 括弧里放入那個與該表有“多對多”關係的表名
    # 規定是一本書可以由多個作者共同完成,而一個作者又可以完成多本書,所以書與作者的關係是“多對多”
    # “多對多”的關係只有依靠第三章表才會完美體現兩個表中的關係,而ManyToManyField(Author)會自動幫我們創建第三張表
    # 也可以在Author表裡寫 models.ManyToManyField(Book) 自動創建第三張表


    # 外鍵中加引號則 外鍵相關聯的Publisher表不一定非要建在Book表之前,不加引號則必須建在該表之前
    # 是根據反射找到的Publisher表
    publishersss = models.ForeignKey("Publisher")
    # models.ForeignKey(Publisher) 括弧里放入你想建立主外鍵的另一個數據表的表名(對應的主鍵的表的名稱)
    # 規定是一本書只能由一家出版社出版,而一家出版社可以出版多本書,所以書與出版社之間的關係就是“多對一”的關係
    # 多對一的關係中應該在“多”的那個表裡創建外鍵,所以這裡添加外鍵
    # 我們寫的欄位是publisher 實際上django幫我們存入資料庫中時自動存儲成了publisher_id欄位, 這是models.ForeignKey()的特殊性

    publication_date = models.DateField()
    price = models.DecimalField(max_digits=5, decimal_places=2, default=10)

    def __str__(self):
        return self.title



class User2(models.Model):
    name = models.CharField(max_length=30)
    sex = models.CharField(max_length=30)

 

 表中插入數據

from blog.models import * # 首先導入應用里的models.py里的所有class(資料庫里的各個表)

# Author表 Author.objects.create(**{ "name":"zhangsan" }) # AuthorDetail表 # 欄位:sex email address birthday author # 先獲取外鍵author所要綁定的Author對象author3 author3 = Author.objects.filter(name = "gaoer")[0] AuthorDetail.objects.create(**{ "sex":True, "email":"[email protected]", "address":"中國北京", "birthday":"1991-10-24", "author":author3 # 一對一關係中 author 賦值 Author對象author3 }) # Publisher表 # 欄位:name address city state_province country website Publisher.objects.create(**{ "name": "出版社002", "address": "地址002", "city": "城市002", "state_province": "省份002", "country": "國家002", "website": "網站002", }) # Book表 # 欄位:title authors publisher publication_date price # 先獲取要建立關係的Publisher對象 publisher2 = Publisher.objects.filter(id = 3)[0] Book.objects.create(**{ "title":"書籍005", "publishersss":publisher2, # 一對多關係中 直接在外鍵publishersss 賦值 publisher對象 "publication_date":"2016-08-09", "price":50 }) #多對多 建立關係 先獲取要綁定的Author對象 authors8 =Author.objects.filter(id = 5)[0] #先獲取要綁定的Book對象 book001 = Book.objects.filter(title="書籍005")[0] # Book對象.關係欄位.add(Author對象) book001.authors.add(authors8) # 由於我們是在Book表中與Author建立的ManyToManyField關係,所以是 Book對象.Book表中的關係欄位名.add(Author對象) # 如果是在Author表中與Book建立的ManyToManyField關係,那麼該是 Author對象.Author表中的關係欄位名.add(Book對象)

 

 --------------------關聯表查詢

   #----------------關聯查找之“一對多”的關係
    # 雙下劃線可以理解為只是一個判斷條件,任何有關聯的表都可以查到
    # 固定寫法:外鍵名__外鍵關聯表的欄位名
    # Book.objects.filter(publishersss__name="出版社001")[0]
    # Publisher.objects.filter(book__title="書籍001")

    # 都是已知A表中的數據,查找與他相關的B表中的數據

    # 當A表中的某行數據只能綁定B表中的一行數據時(一個Book只能對應一個Publisher)
    # 直接 .外鍵名稱
    # book = Book.objects.filter(id = 1)[0]
    # publisher = book.publishersss
    # 由於是“一對多”的關係 所以publisher是一個對象 而不是QuerySet對象

    # 當A表中的某行數據可以綁定多個B表中的數據(一個Publisher對應多個Book)
    # 需要用到 表名_set  固定寫法:表名_set
    # publisher =Publisher.objects.filter(id=1)[0]
    # book=publisher.book_set.all() #  獲取到QuerySit對象集合
    # .book_set 跳轉到與Publisher對象關聯的book表
    #  Publisher.objects.filter(id=1)[0].book_set   相當於  Book.objects 只不過都是與id=1的publisher綁定的書的對象
    #  之後可以根據查詢語法查詢了 .filter .all .get

    # ----------------關聯查找之“多對多”的關係

    # 根據書的ID找到對應的作者 是個QuerySet對象,拿到第一個作者的作者信息.authordetail
    # author = Author.objects.filter(book__id=1)[0].authordetail

    # -----QuerySet對象.values("相關聯的表外鍵欄位名__相關聯的表的欄位名")
    # 取到與之相關聯對象的欄位,不加“__欄位名” 預設取到與之相關聯對象的主鍵
    # Book.objects.filter(title='書籍001').values('publishersss__city')[0]
    # -----QuerySet對象.values("表名__外鍵欄位名")
    # A表和B表有關聯,B表和C表有關聯,A和C無關聯,已知A,查到與A有關聯的B再查到與B有關聯的C
    # A對象點.values('共同關聯B表名__B中關聯C的外鍵欄位名')  得到C表主鍵
    # Author.objects.filter(id=1).values('book__publishersss')

 

 

 --------------------聚合查詢:

通過對QuerySet進行計算,返回一個聚合值的字典。aggregate()中每一個參數都指定一個包含在字典中的返回值。即在查詢集上生成聚合。

首先導入模塊 from django.db.models import aggregates, Avg, Sum, Max, Min

# 從整個查詢集生成統計值。比如,你想要計算所有在售書的平均價錢。Django的查詢語法提供了一種方式描述所有圖書的集合。
    # 得到字典形式結果
    # 預設:
    a = Book.objects.all().aggregate(Avg("price"))
    print(a)  # 執行結果{'price__avg': 60.0}
    # aggregate()子句的參數描述了我們想要計算的聚合值,在這個例子中,是Book模型中price欄位的平均值
    # aggregate()是QuerySet的一個終止子句,意思是說,它返回一個包含一些鍵值對的字典。鍵的名稱是聚合值的標識符,值是計算出來的聚合值。
   # 鍵的名稱是按照欄位和聚合函數的名稱自動生成出來的。如果你想要為聚合值指定一個名稱,可以向聚合子句提供它:
a = Book.objects.all().aggregate(pingjunjiage=Avg("price")) print(a) # 執行結果{'pingjunjiage': 60.0} # 如果你也想知道所有圖書價格的最大值和最小值,可以這樣查詢: a = Book.objects.aggregate(Avg('price'), Max('price'), Min('price'), Sum("price")) print(a) # 執行結果{'price__max': Decimal('80.00'), 'price__avg': 60.0, 'price__sum': Decimal('240.00'), 'price__min': Decimal('50.00')}

 

 

 --------------------分組查詢:

可以通過計算查詢結果中每一個對象所關聯的對象集合,從而得出總計值(也可以是平均值或總和),即為查詢集的每一項生成聚合。

    查詢alex出的書總價格                   

       

        查詢各個作者出的書的總價格,這裡就涉及到分組了,分組條件是authors__name

           

         查詢各個出版社最便宜的書價是多少

       

 

 

 --------------------F查詢和Q查詢



    僅僅靠單一的關鍵字參數查詢已經很難滿足查詢要求。此時Django為我們提供了F和Q查詢:

    # F 使用查詢條件的值,專門取對象中某列值的操作

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


    # Q 構建搜索條件
    from django.db.models import Q

    # 1 Q對象(django.db.models.Q)可以對關鍵字參數進行封裝,從而更好地應用多個查詢
    q1 = models.Book.objects.filter(Q(title__startswith='P')).all()
    print(q1)  # [<Book: Python>, <Book: Perl>]

    # 2、可以組合使用&,|操作符,當一個操作符是用於兩個Q的對象,它產生一個新的Q對象。
    Q(title__startswith='P') | Q(title__startswith='J')

    # 3、Q對象可以用~操作符放在前面表示否定,也可允許否定與不否定形式的組合
    Q(title__startswith='P') | ~Q(pub_date__year=2005)

    # 4、應用範圍:

    # Each lookup function that takes keyword-arguments (e.g. filter(),
    #  exclude(), get()) can also be passed one or more Q objects as
    # positional (not-named) arguments. If you provide multiple Q object
    # arguments to a lookup function, the arguments will be “AND”ed
    # together. For example:

    Book.objects.get(
        Q(title__startswith='P'),
        Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
    )

    # sql:
    # SELECT * from polls WHERE question LIKE 'P%'
    #     AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')

    # import datetime
    # e=datetime.date(2005,5,6)  #2005-05-06

    # 5、Q對象可以與關鍵字參數查詢一起使用,不過一定要把Q對象放在關鍵字參數查詢的前面。
    # 正確:
    Book.objects.get(
        Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
        title__startswith='P')
    # 錯誤:
    Book.objects.get(
        question__startswith='P',
        Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))

 

 

QuerySet

QuerySet對象特點:

1. 可迭代的

2.可切片

#objs=models.Book.objects.all()#[obj1,obj2,ob3...]

    #QuerySet:   可迭代

    # for obj in objs:#每一obj就是一個行對象
    #     print("obj:",obj)
    # QuerySet:  可切片

    # print(objs[1])
    # print(objs[1:4])
    # print(objs[::-1])

 

 QuerySet對象的高效使用:

<1>Django的queryset是惰性的

     Django的queryset對應於資料庫的若幹記錄(row),通過可選的查詢來過濾。例如,下麵的代碼會得
     到資料庫中名字為‘Dave’的所有的人:person_set = Person.objects.filter(first_name="Dave")
     上面的代碼並沒有運行任何的資料庫查詢。你可以使用person_set,給它加上一些過濾條件,或者將它傳給某個函數,
     這些操作都不會發送給資料庫。這是對的,因為資料庫查詢是顯著影響web應用性能的因素之一。

<2>要真正從資料庫獲得數據,你可以遍歷queryset或者使用if queryset,總之你用到數據時就會執行sql.
   為了驗證這些,需要在settings裡加入 LOGGING(驗證方式)
        obj=models.Book.objects.filter(id=3)
        # for i in obj:
        #     print(i)

        # if obj:
        #     print("ok")

<3>queryset是具有cache的
     當你遍歷queryset時,所有匹配的記錄會從資料庫獲取,然後轉換成Django的model。這被稱為執行
    (evaluation).這些model會保存在queryset內置的cache中,這樣如果你再次遍歷這個queryset,
     你不需要重覆運行通用的查詢。
        obj=models.Book.objects.filter(id=3)

        # for i in obj:
        #     print(i)
                          ## models.Book.objects.filter(id=3).update(title="GO")
                          ## obj_new=models.Book.objects.filter(id=3)
        # for i in obj:
        #     print(i)   #LOGGING只會列印一次

<4>
     簡單的使用if語句進行判斷也會完全執行整個queryset並且把數據放入cache,雖然你並不需要這些
     數據!為了避免這個,可以用exists()方法來檢查是否有數據:

            obj = Book.objects.filter(id=4)
            #  exists()的檢查可以避免數據放入queryset的cache。
            if obj.exists():
                print("hello world!")

<5>當queryset非常巨大時,cache會成為問題

     處理成千上萬的記錄時,將它們一次裝入記憶體是很浪費的。更糟糕的是,巨大的queryset可能會鎖住系統
     進程,讓你的程式瀕臨崩潰。要避免在遍曆數據的同時產生queryset cache,可以使用iterator()方法
     來獲取數據,處理完數據就將其丟棄。
        objs = Book.objects.all().iterator()
        # iterator()可以一次只從資料庫獲取少量數據,這樣可以節省記憶體
        for obj in objs:
            print(obj.name)
        #BUT,再次遍歷沒有列印,因為迭代器已經在上一次遍歷(next)到最後一次了,沒得遍歷了
        for obj in objs:
            print(obj.name)

     #當然,使用iterator()方法來防止生成cache,意味著遍歷同一個queryset時會重覆執行查詢。所以使
     #用iterator()的時候要當心,確保你的代碼在操作一個大的queryset時沒有重覆執行查詢

總結:
    queryset的cache是用於減少程式對資料庫的查詢,在通常的使用下會保證只有在需要的時候才會查詢資料庫。
使用exists()和iterator()方法可以優化程式對記憶體的使用。不過,由於它們並不會生成queryset cache,可能
會造成額外的資料庫查詢。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 操作 MySql 資料庫使用 程式包(MySql 開發,其他第三方可能會有些問題)。 project.json 代碼: 測試資料庫腳本: sql CREATE TABLE ( int(11) NOT NULL AUTO_INCREMENT, varchar(255) DEFAULT NULL, in ...
  • Smobiler是一個在VS環境中使用.Net語言來開發APP的開發平臺,也許比Xamarin更方便 ...
  • 反骨仔的 2016 年度全文目錄索引 目錄 Linq 系列 非同步編程系列(一) 非同步編程系列(二) 委托與事件系列 C# 基礎回顧 .NET 相關 SQL 基礎梳理 其它 - 暫無分類 Linq 系列 走進 LINQ 的世界(推薦) 進階 - LINQ 標準查詢操作概述(強烈推薦) Linq To ...
  • 工欲善其事,必先利其器。如今 Web 開發標準越來越高,Web 開發者也在不斷尋找途徑提升自己的技能。為使大家的開發工作更順利進行,本文整理了 10+ 款比較優秀的 Web 開發工具,希望對你有幫助。 喜歡的不要忘了收藏、點贊和打賞哦,感謝大家的支持! Bootstrap Bootstrap 是快速 ...
  • 英文文檔: The constructor builds a tuple whose items are the same and in the same order as iterable‘s items. iterable may be either a sequence, a containe ...
  • 1、直接把表單的參數寫在Controller相應的方法的形參中,適用於get方式提交,不適用於post方式提交。若"Content-Type"="application/x-www-form-urlencoded",可用post提交 url形式:http://localhost:8080/SSMDe ...
  • 為瞭解決C++記憶體泄漏的問題,C++11引入了智能指針(Smart Pointer)。 智能指針的原理是,接受一個申請好的記憶體地址,構造一個保存在棧上的智能指針對象,當程式退出棧的作用域範圍後,由於棧上的變數自動被銷毀,智能指針內部保存的記憶體也就被釋放掉了,除非將智能指針保存起來。 C++11提供了 ...
  • JDBC2.0提供了javax.sql.DataSource介面,它負責建立與資料庫的連接,在應用程式中訪問資料庫時不必編寫連接資料庫的代碼,可以直接從數據源獲得資料庫連接 1.資料庫和連接池 在DataSource中事先建立了多個資料庫連接,這些資料庫連接保存在連接池(ConnectPool)中。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...