欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

《Python编程:从入门到实践》WEB应用程序

程序员文章站 2022-04-06 13:03:42
Centos版本:7.8服务器IP:192.168.100.11Pytho版本:3.6.8Django版本:2.2.2一、Django入门1 Python安装参考:https://blog.csdn.net/linwenhai2018/article/details/1096280862 Sqlite3升级参考:https://blog.csdn.net/linwenhai2018/article/details/1096673443 配置虚拟环境mkd.....

Centos版本:7.8

服务器IP:192.168.100.11

Pytho版本:3.6.8

Django版本:2.2.2

 

一、Django入门

1 Python安装

参考:https://blog.csdn.net/linwenhai2018/article/details/109628086

 

2 Sqlite3升级

参考:https://blog.csdn.net/linwenhai2018/article/details/109667344

 

3 配置虚拟环境

mkdir -p /opt/Projects/learning_log
cd /opt/Projects/learning_log
/opt/python/bin/python3 -m venv ll_env
# 进入虚拟机环境
source ll_env/bin/activate
# 退出虚拟环境
deactivate

 

4 创建项目

# 安装django
(ll_env) [test@test learning_log]$ pip install --upgrade pip
(ll_env) [test@test learning_log]$ pip install Django==2.2.2

# 创建项目learning_log
(ll_env) [test@test learning_log]$ django-admin.py startproject learning_log .

# 修改配置文件
vi learning_log/settings.py
-----------------------------------------
ALLOWED_HOSTS = ["*"]
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
-----------------------------------------

# 安装数据库sqlite3
(ll_env) [test@test learning_log]$ python manage.py migrate

# 运行项目
(ll_env) [test@test learning_log]$ python manage.py runserver 192.168.100.11:8000

浏览器访问:http://192.168.100.11:8000/

《Python编程:从入门到实践》WEB应用程序

 

5 创建应用程序

# 创建应用程序learning_logs
(ll_env) [test@test learning_log]$ python manage.py startapp learning_logs
# 修改配置文件,添加新建的应用程序名
vi learning_log/settings.py 
---------------------------------------
INSTALLED_APPS = [
    --snip--
    'learning_logs',
]
---------------------------------------

 

6 定义模型

定义模型用途:修改数据库表结构。

learning_logs/models.py

#coding=utf-8
from django.db import models

class Topic(models.Model):
    """定义主题"""
    topic_name = models.CharField(max_length=200)     # 主题最大即200个字符
    ctime = models.DateTimeField(auto_now_add=True)
    def __str__(self):
        """显示主题简介"""
        return self.topic_name

class Entry(models.Model):
    """定义主题内容"""
    topic = models.ForeignKey(Topic,on_delete=models.CASCADE,)    # 外键,与topic关联
    content = models.TextField()
    ctime = models.DateTimeField(auto_now_add=True)
    class Meta:
        """使用entries来表示多个条目"""
        verbose_name_plural = 'entries'
    def __str__(self):
        """显示内容简介"""
        return self.content[:50] + "..."
# 生成迁移文件
(ll_env) [test@test learning_log]$ python manage.py makemigrations learning_logs

# 修改数据库
(ll_env) [test@test learning_log]$ python manage.py migrate

 

7 后台管理

# 创建管理员
(ll_env) [test@test learning_log]$ python manage.py createsuperuser

learning_logs/admin.py(向管理网站注册模型) 

#coding=utf-8
from django.contrib import admin
from learning_logs.models import Topic,Entry

admin.site.register(Topic)
admin.site.register(Entry)

 浏览器访问:http://192.168.100.11:8000/admin/

手工添加主题和内容

《Python编程:从入门到实践》WEB应用程序

《Python编程:从入门到实践》WEB应用程序

 

8 Django Shell

