1、表結構關係圖css
2、建表html
from django.db import models # Create your models here. from django.contrib.auth.models import AbstractUser class UserInfo(AbstractUser): """ 用戶信息表 """ phone = models.CharField(max_length=11, null=True, unique=True) # 手機號 avatar = models.FileField(upload_to="avatars/", default="avatars/default.png") # 頭像 blog = models.OneToOneField(to="Blog", null=True) def __str__(self): return self.username class Meta: verbose_name = "用戶信息" verbose_name_plural = verbose_name class Blog(models.Model): """ 博客信息 """ title = models.CharField(max_length=64) # 我的博客標題 theme = models.CharField(max_length=32) # 博客主題 def __str__(self): return self.title class Meta: verbose_name = "博客" verbose_name_plural = verbose_name class Category(models.Model): """ 我的博客文章分類 """ title = models.CharField(max_length=32) # 分類標題 blog = models.ForeignKey(to="Blog") # 外鍵關聯博客,一個博客站點能夠有多個分類 def __str__(self): return "{}-{}".format(self.blog.title, self.title) class Meta: verbose_name = "文章分類" verbose_name_plural = verbose_name class Tag(models.Model): """ 標籤 """ title = models.CharField(max_length=32) # 標籤名 blog = models.ForeignKey(to="Blog") # 所屬博客 def __str__(self): return self.title class Meta: verbose_name = "標籤" verbose_name_plural = verbose_name class Article(models.Model): """ 文章 """ title = models.CharField(max_length=50) # 文章標題 desc = models.CharField(max_length=255) # 文章描述 create_time = models.DateTimeField(auto_now_add=True) # 建立時間 category = models.ForeignKey(to="Category", null=True) # 文章分類 user = models.ForeignKey(to="UserInfo") # 做者 tags = models.ManyToManyField( # 文章的標籤 to="Tag", through="Article2Tag", through_fields=("article", "tag"), ) def __str__(self): return self.title class Meta: verbose_name = "文章" verbose_name_plural = verbose_name class ArticleDetail(models.Model): """ 文章詳情表 """ content = models.TextField() # 文章內容 article = models.OneToOneField(to="Article") class Meta: verbose_name = "文章詳情" verbose_name_plural = verbose_name class Article2Tag(models.Model): """ 文章和標籤的多對多關係表 """ article = models.ForeignKey(to="Article") tag = models.ForeignKey(to="Tag") def __str__(self): return "{}-{}".format(self.article, self.tag) class Meta: unique_together = (("article", "tag"),) verbose_name = "文章-標籤" verbose_name_plural = verbose_name class ArticleUpDown(models.Model): """ 點贊表 """ user = models.ForeignKey(to="UserInfo", null=True) article = models.ForeignKey(to="Article", null=True) is_up = models.BooleanField(default=True) # 點贊仍是踩滅 def __str__(self): return "{}-{}".format(self.user_id, self.article_id) class Meta: unique_together = (("article", "user"),) # 同一我的只能給一篇文章點一次贊 verbose_name = "點贊" verbose_name_plural = verbose_name class Comment(models.Model): """ 評論表 """ article = models.ForeignKey(to="Article") user = models.ForeignKey(to="UserInfo") content = models.CharField(max_length=255) # 評論內容 create_time = models.DateTimeField(auto_now_add=True) parent_comment = models.ForeignKey("self", null=True) # 本身關聯本身 def __str__(self): return self.content class Meta: verbose_name = "評論" verbose_name_plural = verbose_name
1.多對多三種實現方式前端
2.聯合惟一python
3、登陸jquery
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登陸</title> <link rel="stylesheet" href="/static/css/bootstrap/bootstrap3.3.7-min.css"> <link rel="stylesheet" href="/static/css/login.css"> </head> <body> <div class="container col-md-4 col-md-push-3"> <form class="form-horizontal" novalidate> {% csrf_token %} <div class="form-group"> <label class="col-sm-3 control-label" for="inputUser">用戶名:</label> <div class="col-sm-9"> <input type="text" class="form-control" id="inputUser" placeholder="請輸入用戶名" autofocus=""> </div> </div> <div class="form-group"> <label class="col-sm-3 control-label" for="inputPwd">密 碼:</label> <div class="col-sm-9"> <input type="password" class="form-control" id="inputPwd" placeholder="請輸入密碼"> </div> </div> <div class="form-group"> <label class="col-sm-3 control-label" for="inputVcode">驗證碼:</label> <div class="col-sm-4"> <input type="text" class="form-control" id="inputVcode" placeholder="請輸入驗證碼"> </div> <div class="col-sm-5" id="divImgVcode"> <img src="{% url 'v_code' %}" alt="" id="imgVcode"> </div> </div> <div class="form-group"> <div class="col-sm-offset-3 col-sm-3"> <div class="checkbox"> <label> <input type="checkbox" id="remember-me"> 記住我 </label> </div> </div> </div> <div class="form-group"> <div class="col-sm-push-4 col-sm-7"> <button type="button" class="btn btn-block btn-lg btn-info" id="btnLogin">登陸</button> <p id="pErrMsg"></p> </div> </div> </form> </div> <script src="/static/js/jquery/jquery3.3.1-min.js"></script> <script src="/static/js/setAjax.js"></script> <script> $("#btnLogin").click(function () { let username = $("#inputUser").val(); let password = $("#inputPwd").val(); let vCode = $('#inputVcode').val(); $.ajax({ url:{% url 'login' %}, type: 'post', data: { username: username, password: password, vcode:vCode, }, success: function (res) { if (res.code !== 0) { // 認證失敗 $("#pErrMsg").text(res.msg) } else { location.href = '{% url 'index' %}' } } }) }); $('input').focus(function () { $('#pErrMsg').text('') }); let orgUrlLenth = $('#imgVcode')[0].src.length; $('#imgVcode').click(function () { let timeStamp = new Date().valueOf(); this.src = this.src.substring(0, orgUrlLenth) + timeStamp; }) </script> </body> </html>
from django.shortcuts import render, redirect, HttpResponse from django.contrib.auth import authenticate, login, logout from django.contrib.auth.decorators import login_required from PIL import Image, ImageDraw, ImageFont, ImageFilter from django.http import JsonResponse from django import views from io import BytesIO import random # Create your views here. class Login(views.View): def get(self, request): return render(request, 'login.html') def post(self, request): res = {'code': 0} username = request.POST.get('username') password = request.POST.get('password') vcode = request.POST.get('vcode') if vcode.upper() != request.session.get('vcode').upper(): res['code'] = 1 res['msg'] = '驗證碼有誤' else: # auth認證 user = authenticate(request, username=username, password=password) if user: # 認證成功,進行登陸 login(request, user) else: res['code'] = 1 res['msg'] = '用戶名或密碼有誤' return JsonResponse(res) def v_code(request): # 隨機顏色,相對較淺 def random_color1(): return random.randint(64, 255), random.randint(64, 255), random.randint(64, 255) # 隨機顏色,相對較深 def random_color2(): return random.randint(32, 127), random.randint(32, 127), random.randint(32, 127) # 等機率隨機生成 n 個數字、字母(大小寫)組合的驗證碼列表 def random_code(n): rec_list = [] while n: n -= 1 rdm_first = random.randint(0, 1) if rdm_first == 0: rec_list.append(str(random.randint(0, 9))) else: rdm_second = random.randint(0, 1) if rdm_second == 0: rec_list.append(chr(random.randint(65, 90))) else: rec_list.append(chr(random.randint(97, 122))) return rec_list vcode_list = random_code(4) # 由最終驗證碼組成的字符串, 存入session中用來校驗 vcode = ''.join(vcode_list) request.session['vcode'] = vcode # 生成一張圖片 img_obj = Image.new( 'RGB', # 生成圖片的模式 (162, 33), # 大小 random_color1() # 顏色 ) # 生成一個畫筆,指定畫板爲img_obj draw_obj = ImageDraw.Draw(img_obj) # 加載本地字體文件,生成字體對象 font_obj = ImageFont.truetype('static/font/kumo.ttf', size=28) # 依次在畫板上寫上n個驗證碼 for i in range(len(vcode_list)): draw_obj.text( (i * 32 + 20, 0), # 座標 vcode_list[i], # 內容 fill=random_color2(), # 畫筆顏色,即字體顏色 font=font_obj, # 字體對象 ) # # 加干擾線 # width = 250 # 圖片寬度(防止越界) # height = 35 # for i in range(5): # x1 = random.randint(0, width) # x2 = random.randint(0, width) # y1 = random.randint(0, height) # y2 = random.randint(0, height) # draw_obj.line((x1, y1, x2, y2), fill=random_color()) # # # 加干擾點 # for i in range(40): # draw_obj.point([random.randint(0, width), random.randint(0, height)], fill=random_color()) # x = random.randint(0, width) # y = random.randint(0, height) # draw_obj.arc((x, y, x+4, y+4), 0, 90, fill=random_color()) # # 進行模糊處理 # img_obj = img_obj.filter(ImageFilter.BLUR) iof = BytesIO() # 生成IO句柄 img_obj.save(iof, 'png') # 把圖片對象放進IO句柄裏,即保存到內存中 data = iof.getvalue() # 從內存中讀取圖片數據 # 從服務器靜態文件夾內讀取圖片數據 # with open('static/img/oo.png', 'rb') as f: # data = f.read() return HttpResponse(data, content_type='image/png') @login_required def index(request): user_pro = request.user print(user_pro.userinfo.address) return HttpResponse('Index') def log_out(request): logout(request) return redirect('/login/')
from django.contrib import admin from django.urls import path, re_path from Authapp import views urlpatterns = [ path('admin/', admin.site.urls), path('login/', views.Login.as_view(), name='login'), path('index/', views.index, name='index'), path('logout/', views.log_out, name='logout'), re_path('v-code/\d*', views.v_code, name='v_code'), ]
STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static') ] LOGIN_URL = '/login/' AUTH_PROFILE_MODULE = 'Authapp.UserInfo'
注意:ajax
1. ajax,auth,bootstrap(組長教的) 正則表達式
python基礎 random.randint() 字母65-90、97-122 chr(數字) 顏色(0~255)三個一組(0,0,0)sql
2. 製做驗證碼數據庫
1.pillow import PILdjango
Image.new() img對象.filter(ImageFilter.BLUR)
ImageFont.truetype()
ImageDraw.Draw(img對象) draw對象.text() draw對象.line() draw對象.arc()
點擊切換驗證碼實現方式:
1.一直加?
2.加時間戳
3.加?刪?交替 import django.views.decorators.cache import never_cache (前段禁用緩存, 火狐瀏覽器有bug)
2.BytesIO
BytesIO()
img對象.save(IO對象,‘png等格式’)
IO對象.getvalue()
3.HttpResponse 能夠爲 src 提供資源
HttpResponse(data,content_type='image/png') 返回一張圖片
3.前段JS focus blur jQuery對象$(「 #id 」)[ 0 ] 對象DOM length substring()
Date().valueOf() p標籤 .text(" ") location.href="url" col-sm-offset-4 (push-pull)
3、註冊
1. 上傳頭像,前端
上傳文件的input 標籤
<input type="file" accept="image/*" id="inpAvatar">
2. 上傳頭像後臺(views視圖函數)
接收文件:
avatar_file = request.FILES.get("avatar")
保存註冊信息到數據庫:
models.UserInfo.objects.create_user(**form_obj.cleaned_data, avatar=avatar_file)
(由於是File文件,錄入數據庫時,會按字段保存路徑,按路徑找目錄保存文件)
3. 上傳頭像後臺(models模型層)
UserInfo表中:
avatar是一個FileField 字段,FileField(upload_to="avatars/",)
avatar具體保存的是一個路徑,而不是一個文件
具體保存文件的是:這個路徑對應的目錄(配置了media就另當別論)
(配置midia後)具體保存文件的目錄是:在上傳路徑前面拼接上media後的新路徑對應的目錄
3. 關於配置media(不配置就是上面的那樣)
關於static,經過settings設置別名,即讓別名表明其絕對路徑。放置可提供的靜態文件。
不能是全部文件都是能夠訪問的,涉及安全、泄密等問題。像用戶上傳的東西要有
指定的目錄存放。(部署時要作區分)(MEDIA_URL,MEDIA_ROOT是Django提供,也就是說別的就不認識了)
(這樣用戶上傳的文件是存放在media/ 下了,可是用戶數據庫中相關字段存的仍是原來的路徑,因此用時要拼接)
1.settings.py
MEDIA_URL = '/media/' (# 別名)
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') (只有一個目錄,不像static能夠添加多個)
(給用戶上傳的全部文件(FileField、request.FILES)指定一個存放目錄)
TEMPLATES 中添加上下文環境(可選配置)(自動把 MEDIA_URL 註冊到前端的模板中)
'django.template.context_processors.media', (這樣前端拼接時候,能夠作活路徑)
2.urls.py
from django.views.static import serve
re_path('^media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT})
4、主頁面、我的主頁、分類標籤歸檔頁
0.關於路由urls :各類路由都是開發者設計的。
1.評論點贊,bootstrap小圖標
<span class="glyphicon glyphicon-comment">評論({{ article.comment_count }})</span>
<span class="glyphicon glyphicon-thumbs-up">點贊({{ article.up_count }})</span>
2.模板中,時間格式化
模板語言,過濾器
<span>發佈於 {{ article.create_time|date:'Y-m-d H:i:s' }}</span>
3.二級路由 (名稱空間)
項目urls: from django.urls import include from app01 import urls as app01_urls (別名)
app01中urls: from django.urls import path from app01 import views
urlpatterns = [ 各類後續path ]
4.orm 插入原生sql語句
1.一半一半 (利用extra函數在執行orm查詢的同時,額外執行一段sql語句,子查詢)
2. 對象鏈接數據庫,光標對象執行原生sql
from django.db import connection
cusor = connection.cursor() # 鏈接數據庫,得到一個遊標對象
cursor.execute(" sql語句 ") # 遊標處:輸入sql語句
cursor.fetchall() # 取查詢結果
5. 分組、聚合
詳見 http://www.cnblogs.com/haiyan123/p/7745536.html
QuerySet.annotate() --> 分組,前面查的什麼字段,就按照什麼字段進行分組
分組時,給每一個組對象新添加:組屬性(組成員),例如annotate(c=Count(article__title))
分組是爲QuerySet中每個對象(即組名對象)生成一個獨立的彙總值
是對分組完以後的結果進行的聚合
QuerySet.aggregate() --> 聚合,給QuerySet中的每一個對象添加一個新屬性,給一個組進行聚合
是QuerySet 的一個終止子句(也就是返回的再也不是一個QuerySet集合的時候)
意思是說,它返回一個包含一些鍵值對的字典。鍵的名稱是聚合值的標識符,值是計算出來的聚合值。
鍵的名稱是按照 "字段名稱__聚合函數的名稱" 自動生成出來的。若是你想要爲聚合值指定一個名稱,能夠向聚合子句提供它。
6. 多條視圖路由整合一條
路由中正則表達式(無名分組、有名分組不可混合使用)(位置傳參必需要在關鍵字傳參前面)
re_path(r"(\d+)/mid/(\w+)",....) 寫了幾個分組就得匹配幾個參數,沒有就算匹配不到
5、文章詳情頁
1.模板繼承 {% extends "xx.html" %}
2.inclusion_tag
1. 返回一段HTML代碼,用數據填充的
2. 用法:
1. 在app下面建立一個名爲 templatetags 的Python Package
2. 寫個例如「mytags.py」:
from django import template
register = template.Library()
@register.inclusion_tag(file="xx.html")
def show_menu(*args):
... (此處不少查詢操做)
return {"k1" : "v1"}
(xx.html 中使用 k1這個變量)
(用這個自定義標籤只是爲了少書寫查詢語句的代碼,並無減小查詢次數)
3.點贊
1.orm事務操做
from django.db import transaction
with transaction.atomic():
sql1
sql2
2.模板語言
1.{{ xx }}表示的是單值,不在是變量了,
因此在js中用到這樣的值了,要用引號 "{{ request.user }}"
2.把 js 代碼寫入js文件中在導入的時候,由於render渲染時不會去渲染引入的js,因此要處理
(補)
4.QuerySet 惰性求值
1.len() 及 count()
2,.修改單個屬性,兩個方法的區別
3.debug-tool-bar
5.階段問題transaction.atomic() {% extends 'xx.html' %} {% load mytags %}{% func 'xx.html' %}
分組、聚合 F、Q js中正則包裹 /RegExp / RegExp.test(str) RegExp.exec(str)
6、文章評論
5、代碼集
def get_vcode(request): # 隨機顏色,相對較淺 def random_color1(): return random.randint(64, 255), random.randint(64, 255), random.randint(64, 255) # 隨機顏色,相對較深 def random_color2(): return random.randint(32, 127), random.randint(32, 127), random.randint(32, 127) # 等機率隨機生成 n 個數字、字母(大小寫)組合的驗證碼列表 def random_code(n): rec_list = [] while n: n -= 1 rdm_first = random.randint(0, 1) if rdm_first == 0: rec_list.append(str(random.randint(0, 9))) else: rdm_second = random.randint(0, 1) if rdm_second == 0: rec_list.append(chr(random.randint(65, 90))) else: rec_list.append(chr(random.randint(97, 122))) return rec_list vcode_list = random_code(4) # 由最終驗證碼組成的字符串, 存入session中用來校驗 vcode = ''.join(vcode_list) request.session['vcode'] = vcode # 生成一張圖片 img_obj = Image.new( 'RGB', # 生成圖片的模式 (162, 33), # 大小 random_color1() # 顏色 ) # 生成一個畫筆,指定畫板爲img_obj draw_obj = ImageDraw.Draw(img_obj) # 加載本地字體文件,生成字體對象 font_obj = ImageFont.truetype('static/font/kumo.ttf', size=28) # 依次在畫板上寫上n個驗證碼 for i in range(len(vcode_list)): draw_obj.text( (i * 32 + 20, 0), # 座標 vcode_list[i], # 內容 fill=random_color2(), # 畫筆顏色,即字體顏色 font=font_obj, # 字體對象 ) # # 加干擾線 # width = 250 # 圖片寬度(防止越界) # height = 35 # for i in range(5): # x1 = random.randint(0, width) # x2 = random.randint(0, width) # y1 = random.randint(0, height) # y2 = random.randint(0, height) # draw_obj.line((x1, y1, x2, y2), fill=random_color()) # # # 加干擾點 # for i in range(40): # draw_obj.point([random.randint(0, width), random.randint(0, height)], fill=random_color()) # x = random.randint(0, width) # y = random.randint(0, height) # draw_obj.arc((x, y, x+4, y+4), 0, 90, fill=random_color()) # # 進行模糊處理 # img_obj = img_obj.filter(ImageFilter.BLUR) iof = BytesIO() # 生成IO句柄 img_obj.save(iof, 'png') # 把圖片對象放進IO句柄裏,即保存到內存中 data = iof.getvalue() # 從內存中讀取圖片數據 # 從服務器靜態文件夾內讀取圖片數據 # with open('static/img/oo.png', 'rb') as f: # data = f.read() return HttpResponse(data, content_type='image/png')
ok