赞
踩
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), # 注册 path('register/', views.register), # 登录 path('login/', views.login), # 验证码 path('get_code/', views.get_code), # 首页路由 path('home/', views.home), # 退出系统 path('logout/', views.logout), # 修改密码 path('set_password/', views.set_password), # 放开media文件夹 re_path('media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}), # re_path('(?P<username>\w+)/category/(\d+)', views.site), # re_path('(?P<username>\w+)/tag/(\d+)', views.site), # re_path('(?P<username>\w+)/archive/(\w+)', views.site), # 优化以上三个路由 re_path('(?P<username>\w+)/(?P<condition>category|tag|archive)/(?P<param>.*)', views.site), re_path('(?P<username>\w+)', views.site), ]
from django.contrib import admin
from app01 import models
admin.site.register(models.UserInfo)
admin.site.register(models.Blog)
admin.site.register(models.Category)
admin.site.register(models.Article)
admin.site.register(models.Article2Tag)
admin.site.register(models.UpAndDown)
admin.site.register(models.Comment)
admin.site.register(models.Tag)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>首页</title> {% load static %} <script src="{% static 'js/jquery.min.js' %}"></script> <link href="{% static 'bootstrap/css/bootstrap.min.css' %}" rel="stylesheet"> <script src="{% static 'bootstrap/js/bootstrap.min.js' %}"></script> <script src="{% static 'layer/layer.js' %}"></script> {% block css %} {% endblock %} </head> <body> <nav class="navbar navbar-inverse"> <div class="container-fluid"> <!-- Brand and toggle get grouped for better mobile display --> <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="#">全球最大的博客网站</a> </div> <!-- Collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li class="active"><a href="#">文章 <span class="sr-only">(current)</span></a></li> <li><a href="#">分类</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="#">Separated link</a></li> <li role="separator" class="divider"></li> <li><a href="#">One more separated link</a></li> </ul> </li> </ul> <form class="navbar-form navbar-left"> <div class="form-group"> <input type="text" class="form-control" placeholder="Search"> </div> <button type="submit" class="btn btn-default">搜索</button> </form> <ul class="nav navbar-nav navbar-right"> {% if request.session.username %} <li style="line-height: 50px;"> <!-- /media/{ article.blog.userinfo.avatar }} --> {# <img class="media-object" src="/media/{{ article.blog.userinfo.avatar }}" style="width: 100px;" alt="..."> #} <img src="/media/{{ cur_avatar }}" style="width: 50px; height: 36px;" class="onImg" alt=""> </li> <li><a href="#">{{ request.session.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="#" data-toggle="modal" data-target=".bs-example-modal-lg">修改密码</a></li> <li><a href="#">更改头像</a></li> <li><a href="/logout/">退出登录</a></li> <li><a href="#">后台管理</a></li> </ul> </li> {% else %} <li><a href="/login/">登录</a></li> <li><a href="/register/">注册</a></li> {% endif %} </ul> <!-- 模态框 --> <div class="modal fade bs-example-modal-lg" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel"> <div class="modal-dialog modal-lg" role="document"> <div class="modal-content"> <div class="row"> <h1 class="text-center">修改密码</h1> <div class="col-md-8 col-md-offset-2"> <div class="form-group"> 用户名:<input type="text" readonly value="{{ request.session.username }}" class="form-control"> </div> <div class="form-group"> 原密码:<input type="password" id="old_password" class="form-control" msg="原密码必须输入"> </div> <div class="form-group"> 新密码:<input type="password" id="new_password" class="form-control" msg="原密码必须输入"> </div> <div class="form-group"> 确认密码:<input type="password" id="re_password" class="form-control" msg="原密码必须输入"> </div> <div class="form-group"> <input type="button" value="修改密码" class="btn btn-primary btn-block"> </div> </div> </div> </div> </div> </div> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> <!-- container-fluid 不留白,占据整个视图宽度和高度 --> <div class="container-fluid"> <div class="row"> {% block content %} <div class="col-md-2"> <div class="list-group"> <a href="#" class="list-group-item active"> 分类 </a> <a href="#" class="list-group-item">精华</a> <a href="#" class="list-group-item">候选</a> <a href="#" class="list-group-item">订阅</a> <a href="#" class="list-group-item">关注</a> </div> </div> <div class="col-md-7"> <!-- 媒体对象列表 --> <ul class="media-list"> {% for article in article_list %} <li class="media"> <h4 class="media-heading"><a href="">{{ article.title }}</a></h4> <div class="media-left"> <a href="#"> <img class="media-object" src="/media/{{ article.blog.userinfo.avatar }}" style="width: 100px;" alt="..."> </a> </div> <div class="media-body"> {{ article.desc }} </div> <br> <div> <!-- 文章查站点(外键字段建在文章表中),正向查询,通过外键查 article.blog --> <!-- 接着是站点查作者(外键字段在用户表),反向查询,通过表名小写 article.blog.userinfo.username --> <span style="margin-right: 10px;"><a href="">{{ article.blog.userinfo.username }}</a></span> <span style="margin-right: 10px;">{{ article.create_time|date:'Y-m-d' }}</span> <span style="margin-right: 10px;"><span class="glyphicon glyphicon-thumbs-up"></span>{{ article.up_num }}</span> <span style="margin-right: 10px;"> <span class="glyphicon glyphicon-thumbs-down"></span>{{ article.down_num }}</span> <span style="margin-right: 10px;"><span class="glyphicon glyphicon-comment"></span>{{ article.comment_num }}</span> </div> </li> <hr> {% endfor %} </ul> </div> <div class="col-md-3"> <!-- 带标题的面板 --> <div class="panel panel-info"> <div class="panel-heading">Panel heading without title</div> <div class="panel-body"> Panel content </div> </div> <div class="panel panel-success"> <div class="panel-heading">Panel heading without title</div> <div class="panel-body"> Panel content </div> </div> <div class="panel panel-danger"> <div class="panel-heading">Panel heading without title</div> <div class="panel-body"> Panel content </div> </div> </div> {% endblock %} </div> </div> <script> $(".btn").click(function () { // 1.获取参数 let old_password = $("#old_password").val(); let new_password = $("#new_password").val(); let re_password = $("#re_password").val(); // 2.参数验证 let ids = ['old_password', 'new_password', 're_password']; $.each(ids, function (index, value) { if (!$('#' + value).val()) { layer.msg($('#' + value).attr('msg')); return; } }); // 3.发起Ajax请求 $.ajax({ url: '/set_password/', type: 'post', data: { old_password: old_password, new_password: new_password, re_password: re_password, csrfmiddlewaretoken: '{{ csrf_token }}' }, success: function (res) { if (res.code === 200) { layer.msg(res.msg, {}, function () { location.reload(); }) } else { layer.msg(res.msg, {}); } } }); }); </script> </body> </html>
def home(request): ''' media文件的开放: 首先需要在配置文件 settings.py 中加入下面这行代码: MEDIA_ROOT = os.path.join(BASE_DIR, 'media') 以后再次注册账户的时候,图片就上传到 media/avatar 文件夹下了, 但是,当你在前端的 img 的 src="/media/{{ article.blog.userinfo.avatar }}", 还是不能显示图片,这也说名还没有开放 media 文件夹权限,需要在路由 urls.py 文件中 加入: from django.views.static import serve from django.conf import settings re_path('media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}), 这个时候图片才能正常的显示在页面 :param request: :return: ''' # 查询文章表的所有数据 article_list = models.Article.objects.all() try: cur_username = request.session.get('username') # print(cur_username) user_obj = models.UserInfo.objects.get(username=cur_username) # print(user_obj.avatar) cur_avatar = user_obj.avatar except: return redirect('/login/') return render(request, 'home.html', locals())
from django.db import models """ 先写普通字段 之后再写外键字段 """ from django.contrib.auth.models import AbstractUser # auth_user的扩展表(用户表) class UserInfo(AbstractUser): ''' null=True和blank=True的区别: null=True:代表的是数据库中字段可以为空 blank=True:后台系统表单的数据可以为空 ''' phone = models.BigIntegerField(verbose_name='手机号', null=True, blank=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, on_delete=models.CASCADE) # 元信息 class Meta: verbose_name_plural = '用户表' # 博客表 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 Meta: verbose_name_plural = '博客表' def __str__(self): return self.site_name # 分类表 class Category(models.Model): name = models.CharField(verbose_name='文章分类', max_length=32) blog = models.ForeignKey(to='Blog', null=True, on_delete=models.CASCADE) class Meta: verbose_name_plural = '分类表' def __str__(self): return self.name # 标签表 class Tag(models.Model): name = models.CharField(verbose_name='文章标签', max_length=32) blog = models.ForeignKey(to='Blog', null=True, on_delete=models.CASCADE) class Meta: verbose_name_plural = '标签表' def __str__(self): return self.name # 文章表 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.IntegerField(verbose_name='点赞数', default=0) down_num = models.IntegerField(verbose_name='点踩数', default=0) comment_num = models.IntegerField(verbose_name='评论数', default=0) # 外键字段 blog = models.ForeignKey(to='Blog', null=True, on_delete=models.CASCADE) category = models.ForeignKey(to='Category', null=True, on_delete=models.CASCADE) tags = models.ManyToManyField(to='Tag', through='Article2Tag', through_fields=('article', 'tag') ) class Meta: verbose_name_plural = '文章表' def __str__(self): return self.title # 半自动创建第三章表(文章、标签关联表) class Article2Tag(models.Model): article = models.ForeignKey(to='Article', on_delete=models.CASCADE) tag = models.ForeignKey(to='Tag', on_delete=models.CASCADE) class Meta: verbose_name_plural = '文章、标签关联表' # 点赞点彩 class UpAndDown(models.Model): user = models.ForeignKey(to='UserInfo', on_delete=models.CASCADE) article = models.ForeignKey(to='Article', on_delete=models.CASCADE) is_up = models.BooleanField() # 传布尔值 存0/1 class Meta: verbose_name_plural = '点赞点彩表' # 评论表 class Comment(models.Model): user = models.ForeignKey(to='UserInfo', null=True, on_delete=models.CASCADE) article = models.ForeignKey(to='Article', null=True, on_delete=models.CASCADE) 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, on_delete=models.CASCADE) # 有些评论就是根评论 class Meta: verbose_name_plural = '评论表'
{% extends 'home.html' %} {% block css %} <style> .s1 { margin-right: 10px; color: #999; } .content { font-size: 18px; color: #444; } </style> {% endblock %} {% block content %} <div class="col-md-3"> <div class="panel panel-info"> <div class="panel-heading">文章分类</div> <div class="panel-body"> {% for category in category_list %} <!-- 如果后台用的是values --> <p><a href="/{{ username }}/category/{{ category.2 }}">{{ category.0}} ({{ category.1 }})</a></p> <!-- 如果后台用的是values --> {# <p><a href="/{{ username }}/category/{{ category.pk }}">{{ category.name }} ({{ category.count_article_num }})</a></p>#} {% endfor %} </div> </div> <div class="panel panel-success"> <div class="panel-heading">文章标签</div> <div class="panel-body"> {% for tag in tag_list %} <p><a href="/{{ username }}/tag/{{ tag.2 }}">{{ tag.0 }} ({{ tag.1 }})</a></p> {% endfor %} </div> </div> <div class="panel panel-danger"> <div class="panel-heading">日期归档</div> <div class="panel-body"> {% for date in date_list %} {# <p><a href="">{{ date.0 }} ({{ date.1 }})</a></p> #} <p><a href="/{{ username }}/archive/{{ date.month|date:'Y-m' }}">{{ date.month|date:'Y年m月' }} ({{ date.count_article_nums }})</a></p> {% endfor %} </div> </div> </div> <div class="col-md-9"> {% for article in article_list %} <div> <h3><a href="">{{ article.title }}</a></h3> <div class="content"> {{ article.desc }} </div> <div style="margin-top: 10px;" class="pull-right"> <span class="s1">posted</span> <span class="s1">@</span> <span class="s1">{{ article.create_time|date:'Y-m-d' }}</span> <span class="s1">{{ article.blog.userinfo.username }}</span> <span class="s1"> <span class="glyphicon glyphicon-thumbs-up"></span> ({{ article.up_num }}) </span> <span class="s1"> <span class="glyphicon glyphicon-thumbs-down"></span> ({{ article.down_num }}) </span> <span class="s1"> <span class="glyphicon glyphicon-comment"></span> ({{ article.comment_num }}) </span> </div> <hr style="margin-top: 35px;"> <!-- 设置更大的上边距 --> </div> {% endfor %} </div> {% endblock %}
from django.db.models import Count from django.db.models.functions import TruncYear, TruncMonth, TruncDay, TruncDate # 个人站点 def site(request, username, **kwargs): # def site(request, username, condition, param): # def site(request, username): # re_path('(?P<username>\w+)/(?P<condition>category|tag|archive)/(?P<param>.*)>', views.site), # 由于路由中做了有名分组,所以需要参数传递给 site(username, condition, param) # 拿到了站点名称 # 做判断,拿着站点名称去查询用户信息,如果查到了,就可继续,否则返回404页面 user_obj = models.UserInfo.objects.filter(username=username).first() if not user_obj: ''' 图片防盗链:通过 Referer参数判断, 通过这个参数就可以知道你当前的地址是从哪个网页调过来的,然后做验证 ''' return render(request, '404.html') # 查询用户自己的所有文章(过滤当前站点的文章) blog = user_obj.blog article_list = models.Article.objects.filter(blog=blog).all() # print(article_list) # <QuerySet [<Article: xx1>, <Article: xx2>]> # print('kwargs', kwargs) # kwargs {'condition': 'category', 'param': '1'} if kwargs: condition = kwargs.get('condition') param = kwargs.get('param') if condition == 'category': # 按照分类搜索 文章查分类,正向查询,按字段查 article_list = article_list.filter(category__pk=param) elif condition == 'tag': # 按照标签来搜索 文章查标签 article_list = article_list.filter(tags__pk=param) elif condition == 'archive': # 按照日期来搜索 # kwargs: {'condition': 'archive', 'param': '2023-08'} year, month = param.split('-') article_list = article_list.filter(create_time__year=year, create_time__month=month) else: print('对不起,没有获取到相关数据') # 查询当前站点下的所有文章的分类 # category_list = models.Category.objects.filter(blog=blog).all() # 分类查文章数-->外键字段在文章,则反向查询,按表名小写 category_list = models.Category.objects.filter(blog=blog).annotate( count_article_num=Count('article__pk')).values_list('name', 'count_article_num', 'pk') print(category_list) # <QuerySet [('xn', 2)]> # category_list = models.Category.objects.filter(blog=blog).annotate( # count_article_num=Count('article__pk')).values('name', 'count_article_num', 'pk') # print(category_list) # <QuerySet [{'name': 'xn', 'count_article_num': 2}]> ''' values和values_list的区别: values的输出结果是列表套元组 如,<QuerySet [('xn', 2)]> 前端取值用 obj.0, obj.1, obj.2, ... values_list的输出结果是列表套字典 如,<QuerySet [{'name': 'xn', 'count_article_num': 2}]>, 前端取值用 obj.name, obj.count_article_num ''' # 查询当前站点下的所有标签列表 # 标签查文章 tag_list = models.Tag.objects.filter(blog=blog).annotate( count_article_num=Count('article__pk')).values_list('name', 'count_article_num', 'pk') print(tag_list) # 日期归档 ''' id title desc crate_time month 1 2023-08-15 2023-08 2 2023-08-15 2023-08 3 2023-08-06 2023-07 4 2023-08-15 2023-08 5 2023-08-11 2023-02 原生SQL:select date_format(create_time, 'Y-m') from article group by date_format(create_time, 'Y-m') -官方提供 from django.db.models.functions import TruncMonth Article.objects .annotate(month=TruncMonth('timestamp')) # Truncate to month and add to select list .values('month') # Group By month .annotate(c=Count('id')) # Select the count of the grouping .values('month', 'c') # (might be redundant, haven't tested) select month and count ''' # date_list = models.Article.objects.annotate( # month=TruncMonth('create_time')).values('month').filter(blog=blog).annotate( # count_article_nums=Count('pk')).values_list('month', 'count_article_nums') date_list = models.Article.objects.annotate( month=TruncMonth('create_time')).values('month').filter(blog=blog).annotate( count_article_nums=Count('pk')).values('month', 'count_article_nums') # print(date_list) # <QuerySet [{'month': datetime.date(2023, 8, 1), 'count_article_num': 2}]> ''' 侧边栏搜索功能 1.按照分类搜索 https://www.cnblogs.com/wupeiqi/category/850028.html 2.按照标签搜索 https://www.cnblogs.com/wupeiqi/tag/id/ 3.按照日期搜索 https://www.cnblogs.com/wupeiqi/archive/2018-08.html ''' return render(request, 'site.html', locals())
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。