Django项目:学习笔记开发全过程

     阅读:21

《python编程从入门到实践》(第二版)

实践项目3:Django web开发_学习笔记learning_log

写在之前:

        这个项目虽然是一个非常简单的web应用,涉及的知识点较多,包含Django,git,heroku,bootstrap,html,数据库,等等,不过数据库作者使用了sqlite,只要跟着书做,倒是也没什么复杂的操作.

        虽然一板一眼地照着书一步一步地做,还是遇到了很多问题,特别是在最后的部署环节,因为外网限制等一些问题,从注册账号开始就举步维艰,在后面的文档说明中,我将自己在开发过程中遇到的问题和解决的方案都写了出来,希望对也在学习这个项目的同学有所帮助.

 最后部署在的heroku上的项目url为:项目成果展示

几张图片:

 

 项目文件以及git和heroku CLI下载(方便国内下载不动的同学)我打包放在了百度云盘

链接:https://pan.baidu.com/s/1dD1efqJ2UjgNAqeMvKmsZQ 
提取码:http

部署过程遇到问题可以参考:

使用 Python 开始使用 Heroku |贺洛开发中心

文档说明:

项目规范:
    编写一个名为学习笔记的web应用程序,让用户能够记录感兴趣的主题,并在学习每个主题的过程中,添加条目
    学习笔记主页对这个网站进行描述,并邀请用户注册或登录.
    用户登录后,可以创建新主题,添加新条目,阅读已有条目.
