《Python编程:从入门到实践》Django部分的更新

前言:

大家可能看过《Python编程:从入门到实践》这本书并跟着学习了Django,这篇博客的目的就是用新的Django(3.0版本,2.+版本也是一样的)来更新一下Django部分的内容。

说明:

此篇博客只用新的Django来更新一下书中不同部分的代码(支持正版,虽然pdf网上到处都有)。完整代码可以看我的码云Github


正文:

learning_log/urls.py

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/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也是一样的


learning_logs/views.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/urls.py

"""为应用程序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'),
]

说明:LoginViewLogoutView分别用于登录和注销,其下方法as_view()的形参template_name用于定义模板的位置。登录的template_name用于定义请求登录的页面,注销的template_name用于定义注销后要跳转到的页面。

users/views.py

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)

引入库的地方不一样。

base.html

--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))

有问题评论区聊。

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值