【Python编程:从入门到实践】第二十章练习题

20-1  其他表单 :我们对登录页面和 add_topic 页面应用了 Bootstrap 样式。请对其他基于表单的页面做类似的修改: new_entry 页面、 edit_entry 页面和注册页面。
20-2  设置博客的样式 :对于你在第 19 章创建的项目 Blog ,使用 Bootstrap 来设置其样式。
20-3  在线博客 :将你一直在开发的项目 Blog 部署到 Heroku 。确保将 DEBUG 设置为 False ,并修改设置 ALLOWED_HOSTS ,让部署相当安全。
20-4  在更多的情况下显示 404 错误页面 :在视图函数 new_entry() 和 edit_entry() 中,也使用函数 get_object_or_404() 。完成这些修改后进行测试:输入类似于 http://localhost:8000/new_entry/99999/ 的 URL ,确认你能够看到 404 错误页面。
20-5  扩展 “ 学习笔记 ”  :在 “ 学习笔记 ” 中添加一项功能,将修改推送到在线部署。尝试做一项简单的修改,如在主页中对项目作更详细的描述;再尝试添加一项更高级的功能,如让用户能够将主题设置为公开的。为此,需要在模型 Topic 中添加一个名为 public 的属性(其默认值为 False ),并在 new_topic 页面中添加一个表单元素,让用户能够将私有主题改为公开的。然后,你需要迁移项目,并修改 views.py ,让未登录的用户也可以看到所有公开的主题。将修改推送到 Heroku 后,别忘了迁移在线数据库。

优化第十七章项目“pizzeria ”,实现过程(部署Heroku未实现):

