""" 因爲django自帶的sqlite數據庫對日期不敏感,因此咱們換成MySQL """ from django.db import models # Create your models here. """ 先寫普通字段 以後再寫外鍵字段 """ from django.contrib.auth.models import AbstractUser class UserInfo(AbstractUser): phone = models.BigIntegerField(verbose_name='手機號',null=True) # 頭像 avatar = models.FileField(upload_to='avatar/',default='avatar/default.png',verbose_name='用戶頭像') """ 給avatar字段傳文件對象 該文件會自動存儲到avatar文件下 而後avatar字段只保存文件路徑avatar/default.png """ create_time = models.DateField(auto_now_add=True) blog = models.OneToOneField(to='Blog',null=True) class Blog(models.Model): site_name = models.CharField(verbose_name='站點名稱',max_length=32) site_title = models.CharField(verbose_name='站點標題',max_length=32) # 簡單模擬 帶你認識樣式內部原理的操做 site_theme = models.CharField(verbose_name='站點樣式',max_length=64) # 存css/js的文件路徑 class Category(models.Model): name = models.CharField(verbose_name='文章分類',max_length=32) blog = models.ForeignKey(to='Blog',null=True) class Tag(models.Model): name = models.CharField(verbose_name='文章標籤',max_length=32) blog = models.ForeignKey(to='Blog', null=True) class Article(models.Model): title = models.CharField(verbose_name='文章標題',max_length=64) desc = models.CharField(verbose_name='文章簡介',max_length=255) # 文章內容有不少 通常狀況下都是使用TextField content = models.TextField(verbose_name='文章內容') create_time = models.DateField(auto_now_add=True) # 數據庫字段設計優化 up_num = models.BigIntegerField(verbose_name='點贊數',default=0) down_num = models.BigIntegerField(verbose_name='點踩數',default=0) comment_num = models.BigIntegerField(verbose_name='評論數',default=0) # 外鍵字段 blog = models.ForeignKey(to='Blog', null=True) category = models.ForeignKey(to='Category',null=True) tags = models.ManyToManyField(to='Tag', through='Article2Tag', through_fields=('article','tag') ) class Article2Tag(models.Model): article = models.ForeignKey(to='Article') tag = models.ForeignKey(to='Tag') class UpAndDown(models.Model): user = models.ForeignKey(to='UserInfo') article = models.ForeignKey(to='Article') is_up = models.BooleanField() # 傳佈爾值 存0/1 class Comment(models.Model): user = models.ForeignKey(to='UserInfo') article = models.ForeignKey(to='Article') content = models.CharField(verbose_name='評論內容',max_length=255) comment_time = models.DateTimeField(verbose_name='評論時間',auto_now_add=True) # 自關聯 parent = models.ForeignKey(to='self',null=True) # 有些評論就是根評論
""" 咱們以前是直接在views.py中書寫的forms組件代碼 可是爲了接耦合 應該將全部的forms組件代碼單獨寫到一個地方 若是你的項目至始至終只用到一個forms組件那麼你能夠直接建一個py文件書寫便可 myforms.py 可是若是你的項目須要使用多個forms組件,那麼你能夠建立一個文件夾在文件夾內根據 forms組件功能的不一樣建立不一樣的py文件 myforms文件夾 regform.py loginform.py userform.py orderform.py ... """ def register(request): form_obj = MyRegForm() if request.method == 'POST': back_dic = {"code": 1000, 'msg': ''} # 校驗數據是否合法 form_obj = MyRegForm(request.POST) # 判斷數據是否合法 if form_obj.is_valid(): # print(form_obj.cleaned_data) # {'username': 'jason', 'password': '123', 'confirm_password': '123', 'email': '123@qq.com'} clean_data = form_obj.cleaned_data # 將校驗經過的數據字典賦值給一個變量 # 將字典裏面的confirm_password鍵值對刪除 clean_data.pop('confirm_password') # {'username': 'jason', 'password': '123', 'email': '123@qq.com'} # 用戶頭像 file_obj = request.FILES.get('avatar') """針對用戶頭像必定要判斷是否傳值 不能直接添加到字典裏面去""" if file_obj: clean_data['avatar'] = file_obj # 直接操做數據庫保存數據 models.UserInfo.objects.create_user(**clean_data) back_dic['url'] = '/login/' else: back_dic['code'] = 2000 back_dic['msg'] = form_obj.errors return JsonResponse(back_dic) return render(request,'register.html',locals()) <script> $("#myfile").change(function () { // 文件閱讀器對象 // 1 先生成一個文件閱讀器對象 let myFileReaderObj = new FileReader(); // 2 獲取用戶上傳的頭像文件 let fileObj = $(this)[0].files[0]; // 3 將文件對象交給閱讀器對象讀取 myFileReaderObj.readAsDataURL(fileObj) // 異步操做 IO操做 // 4 利用文件閱讀器將文件展現到前端頁面 修改src屬性 // 等待文件閱讀器加載完畢以後再執行 myFileReaderObj.onload = function(){ $('#myimg').attr('src',myFileReaderObj.result) } }) $('#id_commit').click(function () { // 發送ajax請求 咱們發送的數據中即包含普通的鍵值也包含文件 let formDataObj = new FormData(); // 1.添加普通的鍵值對 {#console.log($('#myform').serializeArray()) // [{},{},{},{},{}] 只包含普通鍵值對#} $.each($('#myform').serializeArray(),function (index,obj) { {#console.log(index,obj)#} // obj = {} formDataObj.append(obj.name,obj.value) }); // 2.添加文件數據 formDataObj.append('avatar',$('#myfile')[0].files[0]); // 3.發送ajax請求 $.ajax({ url:"", type:'post', data:formDataObj, // 須要指定兩個關鍵性的參數 contentType:false, processData:false, success:function (args) { if (args.code==1000){ // 跳轉到登錄頁面 window.location.href = args.url }else{ // 如何將對應的錯誤提示展現到對應的input框下面 // forms組件渲染的標籤的id值都是 id_字段名 $.each(args.msg,function (index,obj) { {#console.log(index,obj) // username ["用戶名不能爲空"]#} let targetId = '#id_' + index; $(targetId).next().text(obj[0]).parent().addClass('has-error') }) } } }) }) // 給全部的input框綁定獲取焦點事件 $('input').focus(function () { // 將input下面的span標籤和input外面的div標籤修改內容及屬性 $(this).next().text('').parent().removeClass('has-error') }) </script> # 擴展 """ 通常狀況下咱們在存儲用戶文件的時候爲了不文件名衝突的狀況 會本身給文件名加一個前綴 uuid 隨機字符串 ... """
""" img標籤的src屬性 1.圖片路徑 2.url 3.圖片的二進制數據 咱們的計算機上面致全部可以輸出各式各樣的字體樣式 內部其實對應的是一個個.ttf結尾的文件 http://www.zhaozi.cn/ai/2019/fontlist.php?ph=1&classid=32&softsq=%E5%85%8D%E8%B4%B9%E5%95%86%E7%94%A8 """ """ 圖片相關的模塊 pip3 install pillow """ from PIL import Image,ImageDraw,ImageFont """ Image:生成圖片 ImageDraw:可以在圖片上亂塗亂畫 ImageFont:控制字體樣式 """ from io import BytesIO,StringIO """ 內存管理器模塊 BytesIO:臨時幫你存儲數據 返回的時候數據是二進制 StringIO:臨時幫你存儲數據 返回的時候數據是字符串 """ import random def get_random(): return random.randint(0,255),random.randint(0,255),random.randint(0,255) def get_code(request): # 推導步驟1:直接獲取後端現成的圖片二進制數據發送給前端 # with open(r'static/img/111.jpg','rb') as f: # data = f.read() # return HttpResponse(data) # 推導步驟2:利用pillow模塊動態產生圖片 # img_obj = Image.new('RGB',(430,35),'green') # img_obj = Image.new('RGB',(430,35),get_random()) # # 先將圖片對象保存起來 # with open('xxx.png','wb') as f: # img_obj.save(f,'png') # # 再將圖片對象讀取出來 # with open('xxx.png','rb') as f: # data = f.read() # return HttpResponse(data) # 推導步驟3:文件存儲繁瑣IO操做效率低 藉助於內存管理器模塊 # img_obj = Image.new('RGB', (430, 35), get_random()) # io_obj = BytesIO() # 生成一個內存管理器對象 你能夠當作是文件句柄 # img_obj.save(io_obj,'png') # return HttpResponse(io_obj.getvalue()) # 從內存管理器中讀取二進制的圖片數據返回給前端 # 最終步驟4:寫圖片驗證碼 img_obj = Image.new('RGB', (430, 35), get_random()) img_draw = ImageDraw.Draw(img_obj) # 產生一個畫筆對象 img_font = ImageFont.truetype('static/font/222.ttf',30) # 字體樣式 大小 # 隨機驗證碼 五位數的隨機驗證碼 數字 小寫字母 大寫字母 code = '' for i in range(5): random_upper = chr(random.randint(65,90)) random_lower = chr(random.randint(97,122)) random_int = str(random.randint(0,9)) # 從上面三個裏面隨機選擇一個 tmp = random.choice([random_lower,random_upper,random_int]) # 將產生的隨機字符串寫入到圖片上 """ 爲何一個個寫而不是生成好了以後再寫 由於一個個寫可以控制每一個字體的間隙 而生成好以後再寫的話 間隙就無法控制了 """ img_draw.text((i*60+60,-2),tmp,get_random(),img_font) # 拼接隨機字符串 code += tmp print(code) # 隨機驗證碼在登錄的視圖函數裏面須要用到 要比對 因此要找地方存起來而且其餘視圖函數也能拿到 request.session['code'] = code io_obj = BytesIO() img_obj.save(io_obj,'png') return HttpResponse(io_obj.getvalue()) <script> $("#id_img").click(function () { // 1 先獲取標籤以前的src let oldVal = $(this).attr('src'); $(this).attr('src',oldVal += '?') }) </script>