一、經過form表單或者經過From類上傳css
from django.shortcuts import render,HttpResponse from django import forms from django.forms import fields class UploadForm(forms.Form): user = fields.CharField() img = fields.FileField() def upload(request): '''上傳文件''' if request.method == 'GET': return render(request,'upload.html') else: ''' # 基於Form也能夠上傳,這裏還作了驗證 obj = UploadForm(request.POST,request.FILES) if obj.is_valid(): user = obj.cleaned_data['user'] img = obj.cleaned_data['img'] ''' #img是對象,封裝了文件大小、名稱、內容。。。 img = request.FILES.get('img') print(img.name) print(img.size) #將上傳文件寫入本地 f = open(img.name,'wb') #上傳是一點一點的,因此不能一會兒拿到所有,須要循環 for line in img.chunks(): f.write(line) f.close() return HttpResponse('上傳成功')
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> #c1{ position: absolute; top:0; left:0; opacity: 0; } #c2{ background-color: dodgerblue; border: 1px solid lightblue; font-size: 20px; } </style> </head> <body> <form action="/upload.html" method="POST" enctype="multipart/form-data"> <input type="text" name="user"/> {#修改上傳按鈕的樣式,其實就是把按鈕隱藏,上面覆蓋一個新的按鈕#} <div style="position: relative;"> <a id="c2">新上傳</a> <input type="file" name="img" id="c1"/> </div> <input type="submit" value="提交"/> </form> </body> </html>
二、jQuery ajax和原生的ajax上傳html
二者都用到了同一個類FormData()來封裝用戶提交的數據,本質上ajax和原生ajax原理同樣,由於底層都是用的類XMLHttpRequest;python
可是不是每個瀏覽器都有FormData(),有一些低版本的IE可能不支持;因此若是考慮兼容性的問題,儘可能用iframe + form的形式;mysql
views.pyjquery
#將文件保存到本地,對下面兩個方式都適用 def ajax1(request): ret = {'status':True,'msg':'666'} import json data = request.FILES.get('k') f = open(data.name,'wb') for line in data: f.write(line) f.close() return HttpResponse(json.dumps(ret))
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> {% load staticfiles %} <style> .btn{ display: inline-block; padding: 5px 10px; background-color: #2aabd2; color: white; cursor: pointer; } </style> </head> <body> <h3>Ajax上傳文件</h3> <input type="file" id="img"/> <a class="btn" onclick="ajaxSubmit6();">ajax上傳</a> <a class="btn" onclick="ajaxSubmit7();">原生ajax上傳</a> <script src="{% static 'js/jquery-1.12.4.js' %}"></script> <script> //上傳文件 //經過FormData function ajaxSubmit6() { //獲得img標籤上傳的文件 var f = document.getElementById('img').files[0]; var data = new FormData(); data.append('k',f); $.ajax({ url:'/ajax1.html', type:'POST', data:data, processData: false, // tell jQuery not to process the data contentType: false, // tell jQuery not to set contentType success:function (arg) { console.log(arg); } }) } //經過原生ajax上傳 function ajaxSubmit7() { var f = document.getElementById('img').files[0]; var data = new FormData(); data.append('k',f); var xhr = new XMLHttpRequest(); xhr.open('POST','/ajax1.html'); xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ console.log(xhr.responseText); } }; xhr.send(data); } </script> </body> </html>
三、iframe + form 上傳文件git
iframe默認是不顯示的;面試
views.pyajax
def ajax1(request): ret = {'status':True,'msg':'666'} import json #iframe + form 上傳文件 data = request.FILES.get('img3') f = open(data.name,'wb') for line in data: f.write(line) f.close() return HttpResponse(json.dumps(ret))
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> {% load staticfiles %} <style> .btn{ display: inline-block; padding: 5px 10px; background-color: #2aabd2; color: white; cursor: pointer; } </style> </head> <body> <h2>5.基於iframe+Form上傳文件</h2> <div> <iframe id="iframe3" name="frame3" style="display: none;" ></iframe> <form id="fm3" action="/ajax1.html" method="POST" target="frame3" enctype="multipart/form-data"> <input type="file" name="img3"/> <a onclick="ajaxSubmit8();" class="btn">iframe上傳</a> </form> </div> <script src="{% static 'js/jquery-1.12.4.js' %}"></script> <script> //iframe+form上傳 function ajaxSubmit8() { document.getElementById('iframe3').onload = reloadIframe3; document.getElementById('fm3').submit(); } //至關於回調函數,經過判斷後臺返回的消息來進行下一步操做,只不事後臺返回的內容在iframe中 function reloadIframe3() { var content = this.contentWindow.document.body.innerText; var ret = JSON.parse(content); if(ret.status){ alert('000'); } } </script> </body> </html>
四、上傳圖片時在頁面上預覽sql
from django.shortcuts import render,HttpResponse import json import os import uuid def upload(request): return render(request,'upload.html') def upload_img(request): ret = {'status': True,'data':None, 'msg': None} obj = request.FILES.get('img') #爲避免文件名重複被覆蓋,文件名加個前綴 nid = str(uuid.uuid4()) file_path = os.path.join('static',nid+obj.name) f = open(file_path, 'wb') for line in obj.chunks(): f.write(line) f.close() ret['data'] = file_path return HttpResponse(json.dumps(ret))
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> {% load staticfiles %} <style> .btn{ background-color: #2aabd2; color: white; cursor: pointer; padding: 4px 2px; } .upload{ position: absolute; top:0; left:0; opacity: 0; } </style> </head> <body> <h2>基於iframe+Form上傳文件</h2> <div> <iframe id="iframe" name="fram" style="display: none;" ></iframe> <form id="fm" action="/upload_img.html" method="POST" target="fram" enctype="multipart/form-data"> <div style="position: relative"> <a class="btn">iframe上傳</a> <input type="file" name="img" onchange="uploadFile();" class="upload"/> </div> </form> <h3>預覽</h3> <div id = 'preview'> </div> </div> <script src="{% static 'js/jquery-1.12.4.js' %}"></script> <script> function uploadFile() { document.getElementById('iframe').onload = reloadIframe; document.getElementById('fm').submit(); } function reloadIframe() { var content = this.contentWindow.document.body.innerText; var obj = JSON.parse(content); //生成一個img標籤 var tag = document.createElement('img'); tag.src = obj.data; //先清空上一次的照片,再添加新的照片路徑 $('#preview').empty().append(tag); } </script> </body> </html>
AutoField(Field) - int自增列,必須填入參數 primary_key=True BigAutoField(AutoField) - bigint自增列,必須填入參數 primary_key=True 注:當model中若是沒有自增列,則自動會建立一個列名爲id的列 from django.db import models class UserInfo(models.Model): # 自動建立一個列名爲id的且爲自增的整數列 username = models.CharField(max_length=32) class Group(models.Model): # 自定義自增列 nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) SmallIntegerField(IntegerField): - 小整數 -32768 ~ 32767 PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) - 正小整數 0 ~ 32767 IntegerField(Field) - 整數列(有符號的) -2147483648 ~ 2147483647 PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) - 正整數 0 ~ 2147483647 BigIntegerField(IntegerField): - 長整型(有符號的) -9223372036854775808 ~ 9223372036854775807 BooleanField(Field) - 布爾值類型 NullBooleanField(Field): - 能夠爲空的布爾值 CharField(Field) - 字符類型 - 必須提供max_length參數, max_length表示字符長度 TextField(Field) - 文本類型 EmailField(CharField): - 字符串類型,Django Admin以及ModelForm中提供驗證機制 IPAddressField(Field) - 字符串類型,Django Admin以及ModelForm中提供驗證 IPV4 機制 GenericIPAddressField(Field) - 字符串類型,Django Admin以及ModelForm中提供驗證 Ipv4和Ipv6 - 參數: protocol,用於指定Ipv4或Ipv6, 'both',"ipv4","ipv6" unpack_ipv4, 若是指定爲True,則輸入::ffff:192.0.2.1時候,可解析爲192.0.2.1,開啓刺功能,須要protocol="both" 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 上傳圖片的寬度保存的數據庫字段名(字符串) DateTimeField(DateField) - 日期+時間格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] DateField(DateTimeCheckMixin, Field) - 日期格式 YYYY-MM-DD TimeField(DateTimeCheckMixin, Field) - 時間格式 HH:MM[:ss[.uuuuuu]] DurationField(Field) - 長整數,時間間隔,數據庫中按照bigint存儲,ORM中獲取的值爲datetime.timedelta類型 FloatField(Field) - 浮點型,小數位越多,約不精確,小數建議使用下面字段 DecimalField(Field) - 10進制小數 - 參數: max_digits,小數總長度 decimal_places,小數位長度 BinaryField(Field) - 二進制類型
二、字段參數數據庫
null 數據庫中字段是否能夠爲空 db_column 數據庫中字段的列名 default 數據庫中字段的默認值 primary_key 數據庫中字段是否爲主鍵 db_index 數據庫中字段是否能夠創建索引 unique 數據庫中字段是否能夠創建惟一索引 unique_for_date 數據庫中字段【日期】部分是否能夠創建惟一索引 unique_for_month 數據庫中字段【月】部分是否能夠創建惟一索引 unique_for_year 數據庫中字段【年】部分是否能夠創建惟一索引 verbose_name Admin中顯示的字段名稱 blank Admin中是否容許用戶輸入爲空 editable Admin中是否能夠編輯,直接隱藏了,form中是變灰色 help_text Admin中該字段的提示信息 choices Admin中顯示選擇框的內容,用不變更的數據放在內存中從而避免跨表操做 如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1) error_messages 自定義錯誤信息(字典類型),從而定製想要顯示的錯誤信息; 字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date 如:{'null': "不能爲空.", 'invalid': '格式錯誤'} 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'), ] )
實例:
from django.db import models class UserInfo(models.Model): username = models.CharField( null=True, #能夠爲空 db_column='user', #表中顯示的列名 max_length=32, #字符串字段必須有最大長度 db_index=True, #普通索引,只能加速查找 unique=True, #惟一索引,加速查找,限制列值惟一,能夠爲空,可是隻能有一個空 #primary_key=True, #主鍵索引,加速查找,限制列值惟一,不能爲空 ) #生成下拉框 user_type = models.IntegerField( choices = [ (1,'普通用戶'), (2,'超級用戶'), (3,'VIP用戶'), ] ) part = models.ForeignKey( to = 'Part', to_field = 'id', on_delete = models.CASCADE, # related_name='part', limit_choices_to={'id__gt':1} #只顯示ID大於1的 ) def __str__(self): return self.username class Part(models.Model): caption = models.CharField(max_length=32) def __str__(self): return self.caption
三、多表關係以及參數
多對多自關聯:用戶互粉時,一張表能夠本身跟本身實現多對多的關聯:m = models.ManyToManyField('表名',related_name='utu')
一對多自關聯:評論樓,用戶回覆評論的根ID必須是已經存在的評論ID
ForeignKey(ForeignObject) # ForeignObject(RelatedField) 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,刪除關聯數據, a. 與之關聯的值設置爲指定值,設置:models.SET(值) b. 與之關聯的值設置爲可執行對象的返回值,設置:models.SET(可執行對象) def func(): return 10 class MyModel(models.Model): user = models.ForeignKey( to="User", to_field="id" on_delete=models.SET(func),) 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} - limit_choices_to=lambda : {'nid__gt': 5} from django.db.models import Q - limit_choices_to=Q(nid__gt=10) - limit_choices_to=Q(nid=8) | Q(nid__gt=10) - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root') db_constraint=True # 是否在數據庫中建立外鍵約束 parent_link=False # 在Admin中是否顯示關聯數據 OneToOneField(ForeignKey) to, # 要進行關聯的表名 to_field=None # 要關聯的表中的字段名稱 on_delete=None, # 當刪除關聯表中的數據時,當前表與其關聯的行的行爲 ###### 對於一對一 ###### # 1. 一對一其實就是 一對多 + 惟一索引 # 2.當兩個類之間有繼承關係時,默認會建立一個一對一字段 # 以下會在A表中額外增長一個c_ptr_id列且惟一: class C(models.Model): nid = models.AutoField(primary_key=True) part = models.CharField(max_length=12) class A(C): id = models.AutoField(primary_key=True) code = models.CharField(max_length=1) ManyToManyField(RelatedField) 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} - limit_choices_to=lambda : {'nid__gt': 5} from django.db.models import Q - limit_choices_to=Q(nid__gt=10) - limit_choices_to=Q(nid=8) | Q(nid__gt=10) - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
symmetrical=None, # 僅用於多對多自關聯時,symmetrical用於指定內部是否建立反向操做的字段 # 作以下操做時,不一樣的symmetrical會有不一樣的可選字段 models.BB.objects.filter(...) # 可選字段有:code, id, m1 class BB(models.Model): code = models.CharField(max_length=12) m1 = models.ManyToManyField('self',symmetrical=True) # 可選字段有: bb, code, id, m1 class BB(models.Model): code = models.CharField(max_length=12) m1 = models.ManyToManyField('self',symmetrical=False) through=None, # 自定義第三張表時,使用字段用於指定關係表 through_fields=None, # 自定義第三張表時,使用字段用於指定關係表中那些字段作多對多關係表 from django.db import models class Person(models.Model): name = models.CharField(max_length=50) class Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField( Person, through='Membership', through_fields=('group', 'person'), ) class Membership(models.Model): group = models.ForeignKey(Group, on_delete=models.CASCADE) person = models.ForeignKey(Person, on_delete=models.CASCADE) inviter = models.ForeignKey( Person, on_delete=models.CASCADE, related_name="membership_invites", ) invite_reason = models.CharField(max_length=64) db_constraint=True, # 是否在數據庫中建立外鍵約束 db_table=None, # 默認建立第三張表時,數據庫中表的名稱
class UserInfo(models.Model): nid = models.AutoField(primary_key=True) username = models.CharField(max_length=32) class Meta: # 數據庫中生成的表名稱 verbose_name_plural = '文章評論表' # 聯合索引 index_together = [ ("pub_date", "deadline"), ] # 聯合惟一索引 unique_together = (("driver", "restaurant"),)
四、ORM操做補充
def select_related(self, *fields) #性能相關:表之間進行join連表操做,須要屢次SQL操做,性能低,因此這個方法能夠一次連表操做獲取全部的的數據。 model.tb.objects.all().select_related() model.tb.objects.all().select_related('外鍵字段1','外鍵字段2') def prefetch_related(self, *lookups) #性能相關:不進行連表操做,使用其執行兩次SQL查詢在Python代碼中實現連表操做。 # 第一次:獲取全部用戶表 # 第二次:獲取用戶類型表 where id in (用戶表中的查到的全部用戶ID) models.UserInfo.objects.prefetch_related('外鍵字段') def distinct(self, *field_names) # 用於distinct去重 models.UserInfo.objects.values('nid').distinct() # select distinct nid from userinfo #注:只有在PostgreSQL中才能直接使用distinct(參數)進行去重,其餘數據庫前面要加上values def order_by(self, *field_names) # 用於排序,-id倒序 models.UserInfo.objects.all().order_by('-id','age') def reverse(self): # 倒序 只是對排序的結果進行翻轉 models.UserInfo.objects.all().order_by('-nid').reverse() # 注:若是存在order_by,reverse則是倒序,若是沒有order_by,加上reverse無效,若是多個排序則一一倒序 def defer(self, *fields): models.UserInfo.objects.defer('username','id') 或 models.UserInfo.objects.filter(...).defer('username','id') #映射中排除某列數據 def only(self, *fields): #僅取某個表中的某幾列數據 #和values的區別:結果是[obj,obj,],對象中只有指定的字段 #可是若是你取對象裏面沒有的字段,就會再發一次SQL請求,也能夠取到 models.UserInfo.objects.only('username','id') 或 models.UserInfo.objects.filter(...).only('username','id') def using(self, alias): 指定使用的數據庫,參數爲別名(setting中的設置)
五、執行原生SQL
#第一種 from django.db import connection, connections cursor = connection.cursor() # cursor = connections['default'].cursor() cursor.execute("""SELECT * from auth_user where id = %s""", [1]) row = cursor.fetchone() #第二種 def raw(self, raw_query, params=None, translations=None, using=None): # 執行原生SQL models.UserInfo.objects.raw('select * from userinfo') # 若是SQL是其餘表時,必須將名字設置爲當前UserInfo對象的主鍵列名 models.UserInfo.objects.raw('select id as nid from 其餘表') # 爲原生SQL設置參數 models.UserInfo.objects.raw('select id as nid from userinfo where nid>%s', params=[12,]) # 將獲取的到列名轉換爲指定列名 name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'} Person.objects.raw('SELECT * FROM some_other_table', translations=name_map) # 指定數據庫 models.UserInfo.objects.raw('select * from userinfo', using="default") ################### 原生SQL ################### from django.db import connection, connections cursor = connection.cursor() # cursor = connections['default'].cursor() cursor.execute("""SELECT * from auth_user where id = %s""", [1]) row = cursor.fetchone() # fetchall()/fetchmany(..) #第三種 def extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None) # 構造額外的查詢條件或者映射,如:子查詢 Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,)) Entry.objects.extra(where=['headline=%s'], params=['Lennon']) Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"]) Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])
六、不經常使用操做
def dates(self, field_name, kind, order='ASC'): # 根據時間進行某一部分進行去重查找並截取指定內容 # kind只能是:"year"(年), "month"(年-月), "day"(年-月-日) # order只能是:"ASC" "DESC" # 並獲取轉換後的時間 - year : 年-01-01 - month: 年-月-01 - day : 年-月-日 models.DatePlus.objects.dates('ctime','day','DESC') def datetimes(self, field_name, kind, order='ASC', tzinfo=None): # 根據時間進行某一部分進行去重查找並截取指定內容,將時間轉換爲指定時區時間 # kind只能是 "year", "month", "day", "hour", "minute", "second" # order只能是:"ASC" "DESC" # tzinfo時區對象 models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.UTC) models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.timezone('Asia/Shanghai')) """ pip3 install pytz import pytz pytz.all_timezones pytz.timezone(‘Asia/Shanghai’) """ def aggregate(self, *args, **kwargs): # 聚合函數,獲取字典類型聚合結果 from django.db.models import Count, Avg, Max, Min, Sum result = models.UserInfo.objects.aggregate(k=Count('u_id', distinct=True), n=Count('nid')) ===> {'k': 3, 'n': 4} def bulk_create(self, objs, batch_size=None): # 批量插入 # batch_size表示一次插入的個數 objs = [ models.DDD(name='r11'), models.DDD(name='r22') ] models.DDD.objects.bulk_create(objs, 10) def get_or_create(self, defaults=None, **kwargs): # 若是存在,則獲取,不然,建立 # defaults 指定建立時,其餘字段的值 obj, created = models.UserInfo.objects.get_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 2}) def update_or_create(self, defaults=None, **kwargs): # 若是存在,則更新,不然,建立 # defaults 指定建立時或更新時的其餘字段 obj, created = models.UserInfo.objects.update_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 1}) def in_bulk(self, id_list=None): # 根據主鍵ID進行查找 id_list = [11,21,31] models.DDD.objects.in_bulk(id_list)
七、正確使用索引
數據庫表中添加索引後確實會讓查詢速度起飛,但前提必須是正確的使用索引來查詢,若是以錯誤的方式使用,則即便創建索引也會不奏效。即便創建索引,索引也不會生效:
- like '%xx' select * from tb1 where name like '%cn'; - 使用函數 select * from tb1 where reverse(name) = 'wupeiqi'; - or select * from tb1 where nid = 1 or email = 'seven@live.com'; 特別的:當or條件中有未創建索引的列才失效,如下會走索引 select * from tb1 where nid = 1 or name = 'seven'; select * from tb1 where nid = 1 or email = 'seven@live.com' and name = 'alex' - 類型不一致 若是列是字符串類型,傳入條件是必須用引號引發來,否則... select * from tb1 where name = 999; - != select * from tb1 where name != 'alex' 特別的:若是是主鍵,則仍是會走索引 select * from tb1 where nid != 123 - > select * from tb1 where name > 'alex' 特別的:若是是主鍵或索引是整數類型,則仍是會走索引 select * from tb1 where nid > 123 select * from tb1 where num > 123 - order by select email from tb1 order by name desc; 當根據索引排序時候,選擇的映射若是不是索引,則不走索引 特別的:若是對主鍵排序,則仍是走索引: select * from tb1 order by nid desc; - 組合索引最左前綴 若是組合索引爲:(name,email) name and email -- 使用索引 name -- 使用索引 email -- 不使用索引
一、Django的一個請求週期(請求和相應HTTP),請求和相應都是以字符串的形式 -- a、發送HTTP請求; -- b、服務器接收,根據請求頭中的URL在路由關係表中進行匹配(從上到下); -- c、匹配成功後,執行指定的views函數; 寫視圖函數的兩種方式:FBV CBV URL--》對應一個函數--》這種模式叫FBV url(r'login/', views.login) def login(request) URL--》對應一個類--》這種模式叫CBV 以POST方式發送請求,執行post方法,以GET方式發送請求,執行get方法; View類中有一個方法dispatch來根據請求方式判斷執行什麼方法,咱們能夠自定義這個方法 http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] from django.view import View class Cbv(View): def dispatch(self, request, *args, **kwargs): print('dispatch....') ret = super(Cbv,self).dispatch(request,*args,**kwargs) return ret def get(self,request): return render(request,'cbv.html') def post(self,request): return HttpResponse('cbv.post') urls.py: url(r'cbv/', views.CBV.as_view()) cbv.html: <body> <form action="/cbv/" method="POST"> <input type="text"/> <input type="submit"/> </form> </body> -- d、業務處理 -- 能夠根據我的需求自定製 -- 操做數據庫 - 原生SQL語句 - Django ORM ==最後獲得返回給用戶的結果== -- 響應內容 - 響應頭 - 響應體 響應頭沒有內容,咱們能夠主動給它返回內容 def post(self,request): ret = HttpResponse('cbv.post') ret['k1'] = 'v1' ret.set_cookie('k2','v2') ''' 頭:k1=v1 cookies:k2=v2 體:cbv.post ''' return ret 二、建立Django項目的基本流程 -- 建立新項目 -- 建立APP -- 建立static文件夾,settings配置靜態文件路徑 -- 註冊APP INSTALLED_APPS -- 建立templates文件夾,settings配置模板文件路徑 'DIRS': [os.path.join(BASE_DIR,'templates')], 三、ORM 多對多操做 #多對多添加,書籍類中有authors = models.ManyToManyField('Author') #增 book_obj = Book.objects.get(id=4) book_obj.authors.add(1) book_obj.authors.add(*[1,2,]) #刪 book_obj = Book.objects.get(id=4) book_obj.authors.remove(1) book_obj.authors.remove([1,2,]) book_obj.authors.clear() #重置,以設置的爲準,已經有的不動,新內容裏沒有的就刪除 book_obj.authors.set([1,2,3]) #查 #全部書籍名稱和對應的做者名 book_list = Book.objects.all().values('name','authors__name') #列舉ID=1的書籍的全部做者 #方式一 book_obj = Book.objects.get(id=1) aut_obj = book_obj.authors.all() #方式二 Book.objects.filter(id=1).values('authors__name') #列舉做者charlie的全部書籍 Book.objects.filter(authors__name="charlie") 四、跨多張表查詢 class Book(models.Model): '''書籍''' name = models.CharField(max_length=20) price = models.IntegerField() pub_data = models.DateField() authors = models.ForeignKey('Author',on_delete=models.CASCADE) class Author(models.Model): '''做者''' name = models.CharField(max_length=20) age = models.IntegerField(default=20) country = models.ForeignKey('Country',on_delete=models.CASCADE) class Country(models.Model): '''國家''' name = models.CharField(max_length=20) #全部中國籍做者出的全部書籍 Book.objects.filter(authors__country__name='China') # 列出做者Charlie出過的全部書籍 #正向查找:Book.objects.filter(authors__name='charlie') #反向查找: obj = Authors.objects.filter(name='charlie').first() obj.book_set.all() # 沒有外鍵的表裏其實隱藏了一個字段:類名_set,objects後面有的方法,它都有,也能夠修改這個名字; class Book(models.Model): authors = models.ForeignKey('Author',on_delete=models.CASCADE,related_name='book') obj = Authors.objects.filter(name='charlie').first() book_list = obj.book.all()# 做者對應的全部書籍對象查詢集[obj(name,price,..),obj(name,price,..),] # 下面兩個查詢結果至關於left join 查詢,以查詢的主表爲準,主表有的都顯示,主表有關聯表沒有的顯示爲None Book.objects.all().values('name','authors__name') Aurthor.objects.all().values('name','book__name') 五、QuerySet內部有三種數據類型: -- 字典:values()獲得,用['name']取值 -- 元組:value_list獲得 -- 對象:all\filter獲得,用點取值 六、-- 類表明數據庫表 -- 類的對象代指數據庫的一行記錄 -- ForeignKey字段代指關聯表中的一行數據(關聯類的對象) -- 正向:fk字段 -- 反向:小寫類名_set(默認),自定義ForeignKey(related_name='book') 通常不作反向查找,進行兩次SQL操做,效率低; 七、一對多:這兩種操做至關於left join 連表操做,以查詢的表爲主表,會顯示全部主表內容 Students.objects.all().values('name','classes__name') 顯示全部的學生信息,沒有學生的班級不顯示 Classes.objects.all().values('name','students_set__name') 顯示全部的班級信息,沒有學生的班級顯示None 八、select 標籤 - 單選 $().val() 獲取值 $().val(2) 設置值 - 多選 $().val([1,2,3]) 設置值,獲取也是val() 九、靜態文件夾模板 - js(js文件) - css(css文件) - plugins(bootstrap,font-awesome等插件) 十、JavaScript中把 對象轉換成字符串 -- str = JSON.stringify({'k':'v'}) 字符串轉換成對象 -- dict = JSON.parse(str) $.ajax({ url:'/del_student/', type:'GET', data:{nid:rowId}, datatype:'JSON',//ajax內部會自動轉換 success:function (arg) { //arg已是對象了 } }) 十一、jQuery事件委託 -- .on和.delegate()效果同樣,不過delegate前兩個參數要調換位置 $('要綁定標籤的上級標籤').on('click','要綁定的標籤',function(){})
python3中時間委託只有on,兩個效果雖然同樣,可是儘可能用on; 十二、總結 新URL方式(點擊跳轉到新的頁面): -- 獨立的頁面 -- 數據量大或條目多時,使用這個方便 對話框方式(ajax偷偷發送): -- 數據量小或條目少時使用 -- 此時添加數據,須要考慮當前頁、td中的自定義屬性 -- 數據量大時,工做量很大 若是不是強制要求使用對話框方式,建議使用新URL方式; 若是是刪除操做,建議用ajax方式; 1三、ajax發送checkbox數據,就是列表, var values = [1,2,3,4] $.ajax({ url:'/edit_student/', type:'POST', data:{'k':values}, traditional:true, success:function (arg){} }) error:function(){}//出錯自動觸發 views函數獲取數據方式: v = request.POST.getlist('k') 注意:data字典裏不能嵌套字典直接發送過去,若是非要發送須要JSON轉換一下 1四、使用serialize就能夠獲取整個form表單裏的全部數據,也是字典格式 $.ajax({ data:$('#fm').serialize(), }) 1五、XSS攻擊:跨站腳本攻擊,其實就是用戶寫了一段js代碼,讓其餘人訪問時執行這個腳本; 若是有人在博客下面評論輸入一下代碼,會直接影響其餘用戶瀏覽這篇博客, 你們都陷入一個死循環 <script> for(var i=0;i<9999;i++){ alert(i); } </script> 攻擊方式二: <script> 獲取本地cookie,發送到另一個網站或程序 </script> 1六、null=True,數據庫表中是否能夠爲空 blank=True,用戶輸入是否能夠爲空
二、使用原生sql語句從數據庫中按照年月篩選時間,及數量
# 首先在使用mysql語句的時候不能使用 GROUP BY 的解決方法(sqlite不存在此問題) Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column ‘userinfo.:解決辦法: mysql> set global sql_mode=‘STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION‘; mysql> set session sql_mode=‘STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION‘; # 第二:在mysql中時間格式化函數爲date_format(ctime,"%%Y-%%m")這裏兩個% 是爲了不django出現字符串參數確實報錯,若是不加%會報錯: return "<%s: %s>" % (self.__class__.__name__, self.query) File "C:\Python36\lib\site-packages\django\db\models\sql\query.py", line 110, in __str__ return self.sql % self.params_type(self.params) TypeError: not enough arguments for format string # 第三使用原生語句: select nid ,count(nid) as num, date_format(ctime,"%Y-%m") as create_time from repository_article group by date_format(ctime,"%%Y-%%m"); # 使用sqlite的寫法是: ‘select nid, count(nid) as num,strftime("%Y-%m",create_time) as ctime from repository_article group by strftime("%Y-%m",create_time)‘) # 這裏date_format(ctime,"%Y-%m") as create_time千萬不能寫成date_format(ctime,"%Y-%m") as ctime:由於自己ctime就是一個模塊,這裏若是寫成ctime,最後查詢的時候會報錯: File "C:\Python36\lib\site-packages\pytz\__init__.py", line 222, in localize if dt.tzinfo is not None: AttributeError: ‘str‘ object has no attribute ‘tzinfo‘
三、模板語言中調用方法不用加括號
# row表明classes對象,teachers爲classes表中的M2M字段 <td> {% for item in row.teachers.all %} <span>{{ item.name }}</span> {% endfor %} </td>
四、建立對象時也能夠拿到這個對象,也能夠直接獲取對象的id
obj = Classes.objects.create() obj.id
五、面試題
def func(arg,li=[]): li.append(arg) return li v1=func(1) # print(v1) #[1] v2=func(2,[]) # print(v2) #[2] v3=func(3) # print(v3) #[1, 3] # 代碼從上到下解釋的時候li=[]已經開闢了一塊內存 # v1和v3用的是同一塊內存 # v2從新開闢了一塊內存 print(v1) #[1, 3] print(v2) #[2] print(v3) #[1, 3] n1 = [1,2,3,4,5] n2 = n1 n3 = n1[:] n1[0] = 66 n3[1] = 99 #n1,n2指向同一塊內存,一塊兒改變 #切片會從新開闢一塊內存 print(n1) #[66, 2, 3, 4, 5] print(n2) #[66, 2, 3, 4, 5] print(n3) #[1, 99, 3, 4, 5]
六、admin中顯示的表名
class Meta: verbose_name_plural = '輪播圖'#admin顯示錶名沒有s
七、自動發送json數據的模塊
from django.http import JsonResponse ret = { 'status':True, 'data':course_list } #JsonResponse默認只能發送字典,若是是列表,須要加參數safe=False return JsonResponse(ret)
八、在views中反向生成URL
#reverse經過別名反向生成URL from django.urls import reverse # 參數是字典kwargs: {article_type_id:1} # 在views中 base_url = reverse('index',kwargs={article_type_id:1})#all/1.html # 在HTML模板語言中 {% url 「index」 article_type_id=1 %} # 參數是元組args=(1,) # 在views中 base_url = reverse('index',args=(1,)) # 在HTML模板語言中 {% url 「index」 1 %}
九、OneToOneField 反向查詢 request.user.userprofile.name 記得表名小寫
FK 反向查詢 request.user.userprofile_set.name 記得表名小寫
{{ request.user.userprofile.role.all }} {{ request.user.userprofile.role.select_related }} # 兩個功能同樣
十、動態獲取Django中全部的APP
from django import conf app_list = conf.settings.INSTALLED_APPS
十一、
# 經過數據庫中的類找到其所在的APP名字 app_name = model_class._meta.app_label # 經過數據庫中的類找到對應的表名 model_name = model_class._meta.model_name
十二、獲取choice中對應的文本
status_choices = ( (0, '未報名'), (1, '已報名'), (2, '已退學'), ) # 獲取choice中對應的文本 a = tb.objects.first() a.get_status_display() # 獲取choice對應的值 a.get_status
1三、獲取全部字段對象,obj._meta的用法,dir(obj._meta)查看全部方法
# 結果是一個列表,裏面是字段對象 models.CustomerInfo._meta.fields #獲取字段對象 column_obj = models.CustomerInfo._meta.get_field('字段名') column_obj.choices # ((0, '未報名'),(1, '已報名'),(2, '已退學'),) #經過判讀是否爲空來肯定該字段是否有選項 column_obj.get_choices() # [('','------'),(0, '未報名'),(1, '已報名'),(2, '已退學'),] # 獲取字段類型 column_obj.get_internal_type() # 找到對象關聯的全部對象,包括別人關聯你的和你關聯別人的FK、M2M obj._meta.related_objects
obj._meta.manay_to_many #獲取對象的M2M字段關聯的表 # 查看對象中全部的方法 dir(obj._meta)
1四、自定製admin
class CustomerAdmin(admin.ModelAdmin): list_display = ['id','name','contact_type','contact','source','consult_content'] list_filter = ['source','consultant','status','date'] search_fields = ['contact','consultant__name'] list_per_page = 2 # 每頁顯示條數 readonly_fields = ['status','contact'] # 不可編輯字段
1五、動態生成定製Form類,來完成數據庫表的修改、添加等驗證功能
from django.forms import ModelForm def create_dynamic_model_form(admin_class): """動態生成modelForm""" class Meta: model = admin_class.model fields = '__all__' def __new__(cls,*args,**kwargs): # cls.base_fields獲取數據庫表裏的全部字段名 for field_name in cls.base_fields: field_obj = cls.base_fields.get(field_name) # 定製生成的標籤的class屬性 field_obj.widget.attrs.update({'class':'form-control'}) return ModelForm.__new__(cls) # 由type建立一個form類,繼承ModelForm,而且有一個方法__new__、一個內嵌類Meta dynamic_form = type('DynamicModelForm',(ModelForm,),{'Meta':Meta,'__new__':__new__}) return dynamic_form
def table_obj_change(request,app_name,model_name,obj_id): """kingadmin:數據修改頁""" admin_class = site.enabled_admins[app_name][model_name] # 執行自動建立form類的函數 model_form = form_handle.create_dynamic_model_form(admin_class) # 找到當前修改對象,傳入form類驗證 obj = admin_class.model.objects.get(id=obj_id) if request.method == 'GET': form_obj = model_form(instance=obj) elif request.method == 'POST': form_obj = model_form(instance=obj,data=request.POST) if form_obj.is_valid(): form_obj.save() return redirect('/kingadmin/%s/%s/'%(app_name,model_name)) return render(request,'kingadmin/table_obj_change.html',locals())
# form_obj.instance能夠獲得修改的這一行的數據對象 <h4 class="page-header">修改{{ form_obj.instance }}</h4> <form class="form-horizontal" method="post" novalidate>{% csrf_token %} {% for field in form_obj %} <div class="form-group"> <label for="inputEmail3" class="col-sm-2 control-label">{{ field.label }}</label> <div class="col-sm-10"> {{ field }} <span style="color: red;">{{ field.errors.0 }}</span> </div> </div> {% endfor %} <div class="form-group"> <div class="col-sm-offset-11 col-sm-10"> <button type="submit" class="btn btn-info">Save</button> </div> </div> </form>
1六、經過反射獲取ModelForm驗證中當前字段對應的值
def get_obj_field_val(form_obj,field): """獲取model obj 具體字段的值""" return getattr(form_obj.instance,field)
1七、button按鈕,經常使用的bootstraip類,col-sm-offset-11 ---11表示水平向右移動11,能夠經過修改這個數值來變換button的位置
<div class="form-group"> <div class="col-sm-offset-11 col-sm-10"> <button type="submit" class="btn btn-info">Save</button> </div> </div>
1八、經過外鍵字段對象獲取關聯的數據庫表對應的類:field_obj.related_model
from django.template import Library register = Library() @register.simple_tag def get_available_m2m_data(field_name,form_obj,admin_class): """獲取M2M字段關聯表的全部數據""" # m2m字段對象 field_obj = admin_class.model._meta.get_field(field_name) # related_model獲取該M2M字段對應的表的類 # 把queryset轉換成集合set obj_list = set(field_obj.related_model.objects.all()) # 獲取已經選擇的M2M數據,一樣轉集合set selected_data = set(getattr(form_obj.instance, field_name).all()) # 取兩個集合的差集,獲得的是沒有選擇的M2M數據 return obj_list - selected_data
1九、
function beforeSubmit(ths) { $(":disabled").removeAttr('disabled'); //若是不想form表單提交,這裏return false,上邊onsubmit='return beforeSubmit(this)' //這兩個return是組合,缺一不可 }
20、
# 免除csrftoken驗證 from django.views.decorators.csrf import csrf_exempt @csrf_exempt def enrollment_fileupload(request,enrollment_id): """學員上傳文件""" return HttpResponse('success')
2一、
class Meta: abstract = True # 不建立表,只把字段傳遞給本身的子類
2二、在Django環境外調用其內部的數據庫,須要配置環境變量
# 在Django環境外調用其內部的數據庫,須要配置環境變量,下面三步缺一不可 os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'BlueShield.settings') import django django.setup()
2三、ajax提交數據如何經過csrftoken驗證,$.post(url,data,function(arg){})
2四、用Django本身的用戶認證,更多信息參考PerfectCRM項目
# settings.py # 告訴Django用本身定義的用戶認證表 AUTH_USER_MODEL = 'crm.UserProfile' # APP名+表名 # views.py from django.contrib.auth import authenticate,login,logout from django.contrib.auth.decorators import login_required def acc_login(request): """登錄頁面""" error_msg = '' if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') user = authenticate(username=username,password=password) if user: login(request,user) # 把用戶寫入session # 獲取login_required傳過來的參數,參數表示要跳轉的頁面,若是沒有,就跳轉到首頁 return redirect(request.GET.get('next','/kingadmin')) else: error_msg = '用戶名或密碼錯誤' return render(request,'kingadmin/login.html',{'error_msg':error_msg}) def acc_logout(request): """退出頁面""" logout(request) return redirect('/login') @login_required def table_obj_add(request,app_name,model_name)
2五、批量建立對象,models.tb.objects.bulk_create(obj_list)