七.设置项目样式

  1. 执行命令“pip install django-bootstrap3”安装 django-bootstrap3程序,把该程序加入settings.py(图1);为了能使用Bootstrap提供的交互式元素,需要在settings.py加入代码(图2):

    【Python编程:从入门到实践】第二十章练习题_第1张图片

    【Python编程:从入门到实践】第二十章练习题_第2张图片

     

  2. 修改模板base.html(代码1)、index.html(代码2)、login.html(代码3)、register.html(代码4):
    {% load bootstrap3 %}
    
    
    
    
        
        
        
        Pizzas
        
        {% bootstrap_css %}
        {% bootstrap_javascript %}
    
    
    
        
        
        
    {% block content %}{% endblock content %}
    {% extends "pizzas/base.html" %}
    {% block header %}
    

    Track your message.

    {% endblock header %} {% block content %}

    Register an account to make your own pizzeria, and list the pizzas you're learning about.

    Whenever you learn something new about a pizza, make an entry summarizing what you've learned.

    {% endblock content %}
    {% extends "pizzas/base.html" %}
    {% load bootstrap3 %}
    {% block header %}
    

    Log in to your account.

    {% endblock header %} {% block content %}
    {% csrf_token %} {% bootstrap_form form %} {% buttons %} {% endbuttons %}
    {% endblock content %}
    {% extends "pizzas/base.html" %}
    {% load bootstrap3 %}
    {% block header %}
    

    Register an account.

    {% endblock header %} {% block content %}
    {% csrf_token %} {% bootstrap_form form %} {% buttons %} {% endbuttons %}
    {% endblock content %}

     

  3. 修改模板pizzas.html(代码1)、pizza.html(代码2)、new_pizza.html(代码3)、new_topping.html(代码4)、edit_topping.html(代码5):
    {% extends "pizzas/base.html" %}
    {% block header %}
    

    Pizzas

    Add new pizza

    {% endblock header %} {% block content %}
      {% for pizza in pizzas %}
    • { { pizza }} { { pizza.date_added|date:'M d, Y H:i' }}

    • {% empty %}
    • No pizzas have been added yet.
    • {% endfor %}
    {% endblock content %}
    {% extends 'pizzas/base.html' %}
    {% block header %}
    

    { { pizza }}

    Add new topping

    {% endblock header %} {% block content %} {% for topping in toppings %}

    { { topping.date_added|date:'M d, Y H:i' }} edit topping

    { { topping.name|linebreaks }}
    {% empty %} There are no toppings for this pizza yet. {% endfor %} {% endblock content %}
    {% extends "pizzas/base.html" %}
    {% load bootstrap3 %}
    {% block header %}
    

    Add a new pizza:

    {% endblock header %} {% block content %}
    {% csrf_token %} {% bootstrap_form form %} {% buttons %} {% endbuttons %}
    {% endblock content %}
    {% extends "pizzas/base.html" %}
    {% load bootstrap3 %}
    {% block header %}
    

    Add a new topping:

    {% endblock header %} {% block content %}
    {% csrf_token %} {% bootstrap_form form %} {% buttons %} {% endbuttons %}
    {% endblock content %}
    {% extends "pizzas/base.html" %}
    {% load bootstrap3 %}
    {% block header %}
    

    Edit topping:

    {% endblock header %} {% block content %}
    {% csrf_token %} {% bootstrap_form form %} {% buttons %} {% endbuttons %}
    {% endblock content %}

     

  4. 全部页面效果如下(分别index、register、login、pizzas、pizza、new_pizza、new_topping、edit_topping):

    【Python编程:从入门到实践】第二十章练习题_第3张图片

    【Python编程:从入门到实践】第二十章练习题_第4张图片

    【Python编程:从入门到实践】第二十章练习题_第5张图片

    【Python编程:从入门到实践】第二十章练习题_第6张图片

    【Python编程:从入门到实践】第二十章练习题_第7张图片

    【Python编程:从入门到实践】第二十章练习题_第8张图片

    【Python编程:从入门到实践】第二十章练习题_第9张图片

    【Python编程:从入门到实践】第二十章练习题_第10张图片

     

  5. 创建自定义错误页面,路径pizzeria/pizzeria下新建文件夹templates,文件夹新建模板404.html(代码1)、500.html(代码2):
    {% extends "pizzas/base.html" %}
    {% block header %}
    

    The item you requested is not available. (404)

    {% endblock header %}
    {% extends "pizzas/base.html" %}
    {% block header %}
    

    There has been an internal error. (500)

    {% endblock header %}

     

  6. 修改settings.py,使用自定义错误页面模板(图1),禁止默认的Django调试页面(图2,DEBUG设置False时,必须设置ALLOWED_HOSTS):

    【Python编程:从入门到实践】第二十章练习题_第11张图片

    【Python编程:从入门到实践】第二十章练习题_第12张图片

     

  7. 手工请求不存在的pizza或topping时,显示500错误(服务端错误),不符合实际情况;现把这两种情况改成显示404错误,修改pizzas--views.py(使用get_object_or_404):
    from django.shortcuts import render, get_object_or_404
    from django.http import HttpResponseRedirect, Http404
    
    # django2.0后把原来的django.core.urlresolvers包更改为了django.urls包
    from django.urls import reverse
    from django.contrib.auth.decorators import login_required
    from .models import Pizza, Topping
    from .forms import PizzaForm, ToppingForm
    
    # Create your views here.
    def index(request):
        """ 披萨的主页 """
        return render(request, 'pizzas/index.html')
    
    # login_required() 的代码检查用户是否已登录,仅当用户已登录时, Django 才运行 topics() 的代码。如果用户未登录,就重定向到登录页面。
    # @login_required
    def pizzas(request):
        """ 显示所有的配料 """
        if request.user.is_authenticated:
            # 登录状态下,只显示自己的数据
            pizzas = Pizza.objects.filter(owner=request.user).order_by('date_added')
        else:
            # 未登录状态下,显示公开的数据
            pizzas = list(Pizza.objects.all())
            for pizza in pizzas[:]:
                if pizza.public == False:
                    pizzas.remove(pizza)
        context = {'pizzas': pizzas}
        return render(request, 'pizzas/pizzas.html', context)
    
    @login_required
    def pizza(request, pizza_id):
        """ 显示单个披萨及其所有的配料 """
        #   获取不到pizza条目改成显示404
        pizza = get_object_or_404(Pizza, id=pizza_id)
        # 请求的披萨不归当前用户所有,我们就引发 Http404 异常,让 Django 返回一个 404 错误页面
        check_topic_owner(pizza, request)
        #   date_added 前面的减号指定按降序排列
        toppings = pizza.topping_set.order_by('-date_added')
        context = {'pizza': pizza, 'toppings': toppings}
        return render(request, 'pizzas/pizza.html', context)
    
    @login_required
    def new_pizza(request):
        """ 添加新披萨 """
        if request.method != 'POST':
            #  未提交数据:创建一个新表单
            form = PizzaForm()
        else:
            # POST 提交的数据 , 对数据进行处理
            form = PizzaForm(request.POST)
            # is_valid校验填写了必填信息和符合数据类型及长度
            if form.is_valid():
                new_pizza = form.save(commit=False)
                new_pizza.owner = request.user
                new_pizza.save()
                # 将用户重定向到网页 pizzas
                return HttpResponseRedirect(reverse('pizzas:pizzas'))
        context = {'form': form}
        return render(request, 'pizzas/new_pizza.html', context)
    
    @login_required
    def new_topping(request, pizza_id):
        """ 在特定的披萨中添加新配料 """
        # 获取不到配料条目显示404
        pizza = get_object_or_404(Pizza, id=pizza_id)
        # 解决一个用户可在另一个用户的学习笔记中添加条目问题
        check_topic_owner(pizza, request)
    
        if request.method != 'POST':
            #  未提交数据 , 创建一个空表单
            form = ToppingForm()
        else:
            # POST 提交的数据 , 对数据进行处理
            form = ToppingForm(data=request.POST)
            if form.is_valid():
                # 传递了实参commit=False,让Django创建一个新的配料对象,并将其存储到new_topping中,但不将它保存到数据库中
                new_topping = form.save(commit=False)
                new_topping.pizza = pizza
                # 把配料保存到数据库,并将其与正确的披萨相关联
                new_topping.save()
                return HttpResponseRedirect(reverse('pizzas:pizza', args=[pizza_id]))
        context = {'pizza': pizza, 'form': form}
        return render(request, 'pizzas/new_topping.html', context)
    
    @login_required
    def edit_topping(request, topping_id):
        """ 编辑既有配料 """
        # 获取不到配料编辑条目显示404
        topping = get_object_or_404(Topping, id=topping_id)
        pizza = topping.pizza
        check_topic_owner(pizza, request)
        if request.method != 'POST':
            #  初次请求,使用当前条目填充表单(instance=topping)
            form = ToppingForm(instance=topping)
        else:
            # POST 提交的数据,对数据进行处理
            form = ToppingForm(instance=topping, data=request.POST)
            if form.is_valid():
                form.save()
                return HttpResponseRedirect(reverse('pizzas:pizza', args=[pizza.id]))
        context = {'topping': topping, 'pizza': pizza, 'form': form}
        return render(request, 'pizzas/edit_topping.html', context)
    
    def check_topic_owner(pizza, request):
        """校验关联到的用户是否为当前登录的用户"""
        if pizza.owner != request.user:
            raise Http404

     

  8. 给pizza增加设置是否公开的功能,实现当登录状态下,只显示登录用户自己的数据;而未登录状态下,则显示公开的数据;先修改模型Pizza(pizzas--models.py)增加public属性(图1)、修改pizzas--forms.py(图2,增加字段“is public”和显示字段名)、修改pizzas--views.py(图3,判断登录和未登录情况,并注释“@login_required”),最后进行数据迁移(先执行命令“python manage.py makemigrations pizzas”,后执行命令“python manage.py migrate”);登录和未登录显示数据效果图(图4、图5):

    【Python编程:从入门到实践】第二十章练习题_第13张图片

    【Python编程:从入门到实践】第二十章练习题_第14张图片

    【Python编程:从入门到实践】第二十章练习题_第15张图片

    【Python编程:从入门到实践】第二十章练习题_第16张图片

    【Python编程:从入门到实践】第二十章练习题_第17张图片

    总结:到这里全部练习题更新完毕。

你可能感兴趣的:(python,python,django)