(ll_env) [test@test learning_log]$ python manage.py shell
>>> from learning_logs.models import Topic
>>> Topic.objects.all()
<QuerySet [<Topic: 笑傲江湖>, <Topic: 倚天屠龙记>]>
>>> topics = Topic.objects.all()
>>> for topic in topics:
...     print(topic.id, topic)
... 
1 笑傲江湖
2 倚天屠龙记
>>> t = Topic.objects.get(id=1)
>>> t.topic_name
'笑傲江湖'
>>> t.ctime
datetime.datetime(2020, 11, 4, 8, 58, 50, 239233, tzinfo=<UTC>)
>>> t.entry_set.all()
<QuerySet [<Entry: 《笑傲江湖》是中国现代作家金庸创作的一部长篇武侠小说,于1967年开始创作并连载于《明报》,1969...>]>

 

9 映射URL

learning_log/urls.py(修改项目URL)

#coding=utf-8
from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    # 后台管理跳转
    path('admin/', admin.site.urls),
    # 首页跳转
    path('',include('learning_logs.urls', namespace='learning_logs')),
]

learning_logs/urls.py(修改应用程序URL)

#coding=utf-8
from django.urls import path
from . import views

app_name ='[learning_logs]'
urlpatterns = [
    # 首页
    path('',views.index, name='index'),
    # 主题网页
    path('topics/',views.topics,name='topics'),
    # 内容网页
    path('topics/<topic_id>',views.topic,name='topic'),
]

 

10 视图

learning_logs/views.py

#coding=utf-8
from django.shortcuts import render
from .models import Topic

def index(request):
    """主页"""
    return render(request, 'html/index.html')

def topics(request):
    """图书主题"""
    topics = Topic.objects.order_by('ctime')    # 查询数据库Topic对象,按ctime排序
    context = {'topics': topics}    # 们定义了一个将要发送给模板的字典
    return render(request, 'html/topics.html', context) # 将变量context传递给render()

def topic(request, topic_id):
    """图书简介"""
    topic = Topic.objects.get(id=topic_id)  # 使用get()来获取主题
    entries = topic.entry_set.order_by('-ctime')   # 获取与该主题相关联的条目,排序
    context = {'topic': topic, 'entries': entries}
    return render(request, 'html/topic.html', context)

 

11 网页

# 配置网页默认路径
vi learning_log/settings.py
------------------------------------------
TEMPLATES = [
    {
        --snip--
        'DIRS': [os.path.join(BASE_DIR, '')],
        --snip--
    },
]
------------------------------------------

html/base.html(创建父模板,目录html存放相关网页)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>图书</title>
</head>
<body>
<!--设置超链接-->
<a href="{% url 'learning_logs:index' %}">首页</a>
<a href="{% url 'learning_logs:topics' %}">主题</a>
{% block content %}{% endblock content %}
</body>
</html>

html/index.html(创建首页)

{% extends "html/base.html" %}
{% block content %}
<p>武侠世界欢迎您!</p>
{% endblock content %}

html/topics.html(创建图书列表网页)

{% extends "html/base.html" %}
{% block content %}
<p>图书列表:</p>
<ul>
    {% for topic in topics %}
        <li>
            <a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}</a>
        </li>
    {% empty %}
        <li>无图书</li>
    {% endfor %}
</ul>
{% endblock content %}

html/topic.html(创建图书简介网页)

{% extends "html/base.html" %}
{% block content %}
<p>图书: {{ topic }}</p>
<p>简介:</p>
<ul>
    {% for entry in entries %}
        <li>
            <p>{{ entry.content}}</p>
            <p>{{ entry.ctime|date:'Y-m-d H:i'}}</p>
        </li>
    {% empty %}
        <li>无简介</li>
    {% endfor %}
</ul>
{% endblock content %}

 

 二、图书增加、简介增加、简介编辑功能

1 新增包含表单的模块

learning_logs /forms.py

#coding=utf-8
from django import forms
from .models import Topic,Entry

