blog开发day3+Django admin的简单使用
实例
url.py
"""cnblog_prew URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/2.0/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: path('', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin from django.urls import path,re_path from app01 import views from django.views.static import serve from django.conf import settings urlpatterns = [ path('admin/', admin.site.urls), #使用FBV来写的格式 path('login/', views.Login.as_view()), #注销用户 path('logout/', views.logout), path('get_valid_pic/', views.get_valid_pic), path('index/', views.index), #极验滑动验证码 获取验证码的url path('pc-geetest/register/', views.get_geetest), #注册 path('register/', views.register), # 专门用来校验用户名是否已被注册的接口 path('check_username_exist/', views.check_username_exist), #media相关的路由设置 re_path('media/(?P<path>.*)$', serve, {"document_root": settings.MEDIA_ROOT}), ]
views.py
from django.shortcuts import render,redirect,HttpResponse
from django.http import JsonResponse
# Create your views here.
from django.views import View
from django.contrib import auth
from django.contrib.auth.decorators import login_required
from geetest import GeetestLib
from app01 import forms,models
#极验 登录验证码
# 请在官网申请ID使用,示例ID不可使用
pc_geetest_id = "b46d1900d0a894591916ea94ea91bd2c"
pc_geetest_key = "36fc3fe98530eea08dfc6ce76e3d24c4"
def get_valid_pic(request):
from PIL import Image,ImageDraw,ImageFont
import random
#生乘随机的RGB
def random_color():
return (random.randint(0,255),random.randint(0,255),random.randint(0,255))
#生成随机背景色 对象
image = Image.new("RGB",(270,37),random_color())
#给图片添加内容
draw = ImageDraw.Draw(image)
font = ImageFont.truetype("static/fontAwesome/fonts/song.ttf", 28)
temp = []
for i in range(5):
random_low = chr(random.randint(97,122))
random_upper = chr(random.randint(65,90))
random_digit = str(random.randint(0,9))
random_choose = random.choice([random_low,random_upper,random_digit])
draw.text((40+40*i,0),random_choose,random_color(),font=font)
temp.append(random_choose)
# 在内存中生成图片
from io import BytesIO
f = BytesIO()
image.save(f, "png")
data = f.getvalue()
f.close()
valid_str = ''.join(temp)
request.session['valid_str'] = valid_str
return HttpResponse(data)
class Login(View):
def get(self, request):
return render(request, 'login2.html')
def post(self, request):
username = request.POST.get('username')
password = request.POST.get('password')
#获取极验滑动验证码相关的参数
gt = GeetestLib(pc_geetest_id, pc_geetest_key)
challenge = request.POST.get(gt.FN_CHALLENGE, '')
validate = request.POST.get(gt.FN_VALIDATE, '')
seccode = request.POST.get(gt.FN_SECCODE, '')
status = request.session[gt.GT_STATUS_SESSION_KEY]
user_id = request.session["user_id"]
if status:
result = gt.success_validate(challenge, validate, seccode, user_id)
else:
result = gt.failback_validate(challenge, validate, seccode)
res = {'state': False, 'msg': None}
if result:
# 验证码正确
# 用户认证
user = auth.authenticate(username=username, password=password)
auth.login(request, user) #将登陆用户赋值给 request.user
if user:
res['state'] = True
else:
res['msg'] = '用户名密码错误!'
else:
res['msg'] = '验证码错误'
return JsonResponse(res)
#这个装饰器实现的功能是,之前登录过index的可以直接登录,没登录过的就跳转到login页面
#注意要在settings.py中 LOGIN_URL = '/login/' # 这里配置成你项目登录页面的路由
# @login_required
def index(request):
# 查询所以的文章列表
article_list = models.Article.objects.all()
return render(request,'index.html',{'article_list':article_list})
# 注销
def logout(request):
auth.logout(request)
return redirect('/index/')
#处理极验 获取验证码
def get_geetest(request):
user_id = 'test'
gt = GeetestLib(pc_geetest_id, pc_geetest_key)
status = gt.pre_process(user_id)
request.session[gt.GT_STATUS_SESSION_KEY] = status
request.session["user_id"] = user_id
response_str = gt.get_response_str()
return HttpResponse(response_str)
def register(request):
if request.method == "POST":
#status 是0表示 没出错 1 表示出错
res = {"status":0,"msg":""}
form_obj = forms.RegForm(request.POST)
#帮我做校验
if form_obj.is_valid():
#验证通过
#所以的数据都保存在form_obj.cleaned_data中 一个大字典
form_obj.cleaned_data.pop("re_password") #删除字典中re_password 因为数据库中没有这个属性
#数据库中的头像数据是默认的,所以自己拿 新的
avatar_img = request.FILES.get("avatar")
#在数据库中创建数据
models.UserInfo.objects.create_user(**form_obj.cleaned_data,avatar=avatar_img)
res["msg"] = '/index/'
return JsonResponse(res)
else:
#把错误信息存起来
res["msg"] = form_obj.errors
res["status"] = 1
# print(res) #类似于 {'status': 1, 'msg': {'email': ['邮箱不能为空'], 're_password': ['两次密码输入不一致']}}
return JsonResponse(res)
form_obj = forms.RegForm()
return render(request,'register.html',{"form_obj":form_obj})
#校验用户名是否已被注册
def check_username_exist(request):
res = {"status":0,"msg":""}
username = request.GET.get("username")
is_exist = models.UserInfo.objects.filter(username=username)
if is_exist:
#用户名已被注册
res["status"] = 1
res["msg"] = "用户名已被注册!"
return JsonResponse(res)
settings.py
#Django用户上传的都叫media文件
MEDIA_URL = "/media/"
# media配置,用户上传的文件都默认放在这个文件夹下
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
AUTH_USER_MODEL = "app01.UserInfo"
index.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>index</title> <meta name="viewport" content="width=device-width, initial-scale=1"> {% load static %} <link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap.min.css' %}"> <link rel="stylesheet" href="{% static 'fontAwesome/css/font-awesome.min.css' %}"> <link rel="stylesheet" href="{% static 'sweetalert/sweetalert.css' %}"> <link rel="stylesheet" href="{% static 'mystyle.css' %}"> </head> <body> {#导航条开始#} <nav class="navbar navbar-inverse"> <div class="container-fluid"> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">My Blog</a> </div> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li> <li><a href="#">Link</a></li> </ul> <ul class="nav navbar-nav navbar-right"> {% if request.user.username %} {# 登陆的用户显示#} <li><a href="#">{{ request.user.username }}</a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">个人中心 <span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#">Action</a></li> <li><a href="#">Another action</a></li> <li><a href="#">Something else here</a></li> <li role="separator" class="divider"></li> <li><a href="/logout/">注销</a></li> </ul> </li> {% else %} {# 没登录的用户显示#} <li><a href="/login/">登陆</a></li> <li><a href="/register/">注册</a></li> {% endif %} </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> {#导航条结束#} {#主页面开始#} <div class="container" style="width: 90%"> <div class="row"> <div class="col-md-2"> <div class="panel panel-primary"> <div class="panel-heading">左侧广告栏一</div> <div class="panel-body"> Panel content </div> </div> <div class="panel panel-info"> <div class="panel-heading">左侧广告栏二</div> <div class="panel-body"> Panel content </div> </div> </div> <div class="col-md-8"> {# 文章列表 开始#} <div class="article-list"> {% for article in article_list %} <div class="article"> {#标题#} <h3><a href="">{{ article.title }}</a></h3> {# 简介#} <div class="media"> <div class="media-left"> <a href="#"> <img class="media-object author-img" src="/media/{{ article.user.avatar }}" alt="..."> </a> </div> <div class="media-body"> <p>{{ article.desc }}</p> </div> </div> {#作者名#} <div class="article-footer"> <span><a href="">{{ article.user.username }}</a></span>发布于 <span>{{ article.create_time|date:'Y-m-d H:i:s' }}</span> {#反向查询#} {#<span class="glyphicon glyphicon-comment" aria-hidden="true">评论({{ article.comment_set.all.count }})</span>#} <span class="glyphicon glyphicon-comment" aria-hidden="true">评论({{ article.comment_count }})</span> <span class="glyphicon glyphicon-thumbs-up" aria-hidden="true">点赞({{ article.up_count }})</span> </div> </div> {% endfor %} </div> {# 文章列表 结束#} </div> <div class="col-md-2"> <div class="panel panel-primary"> <div class="panel-heading">右侧广告栏一</div> <div class="panel-body"> Panel content </div> </div> <div class="panel panel-info"> <div class="panel-heading">右侧广告栏二</div> <div class="panel-body"> Panel content </div> </div> </div> </div> </div> {#主页面结束#} <script src="{% static 'jquery-3.2.1.min.js' %}"></script> <script src="{% static 'setupajax.js' %}"></script> <script src="{% static 'bootstrap/js/bootstrap.min.js' %}"></script> <script src="{% static 'sweetalert/sweetalert.min.js' %}"></script> </body> </html>
models.py中Article修改:
class Article(models.Model):
"""
文章
"""
nid = models.AutoField(primary_key=True)
title = models.CharField(max_length=50) # 文章标题
desc = models.CharField(max_length=255) # 文章描述
create_time = models.DateTimeField() # 创建时间
#评论数
comment_count = models.IntegerField(verbose_name="评论数",default=0)
#点赞数
up_count = models.IntegerField(verbose_name="点赞数",default=0)
#踩
down_count = models.IntegerField(verbose_name="差评数",default=0)
category = models.ForeignKey(to="Category", to_field="nid", null=True,on_delete=models.CASCADE)
user = models.ForeignKey(to="UserInfo", to_field="nid",on_delete=models.CASCADE,default=None)
tags = models.ManyToManyField( # 中介模型
to="Tag",
through="Article2Tag",
through_fields=("article", "tag"), # 注意顺序!!!
)
def __str__(self):
return self.title
注意:
要注意这里面的media的配置
先在settings.py中添加:
#Django用户上传的都叫media文件
MEDIA_URL = "/media/"
# media配置,用户上传的文件都默认放在这个文件夹下
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
后再urls.py中添加:
from django.views.static import serve from django.conf import settings
#media相关的路由设置 re_path('media/(?P<path>.*)$', serve, {"document_root": settings.MEDIA_ROOT}),