zoukankan      html  css  js  c++  java
  • Python学习之路—2018/7/14

    Python学习之路—2018/7/12

    3.功能开发

    3.3 设计博客首页

    博客首页中最重要的就是中间的文章区域,所以我首先把文章区域设计出来,一开始并没有数据,如果用orm添加或者直接在数据库添加数据较为麻烦,这时候需要用到django提供的admin,在地址栏输入127.0.0.1:8000/admin,会看见如下的页面:

    这时候输入超级用户的账号和密码,超级用户通过终端输入python manage.py createsuperuser进行添加,登录过后是会看见如下页面:

    接下来在这个页面进行数据的添加,需要注意是添加的顺序,首先应该添加User表,加下来分别是Blog表、Sort表、Tag表,最后是Article表以及Article to tag表,评论表和点赞表可以暂时不填。添加完数据以后就开始设计博客主界面了。

    index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>博客首页</title>
        <link rel="icon" href="/static/blog/image/favicon.ico">
        <link rel="stylesheet" href="/static/blog/css/bootstrap.min.css">
        <link rel="stylesheet" href="/static/blog/css/index.css">
    </head>
    <body>
    <!--顶部导航栏-->
    <nav class="navbar navbar-default">
        <div class="container-fluid">
            <div class="navbar-header">
                <a class="navbar-brand" href="/index">博客园</a>
            </div>
            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                <ul class="nav navbar-nav">
                    <li><a href="#">新闻</a></li>
                    <li><a href="#">博文</a></li>
                </ul>
                <ul class="nav navbar-nav navbar-right">
                    {% if request.user.is_authenticated %}
                        <li><a href="#"><img src="/static/blog/image/user_log.png" id="user_log">{{ 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="#">修改密码</a></li>
                                <li role="separator" class="divider"></li>
                                <li><a href="#">修改头像</a></li>
                                <li role="separator" class="divider"></li>
                                <li><a href="/logout">注销</a></li>
                            </ul>
                        </li>
                    {% else %}
                        <li><a href="/register">注册</a></li>
                        <li><a href="/login">登录</a></li>
                    {% endif %}
    
                </ul>
            </div><!-- /.navbar-collapse -->
        </div><!-- /.container-fluid -->
    </nav>
    <!-- 主体内容 -->
    <div class="container-fluid">
        <div class="row">
            <!-- 左侧区域 -->
            <div class="col-md-3">
                <div class="panel panel-default">
                    <div class="panel-heading">Panel heading without title</div>
                    <div class="panel-body">
                        Panel content
                    </div>
                </div>
                <div class="panel panel-default">
                    <div class="panel-heading">
                        <h3 class="panel-title">Panel title</h3>
                    </div>
                    <div class="panel-body">
                        Panel content
                    </div>
                </div>
            </div>
            <!-- 中间文章区域 -->
            <div class="col-md-6">
                <div class="article_list">
                    {% for article in article_list %}
                        <div class="article_item">
                            <h5><a>{{ article.title }}</a></h5>
                            <div class="article_desc media-body">
                                <span class="media-left">
                                    <a href="/{{ article.user.username }}"><img src="/media/{{ article.user.avatar }}" id="user_avatar"></a>
                                </span>
                                <span class="media-right">{{ article.abstract }}</span>
                            </div>
                            <div class="article_foot small">
                                <span><a href="/{{ article.user.username }}">{{ article.user.username }}</a></span>   
                                <span>发布于 {{ article.create_time|date:"Y-m-d H:i"}}  </span>
                                <span><a><img src="/static/blog/image/comment.png">评论({{ article.comment_count }})</a> </span>
                                <span><a><img src="/static/blog/image/like.png">点赞({{ article.comment_count }})</a></span>
                            </div>
                        </div>
                        <hr>
                    {% endfor %}
                </div>
            </div>
            <!-- 右侧区域 -->
            <div class="col-md-3">1</div>
        </div>
    </div>
    </body>
    <script type="text/javascript" src="/static/blog/js/jquery-3.3.1.min.js"></script>
    <script type="text/javascript" src="/static/blog/js/bootstrap.min.js"></script>
    </html>
    

    index.css

    a:hover {
        cursor: pointer;
        text-decoration: none;
    }
    
    .login-head {
        margin-bottom: 10px;
        border-bottom: 1px solid #ddd;
    }
    
    .login-head a {
        margin-left: 287px;
        color: #5cb85c;
    }
    
    #avatar_img {
         60px;
        height: 60px;
        margin-left: 20px;
    }
    
    .error {
        color: red;
    }
    
    #user_log {
        margin-right: 5px;
    }
    
    #user_avatar {
         60px;
        height: 60px;
    }
    
    .article_foot {
        margin-top: 10px;
    }
    
    .article_foot img {
        vertical-align: -3px;
        margin-right: 2px;
    }
    

    views.py

    # 博客首页
    def index(request):
        article_list = Article.objects.all().order_by("-create_time")
        return render(request, "index.html", locals())
    
    # 注销
    def logout(request):
            auth.logout(request)
        return redirect("/login")
    

    urls.py

    urlpatterns = [
        path('index/', index),
    ]
    

    展示效果:

    3.4 设计个人站点首页

    由于个人站点以及后面的文章详情页他们的不同知识文章区域,所以为了避免重复的代码,首先设计一个模板页面,将需要用到的数据先规划好,个人站点需要名字、圆龄、随笔分类以及对应文章数量、标签分类以及对应的文章数量、时间分类以及对应的文章数量以及文章列表。

    base.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>{{ user.username }} - 博客园</title>
        <link rel="icon" href="/static/blog/image/favicon.ico">
        <link rel="stylesheet" href="/static/blog/css/bootstrap.min.css">
        <link rel="stylesheet" type="text/css" href="/static/blog/css/home_site.css">
        <style type="text/css">
            a:hover {
                cursor: pointer;
                text-decoration: none;
            }
            .panel-body a:hover {
                color: red;
            }
        </style>
    </head>
    <body>
    <div id="home">
        <div id="header">
            <div id="blogTitle">
                <h1><a href="/{{ user.username }}">{{ user.username }}</a></h1>
            </div>
            <div id="navigator">
                <ul id="navList">
                    <li><a href="/index">博客园</a></li>
                    <li><a href="/{{ username }}">首页</a></li>
                    <li><a>管理</a></li>
                </ul>
            </div>
        </div>
        <div id="main">
            <div class="col-md-3">
                {% load my_tags %}
                {% get_style username %}
            </div>
            <div class="col-md-9">
            {% block content %}
            {% endblock %}
            </div>
        </div>
    </div>
    </body>
    </html>
    

    首先介绍一下{% load my_tags %} {% get_style username %}

    在开发中,如果遇到视图与数据相结合作为模板的时候,可以使用inclusion_tag(xxx),它接受一个参数,这个参数是你需要渲染的html代码。步骤大概如下:

    1. 在项目中创建一个名为templatetags的包(名字必须是这个)

    2. 在templatetags的包中创建存放自定义标签的py文件

    3. my_tags.py

      from django import template
      from django.db.models import Count
      from django.db.models.functions import TruncMonth
      import datetime
      from blog.models import *
      
      register = template.Library()
      
      @register.inclusion_tag("get_style.html")  # get_style.html 即数据和视图相结合的Html部分
      def get_style(username):
          user = User.objects.filter(username=username).first()
          if user:
              blog = user.blog
      
              now = datetime.datetime.now()
              both = user.create_time
              day = (now - both).days
              age = int(day / 30)  # 园龄
      
              # 当前站点的每一个分类名称以及文章数
              sort_list = Sort.objects.filter(blog=blog).values("sid").annotate(
                  c=Count("article__aid")).values_list("title", "c")
      
              # 当前站点每个标签名称以及文章数
              tag_list = Tag.objects.filter(blog=blog).values("tid").annotate(
                  c=Count("article__aid")).values_list("name", "c")
      
              # 当前站点每一个年月的名称以及文章数
              # 方式一
              # 当用到较为复杂的sql查询语句时(例如日期的阶段,大小的比较),需要用到extra(select="")方法
              # date_list = Article.objects.filter(user=user).extra(
              #     select={"Y_m_date": "date_format(create_time, '%%Y年%%c月')"}).values("Y_m_date").annotate(
              #     c=Count("aid")).values_list("Y_m_date", "c")
      
              # 方式二,使用django封装的TruncMonth()方法,它会将日期截断到月,抛弃后面的,接下来只需要在html中通过date标签来格式化日期格式就OK了
              """
                  Article.objects.filter(user=user)
                  .annotate(Y_m_date=TruncMonth("create_time"))    将日期截断至月份并加入到字段中
                  .values("Y_m_date")    group by Y_m_date
                  .annotate(c=Count("aid"))   select count(aid) as c
                  .values_list("Y_m_date", "c")    select Y_m_date, c
              """
              date_list = Article.objects.filter(user=user) 
                  .annotate(Y_m_date=TruncMonth("create_time")) 
                  .values("Y_m_date") 
                  .annotate(c=Count("aid")) 
                  .values_list("Y_m_date", "c")
      
              return {"user": user, "blog": blog, "sort_list": sort_list, "tag_list": tag_list, "date_list": date_list, "age": age}  # 将所需数据存放在字典中传递给html部分
      
    4. get_style.html

      <div id="user_info">
          昵称:{{ user.username }}<br>
          园龄:{{ age }}个月
      </div>
      <div class="panel panel-primary">
          <div class="panel-heading">随笔分类</div>
          {% for sort in sort_list %}
              <div class="panel-body">
                  <a href="/{{ user.username }}/sort/{{ sort.0 }}">{{ sort.0 }}({{ sort.1 }})</a>
              </div>
          {% endfor %}
      </div>
      <div class="panel panel-primary">
          <div class="panel-heading">我的标签</div>
          {% for tag in tag_list %}
              <div class="panel-body">
                  <a href="/{{ user.username }}/tag/{{ tag.0 }}/">{{ tag.0 }}({{ tag.1 }})</a>
              </div>
          {% endfor %}
      </div>
      <div class="panel panel-primary">
          <div class="panel-heading">文章归档</div>
          {% for date in date_list %}
              <div class="panel-body">
                  <a href="/{{ user.username }}/date/{{ date.0|date:"Y-n" }}/">{{ date.0|date:"Y年n月" }}({{ date.1 }})</a>
              </div>
          {% endfor %}
      </div>
      
    5. home_site.html

      {% extends "base.html" %}
      
      {% block content %}
          {% for article in article_list %}
              <div class="article_item">
                  <div class="article_date">
                      {{ article.create_time|date:"Y月n月d日" }}
                  </div>
                  <div class="article_title">
                      <a>{{ article.title }}</a>
                  </div>
                  <div class="article_desc">
                      <span class="media-right">摘要:{{ article.abstract }}</span>
                  </div>
                  <div class="article_foot">
                       posted @ {{ article.create_time|date:"Y-m-d H:i" }} {{ user.username }}
                       评论({{ article.comment_count }}) 点赞({{ article.up_count }})
                  </div>
              </div>
          {% endfor %}
      {% endblock %}
      
    6. home_site.css

      * {
          margin: 0;
          padding: 0;
      }
      
      body {
          background: url('/static/blog/image/web_site_bk.jpg') fixed no-repeat;
          background-position: 50% 5%;
          background-size: cover;
          font-family: inherit;
      }
      
      #home {
          margin: 0 auto;
           80%;
          min- 980px;
          background-color: rgba(245, 245, 245, 0.7);
          padding: 30px;
          margin-top: 50px;
          margin-bottom: 50px;
          box-shadow: 0 2px 6px rgba(100, 100, 100, 0.3);
          overflow: hidden;
      }
      
      a {
          text-decoration: none;
      }
      
      a:visited, a:link {
          color: black;
      }
      
      #blogTitle {
          margin-bottom: 25px;
      }
      
      #blogTitle h1 {
          font-size: 36px;
          font-weight: bold;
          line-height: 1.8em;
          margin-top: 10px;
          margin-left: 35px;
      }
      
      #blogTitle a:hover {
          color: #ff4001;
      }
      
      #navigator {
          background-color: #009ACD;
          height: 60px;
          line-height: 60px;
          overflow: hidden;
          clear: both;
          float: left;
      }
      
      #navList {
          min-height: 30px;
          float: left;
          margin-right: 579px;
      }
      
      #navList li {
          float: left;
          list-style: none;
      }
      
      #navList li:hover {
          background-color: #343434;
      }
      
      #navList a {
          display: block;
          padding: 0 1.5em;
          height: 60px;
          float: left;
          font-size: 1.2em;
          text-align: center;
          transition-duration: 0.3s;
          color: #eee;
      }
      
      #navList a:hover {
          text-decoration: none;
      }
      
      #blogStats {
          float: right;
          padding-right: 10px;
          text-align: right;
          color: #eee;
      }
      
      #main {
          min- 950px;
          text-align: left;
          padding: 20px 0 0 10px;
          overflow: hidden;
      }
      
      #user_avatar {
           60px;
          height: 60px;
          margin-left: 20px;
      }
      
      .article_item {
          min-height: 10px;
          box-shadow: 1px 1px 2px #A7A8AD;
          color: #666666;
          margin: 0 5px 60px 0;
          padding: 5px 20px 10px;
          background: rgba(255, 255, 255, 0.5)
      }
      
      .article_title {
          border-left: 8px solid rgba(33, 160, 139, 0.68);
          margin-left: 10px;
          margin-bottom: 10px;
          font-size: 20px;
          float: right;
           100%;
          clear: both;
          font-weight: bold;
          border-bottom: 1px dashed #ccc;
          line-height: 2.5em;
          padding-left: 10px;
      }
      
      .article_title a:hover {
          margin-left: 20px;
      }
      
      .article_desc {
          margin-top: 70px;
      }
      
      .article_date {
           100%;
          color: black;
          line-height: 2.2em;
          font-size: 22px;
          clear: both;
          border-bottom: 1px solid #ccc;
          text-align: center;
      }
      
      .article_foot {
          color: #757575;
           100%;
          clear: both;
          text-align: left;
          font-size: 13px;
          margin-top: 20px;
          line-height: 1.8;
          padding-bottom: 20px;
      }
      
      #user_info {
          border-radius: 7px;
          box-shadow: 1px 1px 2px #A7A8AD;
          color: black;
          padding: 15px 15px 10px;
          background: rgba(255, 255, 255, 0.5);
          margin-bottom: 30px;
      }
      
      .panel {
          background: rgba(255, 255, 255, 0.5);
          margin-bottom: 30px;
      }
      
      .panel-heading {
          font-size: 20px;
      }
      
      .panel-body {
          border-bottom: 1px solid white;
      }
      
    7. views.py

    def home_site(request, username, **kwargs):
        """
        个人站点
        :param request:
        :param username:
        :return:
        """
        user = User.objects.filter(username=username).first()
        if user:
            article_list = Article.objects.filter(user=user)
            # 当前的站点下的所有文章
            # 基于对象查询   article_list = user.article_set.all()
            # 基于双下划线查询
            if kwargs:
                condition = kwargs.get("condition")
                parm = kwargs.get("parm")
                if condition == "sort":
                    article_list = article_list.filter(sort__title=parm)
                elif condition == "tag":
                    article_list = article_list.filter(tag__name=parm)
                elif condition == "date":
                    year = parm.split("-")[0]
                    month = parm.split("-")[1]
                    article_list = article_list.filter(create_time__year=year, create_time__month=month)
            article_list = article_list.order_by("-create_time")
    
            return render(request, "home_site.html", locals())
        else:
            return render(request, "404.html")
    

    urls.py

    urlpatterns = [
    	# 个人站点查询
        re_path(r'^(?P<username>w+)/$', home_site),
        # 个人站点跳转
        re_path(r'^(?P<username>w+)/(?P<condition>sort|tag|date)/(?P<parm>.*)/$', home_site),
    ]
    

    展示效果:

    它的顺序是:

    1. 在自定义的标签中,首先会执行代码,将数据传递给inclusion_tag(xxx)参数中的html,即get_style.html
    2. get_style.html根据传来的数据完成自身的渲染
    3. base.html中调用inclusion_tag 标签的部分完成渲染,即添加get_style.html内容
    4. 个人站点页面继承模板页面,最终呈现

    注意:

    • 利用inclusion_tag完成数据与视图的结合
    • 个人站点url的跳转(例如点击分类会出现当代当前分类的所有文章)主要通过给每个分类/标签/时间添加a标签,指向url,而在视图函数中通过增加参数来完成筛选,将筛选后的文章列表传递给html
    • 当只需要用到datetime的个别元素,例如年月,可以使用django的Trunc函数,例如TruncMonth只会截断到月,剩余的日时分秒不会被取到
    • 避免过多的重复代码

    实现效果:

  • 相关阅读:
    .NET简谈设计模式之(适配器模式)
    .NET简谈组件程序设计之(手动同步)
    .NET简谈组件程序设计之(初识远程调用)
    .NET简谈组件程序设计之(初识.NET线程Thread)
    .NET映射设计(Model与UIControl之间的模型关系)
    .NET简谈事务本质论
    .NET简谈组件程序设计之(异步委托)
    向5.4致敬吧 无为而为
    SQL 2005 分析服务基于角色的动态授权 无为而为
    文思创新深圳招聘biztalk 无为而为
  • 原文地址:https://www.cnblogs.com/ExBurner/p/9308099.html
Copyright © 2011-2022 走看看