《Python编程:从入门到实践》WEB应用程序
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/
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/
手工添加主题和内容
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 %}
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 %}
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 %}
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 %}
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 %}
本文地址:https://blog.csdn.net/linwenhai2018/article/details/109667274
下一篇: Java - PriorityQueue