• 博客项目——〇二首页设计


    首页的设计我们就按照简化的博客园的效果来搞!但是利用了Bootstrap的框架。大概思路是这样的

     最上面是导航条,然后下面是左中右的方式按照2-8-2的布局来分。

    导航条

     导航条我们就用Bootstrap里给的基础的样式就可以,

     注意右边的a标签,如果当前状态是已经登录的话就是上面的样式,如果没有登录,就是一个登录和一个注册。

    <!-- 导航条开始 -->
    <nav class="navbar navbar-default">
        <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>
      
    
          <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="/blog/{{request.user.username}}">我的博客</a></li>
                  <li><a href="#">短消息</a></li>
                  <li><a href="#">设置</a></li>
                  <li><a href="/logout/">注销</a></li>
                </ul>
              </li>
              {%else%}
              <li><a href="/login/">登录</a></li>
              <li><a href="/signup/">注册</a></li>
              
            {%endif%}
    
            </ul>
          </div><!-- /.navbar-collapse -->
        </div><!-- /.container-fluid -->
      </nav>
      <!-- 导航条结束 -->
    导航条部分代码

    注意里面的判断的结构。对当前的登录状态进行用户校验。

    主页框架

     最上面的那个图中,我们就按照2-8-2的布局进行排列,结构就像下面的代码所示

    <!-- 主体开始 -->
    <div class="container-fluid">
    <div class="row">
        <div class="col-md-2 left-body"></div>
        <div class="col-md-8 main-body"></div>
        <div class="col-md-2 right-body"></div>
    </div>
    </div>
    <!-- 主体结束 -->

    左右侧的部分我们可以用来显示一些辅助内容,例如广告、分类什么的。下面就是这一节最主要的部分,模板的填充。

    显示内容的主页

    和博客园一样,在主页里我们用来显示所有的文章 。

    这里先把main-body里的html代码放出来,我们一步步来分析

     1 <!-- 文章列表  开始 -->
     2 <div class="article_list">
     3 {% for article in article_list %}
     4     <div class="article">
     5     <h3><a href="">{{article.title}}</a></h3>
     6     <div class="media">
     7         <div class="media-left">
     8         <a href="#">
     9             <img class="media-object author-img" src="/media/{{article.user.avatar}}" alt="...">
    10         </a>
    11         </div> 
    12         <div class="media-body">
    13         {{article.desc}}
    14         </div>
    15         <div class="article-footer">
    16         <span><a href="">{{article.user.username}}</a></span>
    17         <span>发布于{{article.create_time|date:'Y-m-d H:i:s'}}</span>
    18         <span class="glyphicon glyphicon-comment">评论({{article.comment_count}})</span>
    19         <span class="glyphicon glyphicon-thumbs-up">点赞({{article.up_count}})</span>
    20         <span class="glyphicon glyphicon-thumbs-down">踩灭({{article.down_count}})</span>
    21         </div>
    22     </div>
    23     </div>
    24 {% endfor %}
    25 </div>
    26 <!-- 文章列表  结束 -->

    这个模板对应的视图很简单,只有一行代码就行了

    def home(request):
        article_list = models.Article.objects.all()return render(request,'home.html',{'article_list':article_list})

    也就是说整个过程就是我们在视图中通过ORM索引到所有的文章列表,然后把这个列表render给主页的模板。先看一下显示出来的效果

     

    上面的图就是通过模板渲染出来的效果。下面对几个模板使用的知识点分析一下。

    模板使用

    这里使用了Bootstrap组件的媒体对象的默认样式,左边一个头像,右边放p标签或者span标签来显示相应内容。

     就是在上面的列表中通过for循环生成的代码段。

    <div class="media">
      <div class="media-left">
        <a href="#">
          <img class="media-object" src="..." alt="...">
        </a>
      </div>
      <div class="media-body">
        <h4 class="media-heading">Media heading</h4>
        ...
      </div>
    </div>

    我们只需要显示出来文章中下面几条内容就可以了

     看一下models里对于文章Article是怎么定义的

    class Article(models.Model):
        """
        文章
        """
        nid = models.AutoField(primary_key=True)
        title = models.CharField(max_length=50, verbose_name="文章标题")  # 文章标题
        desc = models.CharField(max_length=255)  # 文章描述
        create_time = models.DateTimeField()  # 创建时间  --> datetime()
    
        # 评论数
        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)
        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

    这里就要我们回顾一下ORM里的两种数据查询方法了:

    基于对象的查询和基于QuerySet的查询

    看一下下面的代码段,我们回顾一下前面的ORM的查询方式

    # ORM基于对象的查询和基于QuerySet的查询方法
    
    
    import os
    
    if __name__ =='__main__':
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BLOG.settings")
        import django
        django.setup()
    
    
        from blog import models
    
        #基于对象的查询:SQL里的子查询(select里嵌套select)
    
        ret = models.Article.objects.first()
        print(ret.user,type(ret.user))   #123 <class 'blog.models.UserInfo'>
        # ret.user是一个对象,就可以直接用对象+.的形式来获取我们需要的内容,像下面一样
        print(ret.user.username)
        print(ret.user.avatar)
    
        #基于QuerySet的方式查询:SQL里的join查询
        ret2 = models.Article.objects.filter(nid = 1)
        print(ret2,type(ret2))
        # <QuerySet [<Article: 博客项目——〇一需求分析(占位)>]> <class 'django.db.models.query.QuerySet'>
        avatar = ret2.values('user__avatar')
        print(avatar)
    ORM基于对象查询和基于QuerySet查询

    为了便于我们在模板中获取相应的数据,先通过all()方法获取到一个QuerySet对象(article_list),在通过render函数的时候,我们用for循环把这个拿到具体的article对象,就可以用基于对象的方式获取到所需要的内容

    标题
    {{article.title}}
    简介
    {{article.desc}}
    头像
    {{article.user.avatar}}

    头像图片的获取

    如果仅仅通过下面的代码是显示不了头像的

    <img class="media-object author-img" src="{{article.user.avatar}}" alt="...">

    这样图片是无法打开的

    检查一下页面上的img标签属性,能发现图片的url是没问题的:http://127.0.0.1:8000/home/avatar/img/hmbb.png,而所有用户上传的头像都放在了根目录下的avatar文件夹中。把这个url复制到地址栏中,f直接访问一下是没有任何效果的

    但是如果把这个文件放在static文件夹里,是可以通过url直接访问的(截图太大就不掩饰了,放一个访问css文件的截图)。

    因为我们在settings.py里指定了静态文件的路径和URL

    STATIC_URL = '/static/'
    STATICFILES_DIRS = [
        os.path.join(BASE_DIR,'static')
    ]

    如果把这个注释掉,就没办法访问了。这样就流出了可以通过URL访问的一些文件的接口,没有暴露的是无法访问的。而静态文件是每次浏览器都要去拿到然后渲染出效果的。这样就保护了我们的代码文件。

    在这里我们就做另外一个路径:在Django里,所有用户上传的文件都叫做media,所以我们需要把在settings.py中对media的属性进行设置

    #Django 用户上传的文件都叫media文件
    MEDIA_URL = '/media/'
    #media配置,用户上传的文件都放在这个文件夹下
    MEDIA_ROOT = os.path.join(BASE_DIR,'media')

    然后新建一个文件夹,把原先的avatar这个文件夹拖进去

     这样就完成了第一步,访问一下这个路径http://127.0.0.1:8000/media/avatars/hmbb.png,发现还是404报错,因为我们这个media的相关路由还没有设置,必须要新指定(STATIC不用手动指定路由是因为STATIC里的静态文件基本上是浏览器在渲染页面的时候必须用的,所有在Django内部就直接设定好了)

    记得要先导入serve模块,下面的语法直接记住就行了。

    from django.views.static import serve
    from django.conf import settings
    
    url(r'^media/(?P<path>.*)$',serve,{'document_root':settings.MEDIA_ROOT})    #设置静态文件路由

    发布时间的显示

    发布时间我们用了一个模板中的tag,前面应该有的

    {{article.create_time|date:'Y-m-d H:i:s'}}

    最后通过一个css文件指定了一下margin-left,避免所有标签挤在一起不美观

    最后把整个html文件放下面

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">
        <link rel="stylesheet" href="/static/css/home.css">
        <title>BLOG主页</title>
    </head>
    <body>
    
    
    <!-- 导航条开始 -->
    <nav class="navbar navbar-default">
        <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>
      
    
          <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="/blog/{{request.user.username}}">我的博客</a></li>
                  <li><a href="#">短消息</a></li>
                  <li><a href="#">设置</a></li>
                  <li><a href="/logout/">注销</a></li>
                </ul>
              </li>
              {%else%}
              <li><a href="/login/">登录</a></li>
              <li><a href="/signup/">注册</a></li>
              
            {%endif%}
    
            </ul>
          </div><!-- /.navbar-collapse -->
        </div><!-- /.container-fluid -->
      </nav>
      <!-- 导航条结束 -->
    
    
    
    
    
      <!-- 主体开始 -->
      <div class="container-fluid">
        <div class="row">
            <div class="col-md-2">
                <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-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">
                        {{article.desc}}
                      </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">评论({{article.comment_count}})</span>
                        <span class="glyphicon glyphicon-thumbs-up">点赞({{article.up_count}})</span>
                        <span class="glyphicon glyphicon-thumbs-down">踩灭({{article.down_count}})</span>
                      </div>
                    </div>
                  </div>
                {% endfor %}
              </div>
              <!-- 文章列表  结束 -->
    
            </div>
            <div class="col-md-2">
    
                <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>
      </div>
    
    
      <script src="/static/jquery-3.2.1.min.js"></script>
      <script src="/static/bootstrap/js/bootstrap.min.js"></script>
    
    </body>
    </html>
    home.html
    数据的添加

     在前面讲数据可视性操作的时候讲过了怎么添加数据,因为整个数据结构互相牵扯的比较多,简易还是从admin页面里添加新的数据,但是要记得修改admin文件,把所有的model都注册了

    from django.contrib import admin
    from blog import models
    # Register your models here.
    admin.site.register(models.UserInfo)
    admin.site.register(models.Article)
    admin.site.register(models.Blog)
    admin.site.register(models.Tag)
    admin.site.register(models.Category)
    admin.site.register(models.Comment)
    admin.site.register(models.ArticleUpDown)
    admin.site.register(models.ArticleDetail)
    admin.site.register(models.Article2Tag)

    对Article新加几条数据,就能在主页上显示出来

    用户管理页面

     由于在导航栏里有用户管理功能,用户的注册和登录方法我们在前面已经讲过了,这里就把代码直接放出来了,不在过多解释。

    FORM组件

    在注册的页面里我只用了一部分form组件,但是还是把一些以后可能会用到的字段放出来了,便于以后的使用,登录的页面未使用这个form组件

    """
    用到的form类
    """
    from django import forms
    from django.core.exceptions import ValidationError
    
    from . import models
    
    class RegForm(forms.Form):
        username = forms.CharField(
            max_length=16,
            label='用户名',
            error_messages={
                'max_length': '用户名最长为16位!',
                'required': '用户名不能为空!'
            },
            widget=forms.widgets.TextInput(
                attrs={
                    'class': 'form-control'
                }
            )
        )
    
        password = forms.CharField(
            min_length=6,
            label='密    码',
            widget=forms.widgets.PasswordInput(
                attrs={
                    'class': 'form-control'
                }
            ),
            error_messages={
                'min_length': '密码不能少于6位!',
                'required': '密码不能为空!'
            }
        )
    
        re_password = forms.CharField(
            max_length=32,
            label='确认密码',
            widget=forms.widgets.PasswordInput(
                attrs={
                    'class': 'form-control'
                }
            ),
            error_messages={
                'max_length': '用户名最长为16位!',
                'required': '用户名不能为空!'
            }
        )
    
        email = forms.EmailField(
            label='邮箱',
            widget=forms.widgets.EmailInput(
                attrs={
                    'class': 'form-control'
                }
            ),
            error_messages={
                'invalid': '邮箱格式不正确',
                'required': '邮箱不能为空'
            }
        )
    # #重构局部的钩子对username字段进行校验
        def clean_username(self):
            username = self.cleaned_data.get('username')
            user = models.UserInfo.objects.filter(username=username)
            if user:
                self.add_error('username',ValidationError('用户名已存在!'))
    
            return username #一定记得加这个返回值,否则在视图中cleaned_data里返回值为空
    
    #重写全局钩子,对确认密码进行校验
        def clean(self):
            username = self.cleaned_data.get('username')
            pwd = self.cleaned_data.get('password')
            re_pwd = self.cleaned_data.get('re_password')
    
    
            if re_pwd and re_pwd != pwd:
                self.add_error('re_password',ValidationError("两次密码不一致"))
    
            else:
                return self.cleaned_data
     
    form.py

    form里的局部钩子一定一定要记得加返回值,在调试的过程中忘记加返回值了,拿到cleaned_data的时候一直显示username为null,搞了快一天才高清是怎么回事。

    用户管理视图

    我把所有用户管理方面的视图都放在了一个py文件里,便于后期的维护

    # user_manage.py
    #用户管理视图
    
    
    from django.shortcuts import render,redirect,HttpResponse
    from django.contrib import auth
    from django.http import JsonResponse
    from . import models,forms
    
    from django.views import View
    
    
    #注册
    def signup(request):
        if request.method == 'POST':
            print(request.POST)
            
            ret = {'status':0,'msg':''}
    
            reg_FORM_obj = forms.RegForm(request.POST)
            if reg_FORM_obj.is_valid():
                reg_FORM_obj.cleaned_data.pop('re_password')
                avatar_img = request.FILES.get('avatar')
                models.UserInfo.objects.create_user(**reg_FORM_obj.cleaned_data,avatar=avatar_img)
                ret['msg'] = '/home/'
                
            else:
                ret['status'] =1
                ret['msg'] = reg_FORM_obj.errors
            return JsonResponse(ret)        
        user_form = forms.RegForm()
        
        return render(request,'signup.html',{'reg_form':user_form})
    
    #校验用户名是否存在
    def name_check(request):
        ret = {}
        if request.method == 'POST':
            username = request.POST.get('username')
            user = models.UserInfo.objects.filter(username = username)
            if  user:
                ret['state'] = 1
                ret['error'] = '用户名已存在'
    
            
            return JsonResponse(ret)    
    
    
    
    #登录
    def login(request):
        message={}
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
    
            if models.UserInfo.objects.filter(username = username):
            
                user = auth.authenticate(username=username,password=password)
    
                if user:
                    auth.login(request,user)
                    return redirect('/home/')
                else:
                    message['error'] = '密码错误'
    
            else:
                message['error'] = '用户名不存在'
    
        return render(request,'login.html',{'message':message})
            
        
    
    #注销
    def logout(request):
        auth.logout(request)
        return redirect('/home/')
    user_manage.py

    对应的用户管理的路由没什么要注意的,但是注册('/signup/')和用户名校验('/signup/namechk')

    模板文件

    用户的注册是通过了FORM组件完成的,但是登录功能因为只有两个input标签就直接用form标签完成了。数据的提交都是通过AJAX完成。

    用户注册的模板

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>用户注册</title>
        <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">
        <link rel="stylesheet" href="/static/mystyle.css">
    </head>
    <body>
    
        <div class="container">
            <div class="row">
                <div class="col-md-6 col-md-offset-3">
                    <form action="{{RegURL}}" method="POST"  novalidate class="form-horizontal reg-form" enctype="multipart/form-data">
    
                        {% csrf_token %}
                        <div class="form-group"><h3>用户注册</h3></div>
                        
    
                        <div class="form-group">
                            <label for="{{reg_form.username.id_for_label}}" class="col-sm-2 control-label">{{reg_form.username.label}}</label>
                            <div class="col-sm-10">
                                {{reg_form.username}}
                                <span class="help-block">{{reg_form.username.errors.0}}</span>
                            </div>
                        </div>
    
                        <div class="form-group">
                            <label for="{{reg_form.password.id_for_label}}" class="col-sm-2 control-label">{{reg_form.password.label}}</label>
                            <div class="col-sm-10">
                                {{reg_form.password}}
                                <span class="help-block">{{reg_form.password.errors.0}}</span>
                            </div>
                        </div>
    
    
    
                        <div class="form-group">
                            <label for="{{reg_form.re_password.id_for_label}}" class="col-sm-2 control-label">{{reg_form.re_password.label}}</label>
                            <div class="col-sm-10">
                                {{reg_form.re_password}}
                                <span class="help-block">{{reg_form.re_password.errors.0}}</span>
                            </div>
                        </div>
    
    
                        <div class="form-group">
                            <label for="{{reg_form.email.id_for_label}}" class="col-sm-2 control-label">{{reg_form.email.label}}</label>
                            <div class="col-sm-10">
                                {{reg_form.email}}
                                <span class="help-block"></span>
                            </div>
                        </div>
    
    
                        <div class="form-group">
                            <label for="" 
                                   class="col-sm-2 control-label">头像</label>
                            <div class="col-sm-10">
                                <label for="id_avatar"><img src="/static/img/default.png" alt="" id="avatar-img"></label>
                                <input type="file"  name="avatar" id="id_avatar" style="display: none;">
                            </div>
                        </div>
    
                    </form>
                    <div class="form-group">
                        <div class="col-sm-offset-2 col-sm-10">
                        <button class="btn btn-success" id="btn">AJAX提交</button>
                        </div>
                    </div>
                </div>
            </div>
    
        </div>
    
    
    <script src="/static/jquery-3.2.1.min.js"></script>
    <script src="/static/bootstrap/js/bootstrap.js"></script>
    <script>
    
    // 上传图像事件
    $('#id_avatar').change(function(){
        var filePath = this.files[0];
        var fileReader = new FileReader();
        fileReader.readAsDataURL(filePath);
        fileReader.onload = function(){
            $('#avatar-img').attr('src',fileReader.result);
        };
    });
    
    
    // 登录按钮事件
    $('#btn').click(function(){
        //点击按钮 ,触发AJAX请求事件
        var formData = new FormData()
    
        formData.append('username',$('#id_username').val());
        formData.append('password',$('#id_password').val());
        formData.append('re_password',$('#id_re_password').val());
        formData.append('email',$('#id_email').val());
        formData.append('avatar',$('#id_avatar')[0].files[0]);
        formData.append('csrfmiddlewaretoken','{{csrf_token}}');
    
        $.ajax({
            url:'/signup/',
            type:'post',
            processData:false,
            contentType:false,
            data:formData,
            success:function(data){
                console.log(data);
                if (data.status){
                    //有错误状态,错误为data.msg
                    //将错误填写至标签内
                    $.each(data.msg,function(k,v){
                        $('#id_'+k).next('span').text(v[0])
                    })
    
                }
                else{//没有错误跳转到指定页面
                    location.href = data.msg;
                }
            }
        })
    })
    
    
    
    //将所有的input框绑定的获取焦点信息
    $('input').focus(function(){
         $(this).next('span').text('');
    })
    </script>
    </body>
    </html>
    signup.html

    还有用户登录的模板

    <!DOCTYPE html>
    <html lang="zh-CN">
      <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
        <meta name="description" content="">
        <meta name="author" content="">
        <link rel="icon" href="../../favicon.ico">
    
        <title>Signin Template for Bootstrap</title>
    
        <!-- Bootstrap core CSS -->
        <link href="/static/bootstrap/css/bootstrap.min.css" rel="stylesheet">
    
    
        <!-- Custom styles for this template -->
        <link href="/static/css/login.css" rel="stylesheet">
      </head>
    
      <body>
    
        <div class="container">
    
          <form class="form-signin" method="POST" action="/login/">
            {%csrf_token%}
            <h2 class="form-signin-heading">请登录</h2>
            <label for="inputEmail" class="sr-only">用户名</label>
            <input type="text" id="inputusername" class="form-control" name="username" placeholder="用户名" required autofocus>
            <label for="inputPassword" class="sr-only">Password</label>
            <input type="password" id="inputPassword" class="form-control" name="password" placeholder="Password" required>
            <div class="checkbox">
              <label>
                <input type="checkbox" value="remember-me"> Remember me
              </label>
            </div>
            <div class="error_message">{{message.error}}</div>
            <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
          </form>
    
        </div> <!-- /container -->
    
      </body>
    </html>
    login.html

    但是本章节最后的三个html文件(home,login和signup)还有许多细节需要完善,比如有些a标签的链接地址都还没有定义,图片也没有做只是预留了个位置,在后面我会慢慢补齐!

  • 相关阅读:
    【docker】命令学习
    docker 安装mysql
    Docker DockerFile案例 自定义的tomcat9
    尚硅谷 Docker DockerFile案例 ONBUILD命令案例
    dockerfile 案例2 CMD ENTRYPOINT命令案例
    Dockerfile案例
    Dockerfile解析
    数据卷容器
    Dockfile添加数据卷
    容器数据卷
  • 原文地址:https://www.cnblogs.com/yinsedeyinse/p/13111345.html
Copyright © 2020-2023  润新知