class TopicForm(forms.ModelForm):
    """图书表单"""
    class Meta:
        model = Topic
        fields = ['topic_name']
        labels = {'topic_name': ''}

class EntryForm(forms.ModelForm):
    """简介表单"""
    class Meta:
        model = Entry
        fields = ['content']
        labels = {'content': ''}
        widgets = {'content': forms.Textarea(attrs={'cols': 80})}

 

2 编辑URL

learning_logs/urls.py

#coding=utf-8
from django.urls import path
from . import views

app_name ='[learning_logs]'

urlpatterns = [
    --snip--
    # 新建图书网页
    path('new_topic/',views.new_topic,name='new_topic'),
    # 新建简介网页
    path('new_entry/<topic_id>',views.new_entry, name='new_entry'),
    # 编辑简介网页
    path('edit_entry/<entry_id>',views.edit_entry,name='edit_entry'),
]

 

3 编辑视图

learning_logs/views.py

#coding=utf-8
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.urls import reverse
from .models import Topic,Entry
from .forms import TopicForm,EntryForm
--snip--

def new_topic(request):
    """添加新图书"""
    if request.method != 'POST':
        # 未提交数据:创建一个新表单
        form = TopicForm()
    else:
        # POST提交的数据,对数据进行处理
        form = TopicForm(request.POST)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('learning_logs:topics'))
    context = {'form': form}
    return render(request, 'html/new_topic.html', context)

def new_entry(request, topic_id):
    """添加图书简介"""
    topic = Topic.objects.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 HttpResponseRedirect(reverse('learning_logs:topic',args=[topic_id]))
    context = {'topic': topic, 'form': form}
    return render(request, 'html/new_entry.html', context)

def edit_entry(request, entry_id):
    """编辑图书简介"""
    entry = Entry.objects.get(id=entry_id)
    topic = entry.topic
    if request.method != 'POST':
        # 初次请求,使用当前条目填充表单
        form = EntryForm(instance=entry)
    else:
        # POST提交的数据,对数据进行处理
        form = EntryForm(instance=entry, data=request.POST)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('learning_logs:topic',args=[topic.id]))
    context = {'entry': entry, 'topic': topic, 'form': form}
    return render(request, 'html/edit_entry.html', context)

 

 4 编辑网页

html/new_topic.html(新建增加图书网页)

{% extends "html/base.html" %}
{% block content %}
<p>新图书名:</p>
<form action="{% url 'learning_logs:new_topic' %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button name="submit">保存</button>
</form>
{% endblock content %}

html/new_entry.html(新建增加简介网页)

{% extends "html/base.html" %}
{% block content %}
<p><a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}</a></p>
<p>添加图书简介:</p>
<form action="{% url 'learning_logs:new_entry' topic.id %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button name='submit'>保存</button>
</form>
{% endblock content %}

html/edit_entry.html(新建修改简介网页)

{% extends "html/base.html" %}
{% block content %}
<p><a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}</a></p>
<p>简介内容:</p>
<form action="{% url 'learning_logs:edit_entry' entry.id %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button name="submit">保存</button>
</form>
{% endblock content %}

html/topics.html(修改图书列表网页,添加链接到页面new_topic)

{% extends "html/base.html" %}
{% block content %}
<p>图书列表:</p>
<ul>
    --snip--
</ul>
<a href="{% url 'learning_logs:new_topic' %}">新增图书</a>
{% endblock content %}

html/topic.html(修改图书简介网页,添加链接到页面new_entry与edit_entry)

{% extends "html/base.html" %}
{% block content %}
<p>图书: {{ topic }}</p>
<p>简介:</p>
<p>
    <a href="{% url 'learning_logs:new_entry' topic.id %}">添加简介</a>
</p>
<ul>
    {% for entry in entries %}
        <li>
            <p>{{ entry.content}}</p>
            <p>{{ entry.ctime|date:'Y-m-d H:i'}}</p>
            <p>
                <a href="{% url 'learning_logs:edit_entry' entry.id %}">编辑</a>
            </p>
        </li>
    {% empty %}
        <li>无简介</li>
    {% endfor %}
