單表查詢
QuerySet的查詢方法
<1> all(): 查詢所有結果 <2> filter(**kwargs): 它包含了與所給篩選條件相匹配的對象 <3> get(**kwargs): 返回與所給篩選條件相匹配的對象,返回結果有且只有一個,如果符合篩選條件的對象超過一個或者沒有都會拋出錯誤。(源碼就去摟一眼~詮釋為何只能是一個對象) <4> exclude(**kwargs): 它包含了與所給篩選條件不匹配的對象 <5> order_by(*field): 對查詢結果排序('-id')/('price') <6> reverse(): 對查詢結果反向排序 >>>前面要先有排序才能反向 <7> count(): 返回數據庫中匹配查詢(QuerySet)的對象數量。 <8> first(): 返回第一條記錄 <9> last(): 返回最后一條記錄 <10> exists(): 如果QuerySet包含數據,就返回True,否則返回False
values 與 values_list Queryset的每個元素都變為字典或元組

distinct(): id不相同 所以無法排除 需要搭配values 與 values_list 使用
QuerySet的添加數據方法
user_obj =models.User.objects.create(name='tank',age=73,register_time='2019-2-14') user_obj = models.User(name='kevin',age=30,register_time='2019-1-1') user_obj.save()
QuerySet的修改數據方法
bookquery=models.Book.objects.all().first() 方式一:取出對象后修改屬性,再save() bookquery.name="hahahah" bookquery.save() 方式二:把所有queryset對象.update(k=v)的形式統一修改 bookquery=models.Book.objects.all().update(name="egon")
QuerySet的刪除數據方法
delete()對對象和清空queryset均適用 queryset models.User.objects.filter(name='egon').delete() 對象 user_obj.delete()
QuerySet中神奇雙下劃線
字段__gt 大于xx的 res = models.User.objects.filter(age__gt=44) 篩選 字段__lt 小于xx的 res = models.User.objects.filter(age__gt=44) 篩選 字段__gte大于等于XXX的 字段__lte小于等于XXX的 字段__in 字段值在某個列表里的 age__in=[44,22,73] 是442273的 age__range=[22,44] 在22到44范圍 字段__(day或year或者mon) 比如 date__year=2019 篩選出date字段中年為多少的 字段__contains=“n” 字 符串里有n的 區分大小寫 字段__icontains="N" 符串里有n或N的 不區分大小寫 startswith='j' 以j開頭的所有.. __endswith='n' 以n結尾的所有...
多表查詢
Query對象與Queryset的跨表查詢
原則:正向查字段 反向差表名小寫_set 一對一只需要表名小寫
正向查詢

反向查詢

基于Queryset雙下劃線查詢

Query對象的增加