过程概述:
    第一部分
        1.建立虚拟环境
            虚拟环境是系统的一个目录,可在其中安装包,并将之与其他python包隔离,
            新建目录 F://pythonProject_actual//learning_log
            在终端中切换到这个目录并以下命令创建一个虚拟环境
            python -m venv ll_env
            ll_env是自己取的虚拟环境的名称
        2.激活虚拟环境
            source ll_env/bin/activate   linux
            ll_env/Scripts/Activate       windows powershell
            这个命令运行ll_env/bin中的脚本activate,环境处活动状态时,环境名将包含在提示符前面的圆括号内
            这时候可以在环境中安装包
        3.停止虚拟环境
            deactivate


        4.安装Django
            pip install django
        5.创建项目
            django-admin startproject learning_log .
            末尾的句点表示让新项目使用合适的目录结构
            这个命令会新建一个名字为learning_log的项目
            运行dir 发现新建了一个目录learning_log,还创建了文件
                manage.py :接受命令,并将其交给django的相关部分运行
                           可用于管理数据库和运行服务器等任务
            运行dir learning_log发现以下文件
                asgi.py
                settings.py  django如何与系统交互,以及如何管理项目
                urls.py      管理页面来响应浏览器的请求
                wsgi.py      web服务器网关接口 web server gateway interface
                __init__.py

        6.创建数据库
            python manage.py migrate
                migrate:迁移数据库
            运行 dir 发现新建了一个数据库文件 db.sqlite3

        7.查看项目状态
            python manage.py runserver
            然后就可以在浏览器看到Django的页面 地址是:http://127.0.0.1:8000/  默认端口8000
            要修改默认端口只需要执行python manage.py runserver 8001

    第二部分:创建应用程序
        Django项目是由一系列应用程序组成,他们协同工作让项目成为一个整体
        1.新开一个powershell,切换到(项目目录)F:\pythonProject_actual\learning_log
        2.激活虚拟环境ll_env/Scripts/Activate
        3.执行python manage.py startapp learning_logs
        4.执行dir发现新增了learning_logs目录
        5.dir learning_logs/发现新建了以下文件
             migrations
             admin.py
             apps.py
             models.py  定义应用程序中管理的数据
             tests.py
             views.py
             __init__.py

        定义模型
            每位用户都要在学习笔记中创建很多的主题,每个条目都和特定的主题相关联
            条目以文本的方式显示,还需要存储每个条目的时间戳
            修改models.py
                from django.db import models
                # Create your models here.
                class Topic(models.Model):
                    """用户学习的主题"""
                    text = models.CharField(max_length=200)
                    date_added = models.DateTimeField(auto_now_add=True)

                    def __str__(self):
                    """返回模型的字符串表示"""
                    return self.text
        激活模型:
            打开settings.py  (F:\pythonProject_actual\learning_log\learning_log)
            在自己创建的应用程序放在默认应用程序的前面,这样可以覆盖默认应用的行为
            修改对应的
                        INSTALLED_APPS = [
                            # 我的应用程序
                            'learning_logs',
                            # 默认添加的应用程序
                            'django.contrib.admin',
                            'django.contrib.auth',
                            'django.contrib.contenttypes',
                            'django.contrib.sessions',
                            'django.contrib.messages',
                            'django.contrib.staticfiles',]
        修改数据库:
            使其能够存储和模型Topic相关的信息
            在终端执行 python manage.py makemigrations learning_logs
            命令makemigrations让Django确定该如何修改数据库使其能够存储和前面定义的新模型相关的数据
            输出
                Migrations for 'learning_logs':
                    learning_logs\migrations\0001_initial.py
                表明创建了一个0001_initial.py的迁移文件,这个文件将在数据库中为Topic创建一个表
            应用这个迁移,修改数据库:python manage.py migrate
        每当要修改数据库管理的数据时,都要经过以下三个步骤:
            修改 models.py
            对learning_logs调用makemigrations
            执行迁移 python manage.py migrate

        Django管理网站
            admin site 管理网站能够轻松处理模型
            通过它使用模型Topic来添加一些主题

            创建超级用户:
                具备所有权限的用户
                python manage.py createsuperuser
                按步骤填写用户名称,口令

            向管理网站注册模型
                修改 admin.py文件

            然后即可使用超级用户登录管理网站  地址http://127.0.0.1:8000/admin/
                添加主题
                    Chess
                    Rock Climbing

            定义模型Entry
                修改models.py
                迁移模型
                执行迁移
            向管理网站注册Entry

        Django shell
            Django 交互式会话环境shell是调试项目和排除故障的理想之地
            python manage.py shell

            Topic.objects.all()返回Topic的所有实例,结果是一个查询集(queryset)列表

            可以通过遍历查询对象的id
            for top in Topic.objects.all():
                print(top.id,top)

            知道对象的id可以使用方法Topic.objects.get(id=1)获取该对象并查看属性
            退出shell control+z enter

    第三部分:创建页面
        url模式描述了url是如何设计的,让Django知道如何将浏览器请求与网站的url匹配,以确定返回哪个页面
        每个url都被映射到特定的视图,视图函数获取并处理页面所需的数据.
        视图函数通常使用模版来渲染页面
        而模版定义页面的总体结构

        定义URL
        编写视图
        编写模版

        设计学习笔记的主页
            简单要求:只显示主题和简单的描述
            映射url:
                让基础url http://127.0.0.1:8000/映射到学习笔记的主页
                修改urls.py文件
                    from django.contrib import admin
                    from django.urls import path,include

                    urlpatterns = [
                        path('admin/', admin.site.urls),
                        path('',include('learning_logs')),  # 用来包含模块learning_logs.urls
                    ]
                在learning_logs中新建一个urls.py

                    """定义learning_logs的URL模式"""
                    from django.urls import  path
                    from . import views

                    app_name = 'learning_logs'

                    urlpatterns = [
                        # 主页
                        path('',views.index,name='index')
                    ]
                path(参数1,参数2,参数3)
                    将url和view建立映射
                    第一个参数是一个字符串,帮助Django正确地路由请求,
                        空字符串与基础url匹配
                    第二个实参指定url与view.py中的那一个函数
                    第三个实参将这个URL模式的名称指定为index,让我们可以在后面的代码的其他地方引用它
                        每当需要提供主页的链接时,都将使用这个名称
            编写视图
                视图函数接受请求中的信息,准备好生成页面所需的数据

                views.py
                    from django.shortcuts import render
                    # Create your views here.
                    def index(request):
                        """学习笔记主页"""
                        return render(request,"learning_logs/index.html")
                根据请求渲染模版index.html

            编写模版
                在learning_logs中新建一个为目录templates
                在templates中新建一个目录learning_logs
                在learning_logs中新建index.html

                这样存放文件才能让Django正确解析地址

        创建其他页面
            创建两个显示数据的页面
                一个列出所有的主题
                另一个显示特定主题的所有条目
            创建一个父模版,让其他模版继承它
                创建网站时,一些通用元素几乎会在所有的也那么页面出现,可编写包含通用元素的父模版
                并让每个页面都继承这个父模板
            父模版
                base.html,并将其存储在index.html所在的目录
                所有页面都包含顶部的标题,因为每个页面都包含这个模板,所以将这个标题设置为到主页的链接
                写入内容
                    <p>
                        <a href="{% url 'learning_logs:index' %}">Learning Log</a>
                    </p>
                    {% block content %}{% endblock content %}
                {% %}指的是模板标签
                    是一小段代码,生成要在页面中显示的信息
                {% block content %}{% endblock content %} 块标签
                    content是一个占位符,其中包含的信息由模板指定
            子模版
                重写index.html
                让它继承父模版
                    {% extends "learning_logs/base.html" %}
                    {% block content %}
                    <p> Learning Log</p>
                    <p>Learning Log helps you keep track of your </p><br>
                    <p>for any topic you're leaning about</p>
                    {% endblock content %}
                子模板的第一行必须包含{% extends "learning_logs/base.html" %}
                    这一句让Django明白要继承哪一个父模板

            显示所有主题的页面
                URL模式
                    http://127.0.0.1:8000/topics返回显示所有主题的页面
                    修改learning_logs/urls.py
                        添加    # 显示所有主题
                                path('topics/',views.topics,name='topics')
                视图
                    添加def topics(request):
                        """显示所有主题"""
                        topics = Topic.objects.order_by('date_added')
                        context = {'topics': topics}
                        return render(request,'learning_logs/topics.html',context)
                模板
                    topics.html
                    修改父模版,使其包含到显示所有主题的页面的链接
            显示特定主题的页面
                url模式
                    修改urls.py
                视图
                模板
                    topic.html
                将显示所有主题的页面中的主题设置为链接
                    修改topics.html,让每个主题都链接到相应页面

    第四部分:用户账户
        创建表单,让用户能够自己添加主题和条目,以及编辑既有条目
            目前只有超级用户通过管理网站才能添加主题和条目
            但我们不想让用户和管理网站交互
            因此我们将使用Django的表单创建工具来创建用户能输入数据的页面

            添加新主题:
                通过Django的ModelForm来创建表单
                    在models.py所在的文件夹创建forms.py文件
                    输入代码
                        from django import forms
                        from .models import Topic
                        class TopicForm(forms.ModelForm):
                            class meta:
                                model = Topic          # 根据哪个模型创建表单
                                fields = ['text']      # 包含的字段
                                labels= {"text : ''"}  # 不要为字段text生成标签
                URL模式new_topic
                    当用户添加新主题时切换到http://127.0.0.1:8000/new_topic/
                    urls.py 添加    # 用于添加新主题的页面
                                    path('new_topic/',views.new_topic,name='new_topic'),
                视图函数new_topic()
                    处理两种情形
                        1刚进入new_topic页面(这种情况应显示空表单)
                        2对提交的表单数据进行处理,并将用户重定向到topics
                GET和POST请求
                    对于只是从服务器读取数据的页面使用GET请求
                    在用户需要通过表单提交信息时,使用POST请求
                模版new_topic.html
                    代码
                        {% extends "learning_logs/base.html" %}
                        {% block content %}
                        <p>Add a new topic</p>
                        <form action="{% url 'learning_logs:new_topic' %}" method="post">
                            {% csrf_token %}  # 用来防止跨站请求伪造攻击
                            {{ form.as_p }}  # 显示表单
                            <button name="submit">Add topic</button>
                        </form>
                        {% endblock content %}
                    action告诉服务器提交的表单发送到哪里 learning_logs:new_topic
                    as_p指的是以字段格式渲染所有表单元素

                    链接到topcs.html
                        <a href="{% url 'learning_logs:new_topic' %}">Add a new topic</a>
            添加新条目
                用于添加新条目的表单
                forms.py
                    添加代码
                    class EntryForm(forms.ModelForm):
                    class Meta:
                        model = Entry
                        fields = ['text']
                        labels = {'text':" "}
                        widgets = {'text':forms.Textarea(attrs={'cols':80})}
                URL模式new_entry
                        # 用于添加新条目的页面
                        path('new_entry/<int:topic_id>/', views.new_entry, name='new_entry'),
                视图函数new_entry
                        def new_entry(request,topic_id):
                        """在特定主题添加条目"""
                        topic = Topic.object.get(id=topic_id)
                        if request.method != 'POST':
                            # 未提交数据,创建一个空表单
                            form = EntryForm()
                        else:
                            # POST提交数据,对数据进行处理
                            form = EntryForm(data=request.POST)
                            if form.is_valid():
                                new_entry = form.save(commit=False)
                                new_entry.topic = topic
                                new_entry.save()
                                return redirect('learning_logs:topic',topic_id = topic_id)
                        # 显示空表单或指出表单数据无效
                        context = {'topic':topic,'form':form}
                        return render(request,'learning_logs/new_entry.html',context)
                模版new_entry.html

                链接到页面topic.html
            编辑条目
                下面来创建让用户能够编辑条目的页面
                url模式
                视图函数edit_entry()
                模版edit_entry.html
                链接到topic.html

        实现用户验证系统
            使用Django自带的用户验证系统来完成
                新建应用程序users
                    python manage.py startapp users
                    在learning_log目录下新建一个users目录
                    目录结构和应用程序learning_logs相同
                将users添加到settings中
                    INSTALLED_APPS = [
                                        # 我的应用程序
                                        'learning_logs',
                                        'users'
                                        --snip--]
                    这样Django就把users应用程序包含到了项目中
                包含users的URL
                    修改根目录中的urls.py
                        urlpatterns = [
                                    path('admin/', admin.site.urls),
                                    path('',include('learning_logs.urls')),
                                    path('',include('users.urls')),]
                    这行代码让所有以users开头的URL(如:都匹配http://127.0.0.1:8000/users/login)
                登录页面
                    在users中新建一个urls.py
                        """定义users的URL模式"""
                        from django.urls import  path,include
                        app_name = 'users'
                        urlpatterns = [
                            # 包含默认的身份验证URL
                            path('',include('django.contrib.auth.urls')),]
                    登录页面的url模式与 http://localhost:8000/users/login/匹配

                    模版login.html
                        用户请求登录页面时,Django将使用默认的视图函数,但仍然需要编写模版
                        在users目录下创建templates/registration
                        新建模版login.html
                            {% extends "learning_logs/base.html" %}
                            {% block content %}
                              {% if form.errors %}
                                <p>Your Username and psaaword didn't match.Please try again</p>
                              {% endif  %}
                            <form action="{% url 'users:login' %}" method="post">
                                {% csrf_token %}
                                {{ form.as_p }}
                                <button name="submit">Log in</button>
                                <input type="hidden" name="next" value="{% url 'learning_logs:index' %}"/>
                            </form>
                            {% endblock content %}
                    链接到登录页面
                        在base.html中添加到登录页面的链接
                                {% if user.is_authenticated %}
                                Hello, {{user.username}}.
                                {% else %}
                                <a href="{% url 'users:login' %}">Log in</a>
                                {% endif %}
                        使用登录页面
                            http://127.0.0.1:8000/users/login/
                注销
                    提供一个让用户注销的途径,为此在base.html中添加一个注销链接
                    在base.html中添加,<a href="{% url 'users:logout' %}">Log out</a>

                    注销确认页面
                    logged_out.html
                        {% extends "learning_logs/base.html" %}
                        {% block content %}
                        <p> You have been logged out.Thank you for visiting</p>
                        <p>已注销,感谢你的访问!</p>
                        {% endblock content %}
                注册页面
                    使用Django提供的表单UserCreationForm创建一个用户注册页面
                    url模式
                        添加path('register/',views.register,name='register'),'
                    视图函数register()
                        def register(request):
                            """注册新用户"""
                            if request.method != 'POST':
                                # 显示空的注册表单
                                form = UserCreationForm()
                            else:
                                # 处理填写好的表单
                                form = UserCreationForm(data=request.POST)
                            if form.is_valid():
                                new_user = form.save()
                                # 让用户自动登录,再重定向到主页
                                login(request,new_user)
                                return redirect('learning_logs:index')
                            # 显示空表单或指出表单无效
                            context = {"form":form}
                            return render(request,'registration/register.html',context)
                    注册模版
                        register.html
                            {% extends "learning_logs/base.html" %}
                            {% block content %}
                            <form action="{% url 'users:register' %}" method="post">
                                {% csrf_token %}
                                {{ form.as_p }}
                                <button name="submit">Register(注册)</button>
                                <input type="hidden" name="next" value="{% url 'learning_logs:index' %}"/>
                            </form>
                            {% endblock content %}
                    链接到注册页面
                        在base.html添加一个用于注册的链接
                            <a href="{% url 'users:register' %}">Register</a> -

            让用户拥有自己的数据
                限制对页面的访问
                @login_required
                    限制访问显示所有主题的页面
                    在learning_logs/views.py中添加代码
                        导入@login_required
                        在topics()添加装饰器@login_required让只有登录的用户才能显示所有页面

                        Django在执行topics之前先检查用户是否登录,已登录用户才执行topics()视图函数
                        否则重定向到登录页面

                        为实现重定向,需要修改settings
                        添加 # 我的设置
                            LOGIN_URL = 'users:login'
                全面限制对项目"学习笔记"的访问
                    在本项目中,将不限制对主页和注册页面的访问,并限制对其他所有页面的访问
                    在learning_logs/views.py中对除了index()以外的所有函数都添加装饰器

                将数据关联到用户
                    只需将最高层的数据关联到用户,低层的数据就会自动关联到用户
                    例如本项目中主题时最高层的数据,只要主题关联到用户,则每个条目都关联到了用户
                    修改Topic模型,让每个主题归属于特定用户
                        修改models.py
                            添加owner = models.ForeignKey(User,on_delete=models.CASCADE)
                            当用户被删除时,其建立的主题也将被删除
                    确定当前有哪些用户
                        迁移数据库,Django需要知道将现有主题关联到哪个用户,比如超级用户
                        启动 Django shell
                            python manage.py shell
                        查看所有用户
                            from django.contrib.auth.models import User
                            User.onjects.all()
                            查看用户id
                        迁移数据库
                            python manage.py makemigrations learning_logs
                            选项为关联到哪一个用户 选择1
                            执行:python manage.py migrate

                            如果需要重置数据库,可以使用命令python manage.py flush
                            这会丢失所有数据,并且需要重新创建超级用户

                    只允许用户访问自己的主题
                        在views.py中对topics()做如下修改
                        topics = Topic.objects.filter(owner=request.user).order_by('date_added')
                    保护用户的主题
                        为防止未授权用户通过url拼接的形式访问到条目
                        修改视图函数topic(),在获取请求之前执行检查
                            # 确认请求的主题属于当前用户
                            if topic.owner != request.user:
                                raise Http404
                    保护页面edit_entry
                        修改视图函数edit_entry()
                            if topic.owner != request.user:
                                 raise Http404
                    将新主题关联到当前用户
                        在new_topic中添加
                            new_topic = form.save(commit=False)
                            new_topic.owner = request.user
                            new_topic.save()
                    保护页面new_entry
                        修改视图函数new_entry()
                            if topic.owner != request.user:
                                 raise Http404
    第五部分:
        设置应用程序的样式并部署
            使用bootstrap设置样式
                django-bootstrap4安装
                    虚拟环境执行 pip install django-bootstrap4
                在应用程序中添加django-bootstrap4
                    settings.py
                        INSTALLED_APPS = [
                                            # 我的应用程序
                                            'learning_logs',
                                            'users',
                                            #第三方应用程序
                                            'bootstrap4'
                                            --snip--]
                修改bsae.html
                    头部
                    {% load bootstrap4 %}
                    <!DOCTYPE html>
                    <html lang="en">
                    <head>
                        <meta charset="UTF-8">
                        <meta name="viewport" content="width=device-width,initial-scale=1,
                                                        shrink-to-fit=no">
                        <title>学习笔记</title>
                        {% bootstrap_css %}
                        {% bootstrap_javascript jquery='full' %}
                    </head>
                定义导航栏
                    <!--导航栏部分-->
                    <nav class="navbar navbar-expand-md navbar-light bg-light mb-4 border">
                        <a class = "navbar-brand" href="{% url 'learning_logs:index' %}">Learning Log</a>
                        <button class="navbar-toggler" type="button" data-toggle="collapse"
                                                data-target="#navbarCollapse" aria-controls="navbarCollapse"
                                                aria-expanded="false" aria-label="Toggle navigation">
                            <span class="navbar-toggler-icon"></span>
                        </button>
                        <div class="collapse navbar-collapse" id="navbarCollapse">
                            <ul class="navbar-nav mr-auto">
                                <li class="nav-item">
                                    <a class="nav-link" href="{% url 'learning_logs:topics' %}">主题</a>
                                </li>
                            </ul>
                            <ul class="navbar-nav ml-auto">
                                {% if user.is_authenticated %}
                                <li class="nav-item">
                                    <span class="navbar-text">你好,{{ user.username}}.</span>
                                </li>
                                <li class="nav-item">
                                    <a class="nav-link" href="{% url 'users:logout' %}">退出</a>
                                </li>
                                {% else %}
                                <li class="nav-item">
                                    <a  class="nav-link" href="{% url 'users:register' %}">注册</a>
                                </li>
                                <li class="nav-item">
                                    <a  class="nav-link" href="{% url 'users:login' %}">登录</a>
                                </li>
                                {% endif %}
                            </ul>
                        </div>
                    </nav>
                主要部分
                    <!--定义页面的主要部分-->
                    <main role="main" class="container">
                        <div class="pb-2 mb-2 border-bottom">
                            {% block page_header %}{% endblock page_header%}
                        </div>
                        <div>
                            {% block content %}{% endblock content %}
                        </div>
                    </main>
                    </body>
                    </html>
                设置主页的样式
                    index.html
                    body部分
                        <body>
                        {% extends "learning_logs/base.html" %}
                        {% block page_header %}
                            <div class="jumbotron">
                                <h1 class="diaplay-3">Track your Learning.</h1>
                                <p class="lead">Make your own Learning Log,and
                                keep a list of the topics you're learning about.
                                Whenever you learn something new about a topic,
                                make an entry summarizing what you;ve learned</p>
                                <a class="btn btn-lg btn-primary" href="{% url 'users:register' %}" role="button">注册 &raquo;</a>
                            </div>
                        {% endblock page_header %}
                设置登录页面的样式
                    login.html
                    body部分
                    <body>
                    {% extends "learning_logs/base.html" %}
                    {% load bootstrap4 %}
                    {% block page_header %}
                        <h2>欢迎登录 login to your account</h2>
                    {% endblock page_header %}

                    {% block content %}
                    <form class ="form" action="{% url 'users:login' %}" method="post">
                        {% csrf_token %}
                        {% bootstrap_form form%}
                        {% buttons %}
                        <button name="submit" class="btn btn-primary">登录</button>
                        {% endbuttons %}
                        <input type="hidden" name="next" value="{% url 'learning_logs:index' %}"/>
                    </form>
                    {% endblock content %}
                    </body>
                设置显示所有主题的页面
                    topics.html
                设置单个主题的条目样式
                    topic.html
                设置修改条目样式
                    edit_entry.html
                设置新增主题和新增条目的样式
                    new_topic.html
                    new_entry.html

            使用Heroku部署项目
                注册账号
                    这一步好难啊!!!
                    主要是国内收不到验证码
                    解决方案:
                    https://blog.csdn.net/weixin_43306345/article/details/110941898?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_utm_term~default-0.no_search_link&spm=1001.2101.3001.4242.1&utm_relevant_index=3
                        我的chrome下载不起Header Editor插件
                        用作者给的github的链接下载了也安装不了
                        但是edge浏览器能安装,用上面文章的配置方法成功注册了
                        注册的时候请先去搞一个国外的邮箱
                        比如outlook或者fixmail
                安装heroku CLI
                    地址https://devcenter.heroku.com/articles/getting-started-with-python#set-up
                安装必要的包
                    虚拟环境下执行 pip install psycopg2==2.7.*
                                        报错,安装了2.9.3
                                  pip install django-heroku
                                  pip install gunicorn
                创建文件requirements.txt
                    pip freeze > requirements.txt
                    该文件中指出了项目依赖的包及其版本
                指定python版本
                    python --version
                    3.9.7
                    在manage.py所在的文件夹新建一个名为runtime.txt的文件
                为部署到heroku而修改settings.py
                    # Heroku设置
                    import django_heroku
                    django_heroku.settings(locals())
                创建启动进程的Procfile
                    在manage.py所在的文件夹新建一个名为Procfile的文件
                使用git跟踪项目文件
                    安装git
                    配置Git
                        git config --global user.name "morbidmuse"
                        git config --global user.email "MorbidMuse520@outlook.com"
                    忽略文件
                        在manage.py所在的文件夹新建.gitignore
                        ll_env/
                        __pycache__/
                        *.sqlite3
                提交项目
                    git init
                    git add .
                    git commit -am "Ready for deployment to heroku."
                    git status
                推送到Heroku
                    heroku login
                        这里可能又因为外网登录不了  可以直接 heroku login -i 在命令行中登录
 Python has released a security update! Please consider upgrading to python-3.9.9
                    登录
                    heroku create
                    git push heroku master

                    为核实正确启动了服务器进程
                    heroku ps


                    在浏览器中打开 heroku open
            在Heroku上建立数据库
                heroku run python manage.py migrate

            改进heroku 的部署
                创建超级用户
                    heroku run bash
                    ls
                    python manage.py createsuperuser
                    exit退出bash
                在heroku上创建对用户友好的URL
                    虚拟环境执行:heroku apps:rename cn-mm-learning-log
                    修改之后必须使用https://cn-mm-learning-log.herokuapp.com/访问项目
            确保项目的安全
                修改settings.py
                将以下代码放在heroku设置下
                    if os.environ.get('DEBUG') == 'TRUE':
                        DEBUG = True
                    elif os.environ.get('DEBUG') == 'FALSE':
                        DEBUG = False
            提交并推送修改
                git commit -am "Set DEBUG based on environment variables"
                git status

                推送修改
                    git push heroku master
            在Heroku上设置环境变量
                heroku config:set DEBUG=FALSE

                这样部署在云平台上的项目在输入错误的url时将显示404错误,而不会显示错误报告.
            创建自定义错误页面
                在learning_log 中新建文件夹templates
                新建模版404.html
                修改settings.py
                    TEMPLATES = [
                                    {
                                        'BACKEND': 'django.template.backends.django.DjangoTemplates',
                                        'DIRS': [os.path.join(BASE_DIR,'templates')],
                                        'APP_DIRS': True,
                                        'OPTIONS': {
                                            'context_processors': [
                                                'django.template.context_processors.debug',
                                                'django.template.context_processors.request',
                                                'django.contrib.auth.context_processors.auth',
                                                'django.contrib.messages.context_processors.messages',
                                            ],
                                        },
                                    },
                                ]
                提交修改
                git add .
                git commit -am "added custom 404 and 500 error pages"
                git status

                推送修改
                    git push heroku master











改BUG记录:
    1.
    编写添加新条目的过程中,发现topic.html中
    添加<p><a href="{% url 'learning_logs:new_entry' topic.id %}">Add new entry</a></p>
    以后,始终报错.Reverse for 'new_entry' with arguments '('',)' not found.1
    pattern(s) tried: ['new_entry/(?P<topic_id>[0-9]+)/\\Z']
    之前都没问题,反复研究添加新条目的url模式,views视图函数,以及new_entry模版都没发现错误

    仔细研究页面发现在url:http://127.0.0.1:8000/topics/5/
    也就是topic的页面中 Topic:后面的主题名称为空,说明topic没有获取到数据
    仔细检查前面的代码发现views.py中的topic函数
    context = {'topics': topics,'entries':entries}
    改为
    context = {'topic': topic,'entries':entries}
    页面正确显示

    总结:topic.html中
    添加<p><a href="{% url 'learning_logs:new_entry' topic.id %}">Add new entry</a></p>
    之所以会报错,是因为根本获取不到 topic的id

    启示:报错的地方可能并不是真正出问题的地方,也许这个缺陷早已存在,只是在报错的位置才得以显现

    2.
    编写编辑条目的页面时
    将return render(request,'learning_logs/edit_entry.html',context)
    错误地写成return render(request,'learning_logs:edit_entry.html',context)
    找了半天找不出错误,因为提示消息只说要渲染的模版不存在.错误地在csdn上找了很多解决模版不存在的方案!!!!
    django.template.exceptions.TemplateDoesNotExist: learning_logs:edit_entry.html

    3.部署的时候多次失败
        可能原因:runtime.txt文件命名错误,之前写成了tuntime.txt
        增加了learning_log/Procfile.windows文件
            内容为web: python manage.py runserver 0.0.0.0:5000


人生充满BUG,而我不是一个合格的改BUG程序员