</ul>
{% endblock content %}

 

三、用户登陆、退出、注册功能

1 创建新应用程序

# 创建新应用程序users
(ll_env) [test@test learning_log]$ python manage.py startapp users

learning_log/settings.py (配置文件添加新应用程序)

--snip--
INSTALLED_APPS = [
    --snip--
    'users',
]
--snip--

 

2 编辑URL

learning_log/urls.py(配置项目跳转URL)

#coding=utf-8
from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    --snip--
    # 用户界面
    path('users/',include('users.urls', namespace='users')),
    --snip--
]

users/urls.py(配置应用程序URL)

#coding=utf-8
from django.urls import path
from django.contrib.auth.views import LoginView,LogoutView
from . import views

app_name = 'users'

urlpatterns = [
    # 登陆界面
    path('login/',LoginView.as_view(template_name='html/login.html'),name='login'),
    # 注销页面
    path('logout/',LogoutView.as_view(template_name='html/index.html'),name='logout'),
    # 注册界面
    path('register/',views.register, name='register'),
]

 

3 编辑视图

users/views.py

#coding=utf-8
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.contrib.auth import login,logout,authenticate
from django.contrib.auth.forms import UserCreationForm

def logout_view(request):
    """注销用户"""
    logout(request)
    return HttpResponseRedirect(reverse('learning_logs:index'))

def register(request):
    """注册新用户"""
    if request.method != 'POST':
        # 显示空的注册表单
        form = UserCreationForm()
    else:
        # 处理填写好的表单
        form = UserCreationForm(data=request.POST)
        if form.is_valid():
            new_user = form.save()
            # 让用户自动登录,再重定向到主页
            authenticated_user = authenticate(username=new_user.username,password=request.POST['password1'])
            login(request, authenticated_user)
            return HttpResponseRedirect(reverse('learning_logs:index'))
    context = {'form': form}
    return render(request, 'html/register.html', context)

 

4 编辑网页

html/login.html(创建登陆网页)

{% extends "html/base.html" %}
{% block content %}
    {% if form.errors %}
    <p>账户和密码不匹配,请重新尝试。</p>
    {% endif %}
    <form method="post" action="{% url 'users:login' %}">
    {% csrf_token %}
    {{ form.as_p }}
    <button name="submit">登陆</button>
    <input type="hidden" name="next" value="{% url 'learning_logs:index' %}" />
    </form>
{% endblock content %}

html/register.html(创建注册网页)

{% extends "html/base.html" %}
{% block content %}
    <form method="post" action="{% url 'users:register' %}">
        {% csrf_token %}
        {{ form.as_p }}
        <button name="submit">注册</button>
        <input type="hidden" name="next" value="{% url 'learning_logs:index' %}" />
    </form>
{% endblock content %}

html/base.html(修改base网页,添加链接页面到登陆、注册、退出)

--snip--
<p>
    <a href="{% url 'learning_logs:index' %}">首页</a>
    <a href="{% url 'learning_logs:topics' %}">主题</a>
    {% if user.is_authenticated %}
        {{ user.username }},欢迎您
        <a href="{% url 'users:logout' %}">退出</a>
    {% else %}
        <a href="{% url 'users:register' %}">注册</a>
        <a href="{% url 'users:login' %}">登陆</a>
    {% endif %}
</p>
--snip--

 

四、访问控制

1 限制功能访问

learning_logs/views.py(使用装饰器@login_required控制)

#coding=utf-8
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.urls import reverse
from .models import Topic,Entry
from .forms import TopicForm,EntryForm
from django.contrib.auth.decorators import login_required
--snip--
@login_required
def topics(request):
    """图书主题"""
--snip--
@login_required
def topic(request, topic_id):
    """图书简介"""