queryset與query的修改
queryset修改 models.Book.objects.all().update(publish_id=3) #所有圖書圖書館都為3 models.Book.objects.filter(pk=1).update(publish=publish_obj)#傳對象 會自動綁定 對象修改 book_obj = models.Book.objects.filter(pk=1).first() # book_obj.publish_id = 3 # 點表中真實存在的字段名 # book_obj.save() ublish_obj = models.Publish.objects.filter(pk=2).first() book_obj.publish = publish_obj # 點orm中字段名 傳該字段對應的表的數據對象 book_obj.save()
book_obj.authors.set((1,)) #屬性必須是多的
book_obj.authors.set((1,2,3)) #屬性是一對多或多對多
刪除某個綁定關系
Book_obj.author.remove( 1,2 ) 一個個 不能使用元祖或者列表
清空 clear() 全清
清空的是你當前這個表記錄對應的綁定關系
book_obj = models.Book.objects.filter(pk=3).first()
book_obj.authors.clear()
queryset與query的刪除
級聯刪除
關聯的對象刪除 自己也刪除
ManyToMany與ForeignKey的操
ForeignKey
增 models.Book.objects.create(publish=publish_obj) models.Book.objects.create(publish_id=1) 改 models.Book.objects.filter(pk=1).update(publish_id=1) models.Book.objects.filter(pk=1).update(publish=publish_obj) book_obj.publish_id = 3 # 點表中真實存在的字段名 book_obj.save() 刪 刪除外鍵對象,并刪除自己
ManyToMany
增 add(*args) #也可以是傳 *obj_list 改 set(tuble) set必須接收一個可迭代對象 刪remove(*args)# 上面三個方法都可以支持傳多個數字或對象 clear()清除所有綁定 外鍵中 刪除對方對自己的綁定,對方允許null才行 多對多 清除所有的字段 第三張表少了這個記錄
聚合查詢 aggregate 分組查詢 annotate
跨表查詢不需要 表名_set
使用之前先導入:
rom django.db.models import Avg, Sum, Max, Min, Count
aggregate聚合
from django.db.models import Avg, Sum, Max, Min, Count res=models.Book.objects.all().aggregate(Avg("price")) print(res) #不指定別名返回字典{'price__avg': 13.233333} res=models.Book.objects.all().aggregate(price_avg=Avg("price")) print(res) #指定返回值13.233333
annotate分組
u_qset=Author.objects.all().annotate(age_avg=Avg("age")) print(u_qset) #QuerySet 分組之后沒影響 u_obj=Author.objects.all().annotate(age_avg=Avg("book__price")) print(u_obj.values("age_avg")) #可以轉為age_avg
Django ORM 常用字段和參數
1.AutoField
手動指定遞增列 自動遞增的int,primary_key=True。當model中如果沒有自增列,則自動會創建一個列名為id的列,有了這個就不會創建
2.IntegerField
整型-2147483648 to 2147483647
3.CharField
參數中必須有max_length
4.DateField
日期格式 YYYY-MM-DD
5.DateTimeField
YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
字段的參數
1.null
是否為空,values bool類型
2.unique
是否唯一,設置后,不能再重復
3.db_index
設置該字段為索引
4.default
默認值
以下是事件字段獨有
5.auto_now_add
設置True后,插入數據會自動添加當前時間
6.auto_now
更新的事件
講一下choise,用戶只能多選一
在models.py中
class User(models.Model):
choices = ((1,'重點大學'),(2,'普通本科'),(3,'專科'),(4,'其他'))
education = models.IntegerField(choices=choices)
在對象查找屬性中
對象.字段拿到的是值
print(u_obj.sex) #1
如果希望是實際意義上的內容
u_obj.get_字段_display() print(u_obj.get_sex_display()) #男
Django框架中的logging使用
BASE_LOG_DIR = os.path.join(BASE_DIR, "log") LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'standard': { 'format': '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' '[%(levelname)s][%(message)s]' }, 'simple': { 'format': '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s' }, 'collect': { 'format': '%(message)s' } }, 'filters': { 'require_debug_true': { '()': 'django.utils.log.RequireDebugTrue', }, }, 'handlers': { 'console': { 'level': 'DEBUG', 'filters': ['require_debug_true'], # 只有在Django debug為True時才在屏幕打印日志 'class': 'logging.StreamHandler', 'formatter': 'simple' }, 'SF': { 'level': 'INFO', 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件,根據文件大小自動切 'filename': os.path.join(BASE_LOG_DIR, "xxx_info.log"), # 日志文件 'maxBytes': 1024 * 1024 * 50, # 日志大小 50M 'backupCount': 3, # 備份數為3 xx.log --> xx.log.1 --> xx.log.2 --> xx.log.3 'formatter': 'standard', 'encoding': 'utf-8', }, 'TF': { 'level': 'INFO', 'class': 'logging.handlers.TimedRotatingFileHandler', # 保存到文件,根據時間自動切 'filename': os.path.join(BASE_LOG_DIR, "xxx_info.log"), # 日志文件 'backupCount': 3, # 備份數為3 xx.log --> xx.log.2018-08-23_00-00-00 --> xx.log.2018-08-24_00-00-00 --> ... 'when': 'D', # 每天一切, 可選值有S/秒 M/分 H/小時 D/天 W0-W6/周(0=周一) midnight/如果沒指定時間就默認在午夜 'formatter': 'standard', 'encoding': 'utf-8', }, 'error': { 'level': 'ERROR', 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件,自動切 'filename': os.path.join(BASE_LOG_DIR, "xxx_err.log"), # 日志文件 'maxBytes': 1024 * 1024 * 5, # 日志大小 50M 'backupCount': 5, 'formatter': 'standard', 'encoding': 'utf-8', }, 'collect': { 'level': 'INFO', 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件,自動切 'filename': os.path.join(BASE_LOG_DIR, "xxx_collect.log"), 'maxBytes': 1024 * 1024 * 50, # 日志大小 50M 'backupCount': 5, 'formatter': 'collect', 'encoding': "utf-8" } }, 'loggers': { '': { # 默認的logger應用如下配置 'handlers': ['SF', 'console', 'error'], # 上線之后可以把'console'移除 'level': 'DEBUG', 'propagate': True, }, 'collect': { # 名為 'collect'的logger還單獨處理 'handlers': ['console', 'collect'], 'level': 'INFO', } }, }
解決字段參數無法篩選-F與Q查詢
F
適用之前from django.db.models import F
我們的過濾器只能篩選某個值,現在想字段值進行比較
篩選出賣出大于庫存的字段 res=models.SP.object.filter(maichu__get=F("kucun")) 把自己的價格+10 res=models.SP.object.all().update(price=F("price")+50) 所有的商品名稱后面添加“NB” #不能直接拼接 from django.db.models.functions import Concat from django.db.models import Value ret3=models.Product.objects.update(name=Concat(F('name'),Value('nb')))
Q
如果和普通的對比 Q必須放在前面
from django.models import Q 篩選出id大于3 或者年齡小于10 models.Book.object.all().filter(Q(id__gt=3)|Q(age__lt=10)) ~取反
名字不等于egon的
models.Book.object.all().filter(Q(id__gt=3)|~Q(name="egon")
如果和普通的對比 Q必須放在前面
models.Book.object.all().filter(Q(id__gt=3),name="egon"
如果字段名只有字符串怎么辦?
q=Q()
q.connector="and"
q.children.append("字段名","字段值")
res=models.biao.object.filter(q)
事物
原子性操作和mysql一樣
from django.db import transaction with transaction.atomic(): # 創建一條訂單數據 # 能執行成功 #錢+100 #錢-100 可以防止執行到一半,后面代碼無法執行造成的后果 要么都成功,要都失敗
QuerySet有哪些方法
all filter exclude annotate distinct order_by 1.select_related方法 OneToOneField 和外鍵均可以適用 Django會獲取相應外鍵對應的對象,使用該字段不會查找數據庫 citys = models.city.objects.select_related('province').all() citys.province #不會走數據庫 2.select_related() ManyToManyField和外鍵字段,可以使用prefetch_related()來進行優化。
犧牲效率優化內存-defer 和 only
我們查詢出來的Queryset里的對象擁有全部屬性,而有些屬性我們不會經常使用
此時就可以用defer和only優化我們的“坦克”變身小刺客。等我們需要用到偏門的字段 再去數據庫查詢
節約了我們內存的使用,但是犧牲了效率
value #查出來的元素是一個字典
only #規定只有某個屬性
only('id','name')#取的對象,只有id和name屬性
defer('id','name')#相反,字段除了id和name都有
上述兩個拿到了不需要的字段 才會去數據庫查
自定義字段
用途不多說,直接干
class MyCharField(models.Field): # 數據庫中Char類型需要指定長度,所以要傳max_length def __init__(self,max_length,*args,**kwargs): self.max_length = max_length # 調用父類init,一定要寫關鍵字傳參,因為Field的init參數很多,可以看一下它的源碼 super().__init__(max_length=max_length,*args,**kwargs) # 該方法也不能少 def db_type(self, connection): return 'char(%s)'%self.max_length
其他邊邊角角
建立第三張表的三種方式
1.ManyTOMany 全自動
1.好處 不需要自己關心第三張表
2.壞處 創表時無法自己手動關聯其他字段
class Book(models.Model): name = models.CharField(max_length=32) authors = models.ManyToManyField(to='Author') class Author(models.Model): name = models.CharField(max_length=32)
2.手動創建第三張表關聯兩個外鍵 純手動
1.好處 可以添加其他字段
2.壞處 跨表查詢不夠方便
class Book(models.Model): name = models.CharField(max_length=32) class Author(models.Model): name = models.CharField(max_length=32) class Book2Author(models.Model): book = models.ForeignKey(to='Book') author = models.ForeignKey(to='Author') info = models.CharField(max_length=32)
3.手動創建第三張表,仍使用ManyToMany
1.好處 可以添加其他字段 夠方便
2.就是在使用的時候,不能用set、add、remove的方法,需要自己使用第三張表進行操作
偽代碼
class 作者表(model.Modes):
...字段
modes.ManyToMany(to="書籍",through="第三張表",through_fields=("表3字段1",“表3字段2”))
class 書籍(models.Model):
....字段
class 第三張表
book = models.ForeignKey(to='Book') #id
author = models.ForeignKey(to='Author') #id
....其他字段信息
在使用的時候,不能用set、add、remove的方法,需要自己跨到第三張表進行操作
models.User2Bumen.objects.create(user_id=1,bumen_id=2)
ContentType編碼
網頁是別人寫的,django也是別人寫的,我們在前后端數據交互的時候
要告訴服務器,我們的數據是哪些需要哪些編碼格式,服務器才好區分 常見的有以下三種
urlencoded
對應數據格式鍵值對 name=123,后端會根據數據格式放在request.POST里
formdate
表單編碼格式
比如普通鍵值對仍然在request.POST中,但是文件的話會丟到reque.Files
application/json
ajax發送json格式數據
jason的內容在request.body里 是二進制
Ajax
可以發起一個異步請求,服務器會給我們一個返回結果
我們可以拿到數據進行替換
我們來做一個在線上傳頭像,并替換Img的例子
需要實例化一個Datefrom 對象
processData 和 contentType 都變為False,不處理Date和使用默認編碼
$("#hread").on("click",function () {
let touxiang_obj=$("img");
let touxiang_img=$("#touxiang");
let formdata =new FormData(); /* 實例化一個form表單 */
{#formdata.datamyfile=touxiang_img[0].files[0]; /* 為表單添加 file和文件內容,并且jquery不能使用files所有取索引0 添加獲取files,取第一個 */#}
formdata.append("myfile",touxiang_img[0].files[0]);
{#console.log(formdata);#}
{#console.log(touxiang_img[0].files[0]);#}
$.ajax(
{# ajax事件 #}
{
url:"/test/",
type:"post",
data:formdata,
processData: false,
contentType:false,
success:function (data) {
leturl="/".concat(data);
touxiang_obj[1].src=leturl;
console.log(touxiang_obj[1]);
{#var res=encodeURI(data);#}
}
})
})
ajax發送json
需要指定改為contentType:pplication/json
數據需要轉為JSON.stringify
$('#d1').click(function () {
$.ajax({
url:'', // url參數可以不寫,默認就是當前頁面打開的地址
type:'post',
contentType:'application/json',
data:JSON.stringify({'name':'jason','hobby':'study'}),
success:function (data) {
{#alert(data)#}
{#$('#i3').val(data)#}
}
})
});
form表單與ajax異同點
1.form表單不支持異步提交局部刷新
2.form表單不支持傳輸json格式數據
3.form表單與ajax默認傳輸數據的編碼格式都是urlencoded
批量提交
服務器每次需要操作大量數據,操作完才能渲染頁面,過程太久
我們先讓把實例化對象存在容器里,通過bulk_create(容器)創建
l=[]
for i in range(10000):
l.append(models.Book(name="書{}".format(i)))
models.Book.objects.bulk_create(l)
分頁
class Pagination(object): def __init__(self, current_page, all_count, per_page_num=2, pager_count=11): """ 封裝分頁相關數據 :param current_page: 當前頁 :param all_count: 數據庫中的數據總條數 :param per_page_num: 每頁顯示的數據條數 :param pager_count: 最多顯示的頁碼個數 用法: queryset = model.objects.all() page_obj = Pagination(current_page,all_count) page_data = queryset[page_obj.start:page_obj.end] 獲取數據用page_data而不再使用原始的queryset 獲取前端分頁樣式用page_obj.page_html """ try: current_page = int(current_page) except Exception as e: current_page = 1 if current_page < 1: current_page = 1 self.current_page = current_page self.all_count = all_count self.per_page_num = per_page_num # 總頁碼 all_pager, tmp = divmod(all_count, per_page_num) if tmp: all_pager += 1 self.all_pager = all_pager self.pager_count = pager_count self.pager_count_half = int((pager_count - 1) / 2) @property def start(self): return (self.current_page - 1) * self.per_page_num @property def end(self): return self.current_page * self.per_page_num def page_html(self): # 如果總頁碼 < 11個: if self.all_pager <= self.pager_count: pager_start = 1 pager_end = self.all_pager + 1 # 總頁碼 > 11 else: # 當前頁如果<=頁面上最多顯示11/2個頁碼 if self.current_page <= self.pager_count_half: pager_start = 1 pager_end = self.pager_count + 1 # 當前頁大于5 else: # 頁碼翻到最后 if (self.current_page + self.pager_count_half) > self.all_pager: pager_end = self.all_pager + 1 pager_start = self.all_pager - self.pager_count + 1 else: pager_start = self.current_page - self.pager_count_half pager_end = self.current_page + self.pager_count_half + 1 page_html_list = [] # 添加前面的nav和ul標簽 page_html_list.append(''' <nav aria-label='Page navigation>' <ul class='pagination'> ''') first_page = '<li><a href="?page=%s">首頁</a></li>' % (1) page_html_list.append(first_page) if self.current_page <= 1: prev_page = '<li class="disabled"><a href="#">上一頁</a></li>' else: prev_page = '<li><a href="?page=%s">上一頁</a></li>' % (self.current_page - 1,) page_html_list.append(prev_page) for i in range(pager_start, pager_end): if i == self.current_page: temp = '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i,) else: temp = '<li><a href="?page=%s">%s</a></li>' % (i, i,) page_html_list.append(temp) if self.current_page >= self.all_pager: next_page = '<li class="disabled"><a href="#">下一頁</a></li>' else: next_page = '<li><a href="?page=%s">下一頁</a></li>' % (self.current_page + 1,) page_html_list.append(next_page) last_page = '<li><a href="?page=%s">尾頁</a></li>' % (self.all_pager,) page_html_list.append(last_page) # 尾部添加標簽 page_html_list.append(''' </nav> </ul> ''') return ''.join(page_html_list)
使用
page_obj = my_page.Pagination(current_page=current_page,all_count=all_count) # 對總數據進行切片
page_queryset = book_list[page_obj.start:page_obj.end]
前端
{{ page_obj.page_html|safe }}
聚合合并
from django.db.models import Aggregate, CharField class Concat(Aggregate): """ORM用來分組顯示其他字段 相當于group_concat""" function = 'GROUP_CONCAT' template = '%(function)s(%(distinct)s%(expressions)s)' def __init__(self, expression, distinct=False, **extra): super(Concat, self).__init__( expression, distinct='DISTINCT ' if distinct else '', output_field=CharField(), **extra) #使用 WhiteList.objects.values('ip').annotate(id=Concat('id'))
from django.db.models import Aggregate, CharField
class Concat(Aggregate):
"""ORM用來分組顯示其他字段 相當于group_concat"""
function = 'GROUP_CONCAT'
template = '%(function)s(%(distinct)s%(expressions)s)'
def __init__(self, expression, distinct=False, **extra):
super(Concat, self).__init__(
expression,
distinct='DISTINCT ' if distinct else '',
output_field=CharField(),
**extra)
浙公網安備 33010602011771號