前言:
大家可能看过《Python编程:从入门到实践》这本书并跟着学习了Django,这篇博客的目的就是用新的Django(3.0版本,2.+版本也是一样的)来更新一下Django部分的内容。
说明:
此篇博客只用新的Django来更新一下书中不同部分的代码(支持正版,虽然pdf网上到处都有)。完整代码可以看我的码云或Github。
正文:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('users/', include('users.urls')),
path('', include('learning_logs.urls')),
]
说明:书中urlpatterns
列表里使用url()
来分割url,此处用较新的path()
,其语法类似。命名空间会在[应用程序名]/urls.py
下定义
"""定义learning_logs的URL模式"""
from django.urls import path
from . import views
app_name = 'learning_logs'
urlpatterns = [
# 主页
path('', views.index, name='index'),
# 显示所有的主题
path('topics/', views.topics, name='topics'),
# 特定主题的详细页面
# <int:topic_id>表示接受一个整数,并用变量topic_id保存它
path('topic/<int:topic_id>/', views.topic, name='topic'),
# 用于添加新主题的页面
path('new_topic/', views.new_topic, name='new_topic'),
# 用于添加新条目的页面
path('new_entry/<int:topic_id>/', views.new_entry, name='new_entry'),
# 用于编辑条目的页面
path('edit_entry/<int:entry_id>/', views.edit_entry, name='edit_entry'),
]
说明:app_name
用于定义命名空间和应用程序的名称,也可以在learning_log/urls.py
中这样写:
path('', include(('learning_logs.urls', 'learning_logs'),
namespace='learning_logs')),
如果这样写的话就不需要app_name
了。
在path()
函数中,url中的整数或其他类型的变量值不需要用正则表达式来捕获,比如整数,只需要用<int:name>
的方法就可以将捕获到的url 中int
类型的变量值保存在name
变量中。其他数据类型比如str
类型也是一样。
提示:
users/urls.py
也是一样的
from django.shortcuts import render
from django.http import HttpResponseRedirect, Http404
from django.urls import reverse
from django.contrib.auth.decorators import login_required
from .models import Topic, Entry
from .forms import TopicForm, EntryForm
def check_topic_owner(owner, user):
if owner != user:
raise Http404
def index(request):
"""学习笔记的主页"""
return render(request, 'learning_logs/index.html')
@login_required
def topics(request):
"""显示所有的主题"""
topics = Topic.objects.filter(owner=request.user).order_by('date_added')
context = {'topics': topics}
return render(request, 'learning_logs/topics.html', context)
@login_required
def topic(request, topic_id):
"""显示单个主体及其所有的条目"""
topic = Topic.objects.get(id=topic_id)
# 确认请求的主题属于当前用户
check_topic_owner(topic.owner, request.user)
entries = topic.entry_set.order_by('-date_added')
context = {'topic': topic, 'entries': entries}
return render(request, 'learning_logs/topic.html', context)
@login_required
def new_topic(request):
"""添加新主题"""
if request.method != 'POST':
# 未提交数据,创建一个新表单
form = TopicForm()
else:
# POST提交的数据,对数据进行处理
form = TopicForm(data=request.POST)
if form.is_valid():
new_topic = form.save(commit=False)
new_topic.owner = request.user
form.save()
return HttpResponseRedirect(reverse('learning_logs:topics'))
context = {'form': form}
return render(request, 'learning_logs/new_topic.html', context)
@login_required
def new_entry(request, topic_id):
"""在特定的主题中添加新条目"""
topic = Topic.objects.get(id=topic_id)
check_topic_owner(topic.owner, request.user)
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, 'learning_logs/new_entry.html', context)
@login_required
def edit_entry(request, entry_id):
"""编辑既有条目"""
entry = Entry.objects.get(id=entry_id)
topic = entry.topic
check_topic_owner(topic.owner, request.user)
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, 'learning_logs/edit_entry.html', context)
import 库的地方不一样。
"""为应用程序users定义URL模式"""
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='users/login.html'),
name='login'),
# 注销
path('logout/', LogoutView.as_view(
template_name='learning_logs/index.html'), name='logout'),
# 注册页面
path('register/', views.register, name='register'),
]
说明:LoginView
和LogoutView
分别用于登录和注销,其下方法as_view()
的形参template_name
用于定义模板的位置。登录的template_name
用于定义请求登录的页面,注销的template_name
用于定义注销后要跳转到的页面。
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.contrib.auth import login, authenticate
from django.contrib.auth.forms import UserCreationForm
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, 'users/register.html', context)
引入库的地方不一样。
--snip--
<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>学习笔记</title>
<link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.4.1/css/bootstrap.min.css">
<script src="https://cdn.staticfile.org/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
--snip--
说明:用默认的{% bootstrap_css %}
和{% bootstrap_javascript %}
默认访问的是官网的文件,很慢。所以换成这样用cdn来加速访问。
当然,用别的cdn来加速也是可以的,比如bootstrap官网提到的:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/css/bootstrap.min.css">
<script src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/js/bootstrap.min.js"></script>
用cdn比把css和js文件下载到本地更好,因为可以及时获取更新(而且下载到本地会有问题。我不知道为什么,我试了好多次,用本地的css和js总会有问题(QAQ))
有问题评论区聊。