--snip--
@login_required
def new_topic(request):
    """添加新图书"""
--snip--
@login_required
def new_entry(request, topic_id):
    """添加图书简介"""
--snip--
@login_required
def edit_entry(request, entry_id):
    """编辑图书简介"""
--snip--

learning_log/settings.py(配置未登陆重定向路径)

--snip--
# 登陆设置
LOGIN_URL = '/users/login/'

2 将数据关联到用户

learning_logs/models.py(修改主题归属)

#coding=utf-8
from django.db import models
from django.contrib.auth.models import User
--snip--
class Topic(models.Model):
    """定义主题"""
    owner = models.ForeignKey(User,on_delete=models.CASCADE,)   # 外键,与User关联
--snip--
    
# 查询用户ID
(ll_env) [test@test learning_log]$ python manage.py shell
Python 3.6.8 (default, Nov 11 2020, 19:49:20) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from django.contrib.auth.models import User
>>> User.objects.all()
<QuerySet [<User: admin>, <User: test>]>
>>> for user in User.objects.all():
...     print(user.username, user.id)
... 
admin 1
test 2
# 修改数据库数据
(ll_env) [test@test learning_log]$ python manage.py makemigrations learning_logs
You are trying to add a non-nullable field 'owner' to topic without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
 2) Quit, and let me add a default in models.py
Select an option: 1
Please enter the default value now, as valid Python
The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now
Type 'exit' to exit this prompt
>>> 1
Migrations for 'learning_logs':
  learning_logs/migrations/0002_topic_owner.py
    - Add field owner to topic
(ll_env) [test@test learning_log]$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, learning_logs, sessions
Running migrations:
  Applying learning_logs.0002_topic_owner... OK
# 验证
(ll_env) [test@test learning_log]$ python manage.py shell
>>> from learning_logs.models import Topic
>>> for topic in Topic.objects.all():
...     print(topic, topic.owner)
... 
笑傲江湖 admin
倚天屠龙记 admin
射雕英雄传 admin

learning_logs/views.py(保护用户主题和页面)

#coding=utf-8
from django.shortcuts import render
from django.http import HttpResponseRedirect,Http404
from django.urls import reverse
from .models import Topic,Entry
from .forms import TopicForm,EntryForm
from django.contrib.auth.decorators import login_required
--snip--
@login_required
def topics(request):
    """图书主题"""
    topics = Topic.objects.filter(owner=request.user).order_by('ctime') # 只允许用户访问自己的主题
    --snip--
--snip--
@login_required
def topic(request, topic_id):
    """图书简介"""
    --snip--
    if topic.owner != request.user:     # 确认请求的主题属于当前用户
        raise Http404
    --snip--
--snip--
@login_required
def new_topic(request):
    """添加新图书"""
        --snip--
        if form.is_valid():
            new_topic = form.save(commit=False) # 将新主题关联到当前用户
            new_topic.owner = request.user
            new_topic.save()
            --snip--
--snip--
@login_required
def edit_entry(request, entry_id):
    """编辑图书简介"""
    --snip--
    if topic.owner != request.user:     # 确认请求的主题属于当前用户
        raise Http404
--snip--

 

五、网页样式

# 安装应用程序django-bootstrap3
(ll_env) [test@test learning_log]$ pip install django-bootstrap3

learning_log/settings.py(添加应用程序)

--snip--

INSTALLED_APPS = (
    --snip--
    'bootstrap3',
    --snip--
)
--snip--

# django-bootstrap3的设置
BOOTSTRAP3 = {
    'include_jquery': True,
}

1 html/base.html

{% load bootstrap3 %}
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Learning Log</title>
    {% bootstrap_css %}
    {% bootstrap_javascript %}
