部落格園專案開發中的難點
阿新 • • 發佈:2018-11-15
1.註冊檢視
一般註冊是通過form表單形式post提交資料,資料一般通過class欄位過濾值看clean_data來獲取的
過濾欄位類(放在view視圖裡)
class UserForm(forms.Form): user=forms.CharField(max_length=32, error_messages={"required":"該欄位不能為空"}, label="使用者名稱", widget=widgets.TextInput(attrs={"class":"form-control"},) ) pwd=forms.CharField(max_length=32, label="密碼", widget=widgets.PasswordInput(attrs={"class":"form-control"},) ) re_pwd=forms.CharField(max_length=32, label="確認密碼", widget=widgets.PasswordInput(attrs={"class":"form-control"},) )
通過註冊的post按鈕進行相應的ajax請求從而clean_data,顯示錯誤或者是重複的欄位
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"> <script src="/static/js/jquery-3.2.1.min.js"></script> <style> #avatar_img { margin-left: 20px; } #avatar { display: none; } .error { color: red; } </style> </head> <body> <h3>註冊頁面</h3> <div class="container"> <div class="row"> <div class="col-md-6 col-lg-offset-3"> <form id="form"> {% csrf_token %} {% for field in form %} <div class="form-group"> <label for="{{ field.auto_id }}">{{ field.label }}</label> {{ field }} <span class="error pull-right"></span> </div> {% endfor %} <div class="form-group"> <label for="avatar"> 頭像 <img id="avatar_img" width="60" height="60" src="/static/blog/img/default.png" alt=""> </label> <input type="file" id="avatar" name="avatar"> </div> <input type="button" class="btn btn-default reg_btn" value="submit"><span class="error"></span> </form> </div> </div> </div> <script> // 頭像預覽 $("#avatar").change(function () { // 獲取使用者選中的檔案物件 var file_obj = $(this)[0].files[0]; // 獲取檔案物件的路徑 var reader = new FileReader(); reader.readAsDataURL(file_obj); // 修改img的src屬性 ,src=檔案物件的路徑 reader.onload = function () { $("#avatar_img").attr("src", reader.result) }; }); // 基於Ajax提交資料 $(".reg_btn").click(function () { //console.log($("#form").serializeArray()); var formdata = new FormData(); var request_data = $("#form").serializeArray(); console.log(request_data); $.each(request_data, function (index, data) { formdata.append(data.name, data.value) }); formdata.append("avatar", $("#avatar")[0].files[0]); console.log('formdata',formdata); $.ajax({ url: "", type: "post", contentType: false, processData: false, data: formdata, success: function (data) { //console.log(data); if (data.user) { // 註冊成功 location.href="/login/" } else { // 註冊失敗 //console.log(data.msg) // 清空錯誤資訊 $("span.error").html(""); $(".form-group").removeClass("has-error"); // 展此次提交的錯誤資訊! $.each(data.msg, function (field, error_list) { console.log(field, error_list); if (field=="__all__"){ $("#id_re_pwd").next().html(error_list[0]).parent().addClass("has-error"); } $("#id_" + field).next().html(error_list[0]); $("#id_" + field).parent().addClass("has-error"); }) } } }) }) </script> </body> </html>
2.登入檢視
form表單形式,判斷頁面的請求方式post or get
def login(request): if request.method == 'POST': print(2) response = {'user':None, 'msg':None} user = request.POST.get('user',None) print(user,'user') pwd = request.POST.get('pwd', None) valid_code = request.POST.get('valid_code', None) print('valid_code',valid_code) # print('request', request) check_true = request.session.get("check") print("check_true",check_true) if valid_code.upper() == check_true.upper(): print(1) user = auth.authenticate(username=user,password=pwd) # 自動去user(django自動生成)表裡去校驗 if user: auth.login(request, user) response['user'] = user.username else: response['msg']='密碼輸入錯誤' else: response['msg']='驗證碼錯誤' return JsonResponse(response) return render(request,'login.html')
@login_required 若檢視方法巢狀此裝飾器,且setting中設定 LOGIN_URL="/login/" 進入檢視自動跳轉至登入介面先登入才能進入檢視
登入校驗也是基於ajax實現的(校驗密碼跟驗證碼)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>LOGIN</title> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"> </head> <body> <div id="content"> <div> <div id="head" class="col-md-6 col-lg-offset-3"> <form action=""> {% csrf_token %} <div class="form-group"> <label for="user">賬號</label> <input type="text" id="user" class="form-control"> </div> <div class="form-group"> <label for="pwd">密碼</label> <input type="password" id="pwd" class="form-control"> </div> <div class="form-group"> <label for="pwd">驗證碼</label> <div class="row"> <div class="col-md-6"> <input type="text" class="form-control" id="valid_code"> </div> <div class="col-md-6"> <img width="270" height="36" id="valid_code_img" src="/get_validCode_img/" alt=""> </div> </div> </div> <input type="button" class="btn btn-default login_btn" value="submit"><span class="error"></span> <a href="/register/" class="btn btn-success pull-right">註冊</a> </form> </div> </div> </div> </body> <script src="/static/js/jquery-3.2.1.min.js/"></script> <script> $("#valid_code_img").click(function () { {#console.log($(this)[0]);#} $(this)[0].src += "?" }); $('.login_btn').click( function () { $.ajax({ url:'', type:'post', data:{ user:$('#user').val(), pwd:$('#pwd').val(), valid_code:$('#valid_code').val(), csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val() }, success: function (data) { console.log(data); if (data.user) { if (location.search){ location.href = location.search.slice(6) } else { location.href = "/index/" } } else { $(".error").text(data.msg).css({"color": "red", "margin-left": "10px"}); setTimeout(function(){ $(".error").text(""); },1000) } } }) }) </script> </html>
登入的驗證碼生成
隨機數生成字母與數字結合的驗證碼(字型設定),顏色是基於(255,255,255)隨機生成,通過pillow(PIL)生成驗證碼圖片,並通過session儲存傳輸校驗。
def create_img(request): img = Image.new('RGB',(270,40),color=color_yeild()) draw = ImageDraw.Draw(img) kumo_font = ImageFont.truetype('static/font/kumo.ttf',size=32) check_digit = '' for i in range(5): random_num = str(random.randint(0,9)) random_low_alpha = chr(random.randint(95, 122)) random_upper_alpha = chr(random.randint(65, 90)) random_char = random.choice([random_num, random_low_alpha, random_upper_alpha]) draw.text((i*50+20,5),random_char,color_yeild(),kumo_font) check_digit += random_char # print('check_digit',check_digit) request.session["check"] = check_digit f = BytesIO() img.save(f, 'png') data = f.getvalue() # with open('wudi.png','wb') as f: # img.save(f,'png') # f = open('wudi.png','rb') # import json # data = json.dumps(img) return HttpResponse(data)
# 隨機生成顏色
def color_yeild(): result = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) return result
3.登出檢視
def logout(request): auth.logout(request) return redirect('/login/')
通過超連結跳轉的方式進入檢視
<ul class="nav navbar-nav navbar-right"> {% if request.user.is_authenticated %} <li><a href="#"><span id="user_icon" class="glyphicon glyphicon-user"></span>{{ request.user.username }}</a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#">修改密碼</a></li> <li><a href="#">修改頭像</a></li> <li><a href="/cn_backend/">管理</a></li> <li><a href="/logout/">登出</a></li> <li role="separator" class="divider"></li> <li><a href="#">Separated link</a></li> </ul> </li> {% else %} <li><a href="/login/">登入</a></li> <li><a href="/register/">註冊</a></li> {% endif %}
4.home_site檢視
通過正則分組獲取相應的條件
re_path('^(?P<username>\w+)/(?P<condition>tag|category|archive)/(?P<param>.*)/$', views.home_site),
傳進檢視函式內
進行各方面判斷
def home_site(request, username, **kwargs): print("usename1", username) user = UserInfo.objects.filter(username=username).first() if not user: return HttpResponse('404') blog = user.blog article_list = Article.objects.filter(user=user) # article_list = models.Article.objects.filter(user=user) if kwargs: print("kwargs",kwargs) condition = kwargs.get("condition") param = kwargs.get("param") # 2012-12 if condition == "category": print(11111111111111111111111111111) article_list = article_list.filter(category__title=param) elif condition == "tag": print(222222222222222222222222222222) article_list = article_list.filter(tags__title=param) else: year, month = param.split("/") article_list = article_list.filter(create_time__year=year, create_time__month=month) return render(request,"home_site.html",{"username": username, "blog": blog, "article_list": article_list,})
5.點贊檢視
點贊檢視是基於ajax進行資料庫判斷是否登入使用者已經進行過點贊操作(每篇文章都有相應的點贊操作)
<script> // 點贊請求 $("#div_digg .action").click(function () { var is_up = $(this).hasClass("diggit"); $obj = $(this).children("span"); $.ajax({ url: "/digg/", type: "post", data: { "csrfmiddlewaretoken": $("[name='csrfmiddlewaretoken']").val(), //ajax操作在上面建立csrf(位置都可以,form,div) "is_up": is_up, "article_id": "{{ article_obj.pk }}", }, success: function (data) { console.log(data); if (data.state) { var val = parseInt($obj.text()); $obj.text(val + 1); } else { var val = data.handled ? "您已經推薦過!" : "您已經反對過!"; //三元表示式 if 條件?如果成立就是冒號前的,反之冒號後面的 $("#digg_tips").html(val); setTimeout(function () { $("#digg_tips").html("") }, 1000) } } }) })
檢視傳出布林資料來判斷是否點贊過
def digg(request): """ 點贊檢視 :param request: :return: """ import json if request.is_ajax(): print("點贊", request.POST) is_up = json.loads(request.POST.get("is_up")) # ajax傳輸過來是網頁獲取為布林,傳輸自動json過,所以需要json反解碼 article_id = request.POST.get("article_id") user_id = request.user.pk obj = ArticleUpDown.objects.filter(user_id=user_id, article_id=article_id).first() print("objqueryset", obj) response = {"state":True} if not obj: art = ArticleUpDown.objects.create(user_id=user_id, is_up=is_up, article_id=article_id) queryset1 = Article.objects.filter(pk=article_id) print("queryset", queryset1) if is_up: queryset1.update(up_count=F("up_count")+1) print(1111111111111111111111111111) else: queryset1.update(down_count=F("down_count")+1) print(1111111111111111111111111111) else: response["state"] = False response["handled"] = obj.is_up return JsonResponse(response)
6.評論檢視
評論也是基於點選事件的ajax請求
// 評論請求 var pid = ""; $(".comment_btn").click(function () { var content = $("#comment_content").val(); if (pid) { var index = content.indexOf("\n"); content = content.slice(index + 1) } $.ajax({ url: "/comment/", type: "post", data: { "csrfmiddlewaretoken": $("[name='csrfmiddlewaretoken']").val(), "article_id": "{{ article_obj.pk }}", "content": content, pid: pid }, success: function (data) { console.log(data); var create_time = data.create_time; var username = data.username; var content = data.content; var s = ` <li class="list-group-item"> <div> <span>${create_time}</span> <a href=""><span>${username}</span></a> </div> <div class="comment_con"> <p>${content}</p> </div> </li>`; $("ul.comment_list").append(s); // 清空評論框 pid = "", $("#comment_content").val(""); } }) });
下面的檢視函式包括評論郵件部分的內容,郵件部分程式碼邏輯正確但是實現不了
def comment(request): """ 提交評論檢視函式 功能: 1 儲存評論 2 建立事務 3 傳送郵件 :param request: :return: """ print(request.POST) article_id = request.POST.get("article_id") pid = request.POST.get("pid") content = request.POST.get("content") user_id = request.user.pk article_obj = Article.objects.filter(pk=article_id).first() # 事務操作 comment_obj = Comment.objects.create(user_id=user_id, article_id=article_id, content=content, parent_comment_id=pid) print("comment_obj",comment_obj) Article.objects.filter(pk=article_id).update(comment_count=F("comment_count") + 1) response = {} response["create_time"] = comment_obj.create_time.strftime("%Y-%m-%d %X") response["username"] = request.user.username response["content"] = content # 傳送郵件 from django.core.mail import send_mail from blog_project import settings #send_mail(1,2,"[email protected]",["[email protected]"], fail_silently=False) # send_mail( # "您的文章%s新增了一條評論內容"%article_obj.title, # content, # settings.EMAIL_HOST_USER, # # settings.EMAIL_HOST_PASSWORD, # ["[email protected]"] # ) # print("settings.EMAIL_HOST_USER",settings.EMAIL_HOST_USER) import threading print("article_obj.title", article_obj.title) print("content", content) t = threading.Thread(target=send_mail, args=("您的文章%s新增了一條評論內容" % article_obj.title, content, settings.EMAIL_HOST_USER, ["[email protected]"]) ) t.start() return JsonResponse(response)
郵件部分的setting
EMAIL_HOST = 'smtp.exmail.qq.com' # 如果是 163 改成 smtp.163.com EMAIL_PORT = 465 EMAIL_HOST_USER = '@qq.com' # 帳號 EMAIL_HOST_PASSWORD = '' # 密碼 為郵箱的授權碼 # DEFAULT_FROM_EMAIL = EMAIL_HOST_USER EMAIL_USE_SSL = True