</head>
<body>
    <!-- Static navbar -->
    <nav class="navbar navbar-default navbar-static-top">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed"
                    data-toggle="collapse" data-target="#navbar"
                    aria-expanded="false" aria-controls="navbar">
                </button>
                <a class="navbar-brand" href="{% url 'learning_logs:index' %}">首页</a>
            </div>
            <div id="navbar" class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li><a href="{% url 'learning_logs:topics' %}">图书</a></li>
                </ul>
                <ul class="nav navbar-nav navbar-right">
                    {% if user.is_authenticated %}
                        <li><a>Hello, {{ user.username }}.</a></li>
                        <li><a href="{% url 'users:logout' %}">退出</a></li>
                    {% else %}
                        <li><a href="{% url 'users:register' %}">注册</a></li>
                        <li><a href="{% url 'users:login' %}">登陆</a></li>
                    {% endif %}
                </ul>
            </div><!--/.nav-collapse -->
        </div>
    </nav>
    <div class="container">
        <div class="page-header">
            {% block header %}{% endblock header %}
        </div>
        <div>
            {% block content %}{% endblock content %}
        </div>
    </div> <!-- /container -->
</body>
</html>

2 html/index.html

{% extends "html/base.html" %}
{% block header %}
    <div class='jumbotron'>
        <h3>武侠世界欢迎您!</h3>
    </div>
{% endblock header %}
{% block content %}
<h4>
    武侠小说是中国旧通俗小说的一种重要类型,多以侠客和义士为主人公,描写他们身怀绝技、见义勇为和叛逆*行为。
</h4>
{% endblock content %}

《Python编程:从入门到实践》WEB应用程序 

3 html/topics.html

{% extends "html/base.html" %}
{% block header %}
    <h3>图书列表</h3>
{% endblock header %}
{% block content %}
    <ul>
        {% for topic in topics %}
            <li>
                <h4>
                    <a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}</a>
                </h4>
            </li>
        {% empty %}
            <li>无图书</li>
        {% endfor %}
    </ul>
    <h4><a href="{% url 'learning_logs:new_topic' %}">新增图书</h4>
{% endblock content %}

《Python编程:从入门到实践》WEB应用程序 

4 html/topic.html

{% extends "html/base.html" %}
{% block header %}
    <h3>{{ topic }}</h3>
{% endblock header %}
{% block content %}
    <p>
        <a href="{% url 'learning_logs:new_entry' topic.id %}">添加简介</a>
    </p>
    {% for entry in entries %}
        <div class="panel panel-default">
            <div class="panel-heading">
                <h4>
                    {{ entry.ctime|date:'Y-m-d H:i' }}
                    <small>
                        <a href="{% url 'learning_logs:edit_entry' entry.id %}">编辑简介</a>
                    </small>
                </h4>
            </div>
            <div class="panel-body">
                {{ entry.content|linebreaks }}
            </div>
        </div> <!-- panel -->
    {% empty %}
        无简介
    {% endfor %}
{% endblock content %}

《Python编程:从入门到实践》WEB应用程序 

5 html/new_topic.html

{% extends "html/base.html" %}
{% load bootstrap3 %}
{% block header %}
    <h3>输入图书名:</h3>
{% endblock header %}
{% block content %}
    <form action="{% url 'learning_logs:new_topic' %}" method='post' class="form">
        {% csrf_token %}
        {% bootstrap_form form %}
        {% buttons %}
            <button name="submit" class="btn btn-primary">保存</button>
        {% endbuttons %}
    </form>
{% endblock content %}

《Python编程:从入门到实践》WEB应用程序 

6 html/login.html

{% extends "html/base.html" %}
{% load bootstrap3 %}
{% block header %}
    <h3>登陆您的账户</h3>
{% endblock header %}
{% block content %}
    <form method="post" action="{% url 'users:login' %}" class="form">
        {% 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 %}

《Python编程:从入门到实践》WEB应用程序

本文地址:https://blog.csdn.net/linwenhai2018/article/details/109667274

相关标签: Python django