18-2  简短的条目 :当前, Django 在管理网站或 shell 中显示 Entry 实例时,模型Entry 的方法 __str__() 都在它的末尾加上省略号。请在方法 __str__() 中添加一条 if 语句,以便仅在条目长度超过 50 字符时才添加省略号。使用管理网站来添加一个长度少于 50 字符的条目,并核实显示它时没有省略号。
18-4  比萨店 :新建一个名为 pizzeria 的项目,并在其中添加一个名为 pizzas 的应用程序。定义一个名为 Pizza 的模型,它包含字段 name ,用于存储比萨名称,如 Hawaiian 和 Meat Lovers 。定义一个名为 Topping 的模型,它包含字段 pizza和 name ,其中字段 pizza 是一个关联到 Pizza 的外键,而字段 name 用于存储配料,如 pineapple 、 Canadian bacon 和 sausage 。
向管理网站注册这两个模型,并使用管理网站输入一些比萨名和配料。使用 shell 来查看你输入的数据。
18-6  比萨店主页 :在你为完成练习 18-4 而创建的项目 Pizzeria 中,添加一个主页。
18-8  比萨店页面 :在练习 18-6 中开发的项目 Pizzeria 中添加一个页面,它显示供应的比萨的名称。然后,将每个比萨名称都设置成一个链接,单击这种链接将显示一个页面,其中列出了相应比萨的配料。请务必使用模板继承来高效地创建页面。

19-1 博客 :新建一个 Django 项目,将其命名为 Blog 。在这个项目中,创建一个名为 blogs 的应用程序,并在其中创建一个名为 BlogPost 的模型。这个模型应包含 title 、 text 和 date_added 等字段。为这个项目创建一个超级用户,并使用管理网站创建几个简短的帖子。创建一个主页,在其中按时间顺序显示所有的帖子。
创建两个表单,其中一个用于发布新帖子,另一个用于编辑既有的帖子。
尝试填写这些表单,确认它们能够正确地工作。
19-2 博客账户 :在你为完成练习 19-1 而开发的项目 Blog 中,添加一个用户身份验证和注册系统。让已登录的用户在屏幕上看到其用户
名,并让未注册的用户看到一个到注册页面的链接。
19-3 重构 :在 views.py 中,我们在两个地方核实主题关联到的用户为当前登录的用户。请将执行这种检查的代码放在一个名为 check_topic_owner() 的函数中,并在恰当的地方调用这个函数。
19-4 保护页面 new_entry :一个用户可在另一个用户的学习笔记中添加条目,方法是输入这样的 URL ,即其中包含输入另一个用户的主题的 ID 。为防范这种攻击,请在保存新条目前,核实它所属的主题归当前用户所有。
19-5 受保护的博客 :在你创建的项目 Blog 中,确保每篇博文都与特定用户相关联。确保任何用户都可访问所有的博文,但只有已登录的用户能够发表博文以及编辑既有博文。在让用户能够编辑其博文的视图中,在处理表单前确认用户编辑的是他自己发表的博文。

合并为项目“pizzeria ”,实现过程(Windows系统+python3.8.0+django3.0.1):

一.创建项目

  1. 新建项目目录“pizzeria”后,终端切换到这个目录下,执行命令“python -m venv ll_env”创建一个虚拟环境(虚拟环境是系统的一个位置,可以在其中安装工程包,并将其与其他 Python 包隔离,将项目的库与其他项目分离是有益的。);
  2. 执行命令“source ll_env/Scripts/activate”激活虚拟环境;
  3. 激活虚拟环境后,执行命令“pip install Django”来安装 Django:

  4. 用Django自带的脚手架工具“django-admin.py startproject pizzeria .”创建项目(末尾的句点让新项目使用合适的目录结构,这样开发完成后可轻松地将应用程序部署到服务器);
  5. 执行命令“python manage.py migrate”创建数据库:

二.创建应用程序

  1. 执行命令“python manage.py startapp pizzas”创建应用程序;

  2. 定义模型“Pizza ”和“Topping”(pizzas--models.py):
    from django.db import models# Create your models here.
    class Pizza(models.Model):""" 披萨 """#     由字符或文本组成的数据(限制长度100)name = models.CharField(max_length=100)#    记录日期和时间的数据(自动创建当前时间)date_added = models.DateTimeField(auto_now_add=True)def __str__(self):return self.name
    class Topping(models.Model):""" 配料 """#   外键实例#   django 升级到2.0之后,表与表之间关联的时候,必须要写on_delete参数#     由于多对多(ManyToManyField)没有 on_delete 参数,所以以上只针对外键(ForeignKey)和一对一(OneToOneField)pizza = models.ForeignKey(Pizza, on_delete=models.CASCADE)name = models.TextField()date_added = models.DateTimeField(auto_now_add=True)def __str__(self):""" 返回模型的字符串表示 """#   长于50字符才截取和显示省略号if len(self.name) > 50:return self.name[:50] + "..."else:return self.name
  3. 要使用模型,必须让 Django 将应用程序包含到项目中(pizzeria--settings.py):

  4. 执行命令“python manage.py makemigrations”创建迁移文件,然后执行命令“python manage.py migrate”进行数据库迁移(每次数据的修改,都需要执行以下三个步骤:修改models.py---创建迁移文件---进行数据库迁移):

  5. Git Bash执行命令“python manage.py createsuperuser”(创建超级用户)会报错“Superuser creation skipped due to not running in a TTY. You can run `manage.py c reatesuperuser` in your project to create one manually.”;需改成cmd执行,执行之前先激活虚拟环境“ll_env\Scripts\activate”,然后再执行“python manage.py createsuperuser”创建用户:

  6. 进行模型注册(pizzas--admin.py):
    from django.contrib import admin
    from pizzas.models import Pizza, Topping# Register your models here.
    admin.site.register(Pizza)
    admin.site.register(Topping)
  7. 访问“http://127.0.0.1:8001/admin/login/”,并输入你创建的用户名和密码进行登录,首页显示如下:

三.创建网页(首页和其他页面)

  1. pizzas路由表接入到全局路由表(pizzeria--urls.py)并实现应用pizzas的路由表(文件夹 pizzas 中创建另一个 urls.py 文件):

    # 导入项目和网站管理 URL 的函数和模块
    from django.conf.urls import include, url
    from django.contrib import admin
    urlpatterns = [url(r'^admin/', admin.site.urls),# namespace 将 pizzas 的 URL 同项目中的其他 URL 区分开来#     源码函数def include(arg, namespace=None)中“urlconf_module, app_name = arg”,所以arg需要传入一个两元元组url(r'', include(('pizzas.urls', 'pizzas'), namespace='pizzas')),
    ]
    """ 定义 pizzas 的 URL 模式 """
    from django.conf.urls import url
    from . import views
    urlpatterns = [# 主页#    r让Python将接下来的字符串视为原始字符串,而引号告诉 Python 正则表达式始于和终于何处。脱字符( ^ )让 Python 查看字符串的开头,#    而美元符号让 Python 查看字符串的末尾。总体而言,这个正则表达式让 Python 查找开头和末尾之间没有任何东西的 URL 。url(r'^$', views.index, name='index'),# 显示所有的配料url(r'^pizzas/$', views.pizzas, name='pizzas'),# 特定主题的详细页面#    r 让 Django 将这个字符串视为原始字符串,并指出正则表达式包含在引号内。#    这个表达式的第二部分( /(?P<pizza_id>\d+)/ )与包含在两个斜杠内的整数匹配,并将这个整数存储在一个名为 pizza_id 的实参中。#    这部分表达式两边的括号捕获 URL 中的值; ?P<pizza_id> 将匹配的值存储到 pizza_id 中;#    而表达式 \d+ 与包含在两个斜杆内的任何数字都匹配,不管这个数字为多少位。url(r'^pizza/(?P<pizza_id>\d+)/$', views.pizza, name='pizza'),
    ]
  2. 编写视图(pizzas--views.py):
    from django.shortcuts import render
    from .models import Pizza# Create your views here.
    def index(request):""" 披萨的主页 """return render(request, 'pizzas/index.html')def pizzas(request):""" 显示所有的配料 """pizzas = Pizza.objects.order_by('date_added')context = {'pizzas': pizzas}return render(request, 'pizzas/pizzas.html', context)def pizza(request, pizza_id):""" 显示单个披萨及其所有的配料 """pizza = Pizza.objects.get(id=pizza_id)#     date_added 前面的减号指定按降序排列toppings = pizza.topping_set.order_by('-date_added')context = {'pizza': pizza, 'toppings': toppings}return render(request, 'pizzas/pizza.html', context)
  3. 在文件夹 pizzas 中新建文件夹 templates--> 新建文件夹pizzas,为了使用模板继承来高效地创建页面,在末级pizzas新建文件base.html,编写代码如下:
    <p><a href="{% url 'pizzas:index' %}">pizzeria</a> -<a href="{% url 'pizzas:pizzas' %}">pizzas</a>
    </p>
    {% block content %}{% endblock content %}
  4. 在末级pizzas新建文件index.html(图1)、pizzas.html(图2)和pizza.html(图3),编写代码如下:
    {% extends "pizzas/base.html" %}
    {% block content %}<p>Pizza, also known as Pizza, Pizza, Pizza, Pizza, is a food originated in Italy, is popular around the world.Pizza is usually made from fermented pita covered with tomato sauce, cheese and other ingredients and baked in an oven.</p>
    {% endblock content %}
    {% extends "pizzas/base.html" %}
    {% block content %}
    <p>Pizzas</p>
    <ul>{% for pizza in pizzas %}<li><a href="{% url 'pizzas:pizza' pizza.id %}">{{ pizza }}</a></li>{% empty %}<li>No pizzas have been added yet.</li>{% endfor %}
    </ul>
    {% endblock content %}
    {% extends 'pizzas/base.html' %}
    {% block content %}
    <p>Pizza: {{ pizza }}</p>
    <p>Toppings:</p>
    <ul>{% for topping in toppings %}<li><!-- 竖线( | )表示模板过滤器 --><p>{{ topping.date_added|date:'M d, Y H:i' }}</p><p>{{ topping.name|linebreaks }}</p></li>{% empty %}<li>There are no toppings for this pizza yet.</li>{% endfor %}
    </ul>
    {% endblock content %}

四.增加编辑披萨和配料功能

  1. 添加披萨和配料的表单(forms.py):

    from django import forms
    from .models import Pizza, Topping
    class PizzaForm(forms.ModelForm):class Meta:model = Pizzafields = ['name']# 让 Django 不要为字段 name 生成标签labels = {'name': ''}class ToppingForm(forms.ModelForm):class Meta:model = Toppingfields = ['name']labels = {'name': ''}# 设置属性widgets,可覆盖Django选择的默认小部件# 文本区域改成80列(非默认的40列)widgets = {'name': forms.Textarea(attrs={'cols': 80})}
  2. 应用pizzas的路由表增加新路由(后面三个):
    """ 定义 pizzas 的 URL 模式 """
    from django.conf.urls import url
    from . import views
    urlpatterns = [# 主页#    r让Python将接下来的字符串视为原始字符串,而引号告诉 Python 正则表达式始于和终于何处。脱字符( ^ )让 Python 查看字符串的开头,#   而美元符号让 Python 查看字符串的末尾。总体而言,这个正则表达式让 Python 查找开头和末尾之间没有任何东西的 URL 。url(r'^$', views.index, name='index'),# 显示所有的配料url(r'^pizzas/$', views.pizzas, name='pizzas'),# 特定主题的详细页面#    r 让 Django 将这个字符串视为原始字符串,并指出正则表达式包含在引号内。#    这个表达式的第二部分( /(?P<pizza_id>\d+)/ )与包含在两个斜杠内的整数匹配,并将这个整数存储在一个名为 pizza_id 的实参中。#    这部分表达式两边的括号捕获 URL 中的值; ?P<pizza_id> 将匹配的值存储到 pizza_id 中;#    而表达式 \d+ 与包含在两个斜杆内的任何数字都匹配,不管这个数字为多少位。url(r'^pizza/(?P<pizza_id>\d+)/$', views.pizza, name='pizza'),# 用于添加新披萨的页面url(r'^new_pizza/$', views.new_pizza, name='new_pizza'),# 用于添加新配料的页面url(r'^new_topping/(?P<pizza_id>\d+)/$', views.new_topping, name='new_topping'),# 用于编辑配料的页面url(r'^edit_topping/(?P<topping_id>\d+)/$', views.edit_topping, name='edit_topping'),
    ]
  3. 修改视图(pizzas--views.py):
    from django.shortcuts import render
    from django.http import HttpResponseRedirect# django2.0后把原来的django.core.urlresolvers包更改为了django.urls包
    from django.urls import reverse
    from .models import Pizza, Topping
    from .forms import PizzaForm, ToppingForm# Create your views here.
    def index(request):""" 披萨的主页 """return render(request, 'pizzas/index.html')def pizzas(request):""" 显示所有的配料 """pizzas = Pizza.objects.order_by('date_added')context = {'pizzas': pizzas}return render(request, 'pizzas/pizzas.html', context)def pizza(request, pizza_id):""" 显示单个披萨及其所有的配料 """pizza = Pizza.objects.get(id=pizza_id)#     date_added 前面的减号指定按降序排列toppings = pizza.topping_set.order_by('-date_added')context = {'pizza': pizza, 'toppings': toppings}return render(request, 'pizzas/pizza.html', context)def new_pizza(request):""" 添加新披萨 """if request.method != 'POST':#  未提交数据:创建一个新表单form = PizzaForm()else:# POST 提交的数据 , 对数据进行处理form = PizzaForm(request.POST)# is_valid校验填写了必填信息和符合数据类型及长度if form.is_valid():form.save()# 将用户重定向到网页 pizzasreturn HttpResponseRedirect(reverse('pizzas:pizzas'))context = {'form': form}return render(request, 'pizzas/new_pizza.html', context)def new_topping(request, pizza_id):""" 在特定的披萨中添加新配料 """pizza = Pizza.objects.get(id=pizza_id)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)def edit_topping(request, topping_id):""" 编辑既有配料 """topping = Topping.objects.get(id=topping_id)pizza = topping.pizzaif 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)
  4. 新建模板new_pizza.html(图1)、new_topping.html(图2)、edit_topping.html(图3):
    {% extends "pizzas/base.html" %}
    {% block content %}
    <p>Add a new pizza:</p>
    <form action="{% url 'pizzas:new_pizza' %}" method='post'><!-- 防止攻击者利用表单来获得对服务器未经授权的访问 -->{% csrf_token %}<!-- 显示表单(段落格式渲染) -->{{ form.as_p }}<button name="submit">add pizza</button>
    </form>
    {% endblock content %}
    {% extends "pizzas/base.html" %}
    {% block content %}
    <p><a href="{% url 'pizzas:pizza' pizza.id %}">{{ pizza }}</a></p>
    <p>Add a new topping:</p>
    <form action="{% url 'pizzas:new_topping' pizza.id %}" method='post'>{% csrf_token %}{{ form.as_p }}<button name='submit'>add topping</button>
    </form>
    {% endblock content %}
    {% extends "pizzas/base.html" %}
    {% block content %}
    <p><a href="{% url 'pizzas:pizza' pizza.id %}">{{ pizza }}</a></p>
    <p>Edit topping:</p>
    <form action="{% url 'pizzas:edit_topping' topping.id %}" method='post'>{% csrf_token %}{{ form.as_p }}<button name="submit">save changes</button>
    </form>
    {% endblock content %}
  5. 修改模板pizzas.html(图1)、pizza.html(图2):
    {% extends "pizzas/base.html" %}
    {% block content %}
    <p>Pizzas</p>
    <ul>{% for pizza in pizzas %}<li><a href="{% url 'pizzas:pizza' pizza.id %}">{{ pizza }}</a></li>{% empty %}<li>No pizzas have been added yet.</li>{% endfor %}
    </ul>
    <a href="{% url 'pizzas:new_pizza' %}">Add a new pizza:</a>
    {% endblock content %}
    {% extends 'pizzas/base.html' %}
    {% block content %}
    <p>Pizza: {{ pizza }}</p>
    <p>Toppings:</p>
    <p><a href="{% url 'pizzas:new_topping' pizza.id %}">add new topping</a>
    </p>
    <ul>{% for topping in toppings %}<li><!-- 竖线( | )表示模板过滤器 --><p>{{ topping.date_added|date:'M d, Y H:i' }}</p><p>{{ topping.name|linebreaks }}</p><p><a href="{% url 'pizzas:edit_topping' topping.id %}">edit topping</a></p></li>{% empty %}<li>There are no toppings for this pizza yet.</li>{% endfor %}
    </ul>
    {% endblock content %}

五.创建用户账户(登录、注销和注册)

  1. 执行命令“python manage.py startapp users”创建“users”的应用程序;
  2. 将应用程序 users 添加到 settings.py 中:

  3. users路由表接入到全局路由表(pizzeria--urls.py)并实现应用users的路由表(文件夹 users 中创建另一个 urls.py 文件):
    # 导入项目和网站管理 URL 的函数和模块
    from django.conf.urls import include, url
    from django.contrib import admin
    urlpatterns = [url(r'^admin/', admin.site.urls),url(r'^users/', include(('users.urls', 'users'), namespace='users')),# namespace 将 pizzas 的 URL 同项目中的其他 URL 区分开来#   源码函数def include(arg, namespace=None)中“urlconf_module, app_name = arg”,所以arg需要传入一个两元元组url(r'', include(('pizzas.urls', 'pizzas'), namespace='pizzas')),
    ]
    """ 为应用程序 users 定义 URL 模式 """
    from django.conf.urls import url
    from django.contrib.auth.views import LoginView
    from . import viewsurlpatterns = [#登录界面  LoginView.as_view后面要加上()url(r'^login/$', LoginView.as_view(template_name='users/login.html'), name='login'),# 注销url(r'^logout/$', views.logout_view, name='logout'),# 注册页面url(r'^register/$', views.register, name='register'),
    ]
  4. 在文件夹 users 中新建文件夹 templates--> 新建文件夹users,在末级users新建文件login.html(图1)和register.html(图2),编写代码如下:
    {% extends "pizzas/base.html" %}
    {% block content %}{% if form.errors %}<p>Your username and password didn't match. Please try again.</p>{% endif %}<form method="post" action="{% url 'users:login' %}">{% csrf_token %}{{ form.as_p }}<button name="submit">log in</button><input type="hidden" name="next" value="{% url 'pizzas:index' %}" /></form>
    {% endblock content %}
    {% extends "pizzas/base.html" %}
    {% block content %}<form method="post" action="{% url 'users:register' %}">{% csrf_token %}{{ form.as_p }}<button name="submit">register</button><input type="hidden" name="next" value="{% url 'pizzas:index' %}" /></form>
    {% endblock content %}
  5. 修改base.html页面内容:
    <p><a href="{% url 'pizzas:index' %}">pizzeria</a> -<a href="{% url 'pizzas:pizzas' %}">pizzas</a> -{% if user.is_authenticated %}Hello, {{ user.username }}.<a href="{% url 'users:logout' %}">log out</a>{% else %}<a href="{% url 'users:register' %}">register</a> -<a href="{% url 'users:login' %}">log in</a>{% endif %}
    </p>
    {% block content %}{% endblock content %}
  6. 修改视图(users--views.py):
    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 UserCreationFormdef logout_view(request):""" 注销用户 """logout(request)return HttpResponseRedirect(reverse('pizzas: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('pizzas:index'))context = {'form': form}return render(request, 'users/register.html', context)

六.让用户拥有自己的数据

  1. 使用 @login_required 限制访问,除了首页、登录页面和注册页面,其它页面都只有已登录的用户才能访问数据;
  2. 只允许用户访问自己的数据,合并1的代码如下(pizzas-views.py):
    from django.shortcuts import render
    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):""" 显示所有的配料 """pizzas = Pizza.objects.filter(owner=request.user).order_by('date_added')context = {'pizzas': pizzas}return render(request, 'pizzas/pizzas.html', context)@login_required
    def pizza(request, pizza_id):""" 显示单个披萨及其所有的配料 """pizza = Pizza.objects.get(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.usernew_pizza.save()# 将用户重定向到网页 pizzasreturn HttpResponseRedirect(reverse('pizzas:pizzas'))context = {'form': form}return render(request, 'pizzas/new_pizza.html', context)@login_required
    def new_topping(request, pizza_id):""" 在特定的披萨中添加新配料 """pizza = Pizza.objects.get(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):""" 编辑既有配料 """topping = Topping.objects.get(id=topping_id)pizza = topping.pizzacheck_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
  3. settings.py末尾添加“LOGIN_URL = '/users/login/'”,使未登录时访问到校验需要登录的页面,重定向到登录页面;
  4. 将数据关联到用户,先修改models.py(图1,pizza增加用户外键),然后查找所有用户ID---使其数据(pizza)关联到超级用户---迁移数据库(图2);
    from django.db import models
    from django.contrib.auth.models import User# Create your models here.
    class Pizza(models.Model):""" 披萨 """#   由字符或文本组成的数据(限制长度100)name = models.CharField(max_length=100)#   记录日期和时间的数据(自动创建当前时间)date_added = models.DateTimeField(auto_now_add=True)owner = models.ForeignKey(User, on_delete=models.CASCADE)def __str__(self):return self.name
    class Topping(models.Model):""" 配料 """#   外键实例#   django 升级到2.0之后,表与表之间关联的时候,必须要写on_delete参数#   由于多对多(ManyToManyField)没有 on_delete 参数,所以以上只针对外键(ForeignKey)和一对一(OneToOneField)pizza = models.ForeignKey(Pizza, on_delete=models.CASCADE)name = models.TextField()date_added = models.DateTimeField(auto_now_add=True)def __str__(self):""" 返回模型的字符串表示 """#   长于50字符才截取和显示省略号if len(self.name) > 50:return self.name[:50] + "..."else:return self.name

  5. 切换不同用户登录只能查看自己的数据,访问非自己数据的URL提示404错误:

    总结,整个项目结构如下:

【Python编程:从入门到实践】第十八章和第十九章练习题(Django创建网站)相关推荐

  1. 《Python编程 从入门到实践》 一、基础知识 第六章 字典

    6.1一个简单的字典 来看一个游戏,其中包含一些外星人,这些外星人的颜色和点数各不相同,下面是一个简单的字典,存储了有关特定外星人的信息: alien_0={'color':'green','poin ...

  2. 《Python编程从入门到实践》学习笔记8(第9章:类)

    笔者从昨天开始感觉到了课程的难度,接下来不能简单的概括知识点.笔者将会按照书上的标题章节来整理知识点.这样看起来会更加直观. 9.1 创建类和使用类 9.1.1 创建Dog类 1 class Dog( ...

  3. 《Python编程从入门到实践》(第2版)第二章 习题答案

    练习2-1:简单消息 将一条消息赋给变量,并将其打印出来. message = "Hello World!" print(message) Hello World! 练习2-2:多 ...

  4. 《Python编程 从入门到实践》第八章 ——函数习题

    8-1       编写一个名为display_message()的函数,指出你在本章学的是什么.调用这个函数,确认显示的消息正确无误. def display_message():     '''本 ...

  5. python编程 从入门到实践豆瓣-三周刷完《Python编程从入门到实践》的感受

    本文将以对话采访的形式展现 为什么会选择学习Python 语法简洁,实用,和golang部分类似,学习性价比高: 应用范围广,涉及后端,机器学习,图像处理,游戏等: 好奇这是一门怎样的语言 计划如何学 ...

  6. python编程 从入门到实践怎么样-python编程从入门到实践这本书怎么样

    <Python编程-从入门到实践>作者: Eric Matthes,已翻译为中文,人民邮电出版社出版. python编程从入门到实践怎么样? 我们一起看看已经学习的同学对这本书的口碑和评价 ...

  7. python编程入门指南怎么样-python编程从入门到实践这本书怎么样

    <Python编程-从入门到实践>作者: Eric Matthes,已翻译为中文,人民邮电出版社出版. python编程从入门到实践怎么样? 我们一起看看已经学习的同学对这本书的口碑和评价 ...

  8. python编程从入门到实践 第18章Django入门 2022年最新

    说明:这篇文章只是记录自己自学本书的一个痕迹,日后来看作为一个念想.至于做为公开,是希望对一些同样跟我一样的朋友有一点点帮助,当然我本人就是小白,帮助可能也不大哈哈. 这篇文章记录了<pytho ...

  9. 《Python编程从入门到实践》袁国忠 译 P1~P200学习笔记

    <Python编程从入门到实践>袁国忠 译 P1~P200 学习笔记 <Python编程从入门到实践>袁国忠 译 P1~P200之前两天在学习时做的笔记总结,在这里也记录一下, ...

  10. 《Python编程从入门到实践》,留言送5本

    你好,我是 zhenguo 我每次送书,一定必选经典.今天图灵出版社的这本<Python编程从入门到实践>,就很值得一读,强调入门学习Python的动手和实践,是一本经典好书.今天一共赠送 ...

最新文章

  1. 为什么深度学习不能取代传统的计算机视觉技术?
  2. 全球16家超级独角兽公司,为什么中国能占7家,印度只有1家?未来哪些行业最可能诞生独角兽?
  3. 山东工商学院计算机科学与技术分数线,山东工商学院计算机科学与技术专业2016年在山东理科高考录取最低分数线...
  4. 【Linux】一步一步学Linux——help命令(16)
  5. 如何把SAP CRM产品主数据隐藏的batch ID字段显示出来
  6. JAVA并发编程实战---第三章:对象的共享(2)
  7. 【剑指offer】面试题31:栈的压入,弹出序列
  8. 大分区表高并发性能提升100倍?阿里云 RDS PostgreSQL 12 解读
  9. principle中文_principle与principal,长得像,发音还一样!又头疼了!
  10. 以太坊 solidity 函数的完整声明格式
  11. 转 Kafka入门经典教程
  12. 中国三级流域空间分布数据/国家新区分布数据/NPP净初级生产力数据/植被覆盖空间分布数据/土地利用数据/NDVI数据/植被类型分布/土壤类型数据
  13. 基础电路设计知识:电阻、电容、电感、二极管、三极管、mos管!
  14. 解析函数的幂级数理论【无穷级数收敛性】
  15. VBA写一个下拉复选框,以及循环判断,附代码
  16. CwRsync | Windows与Windows之间同步备份配置详解
  17. 多维数据库概述之一---多维数据库的选择
  18. 服务器u单核性能排行,CPU单核性能天梯图2021 2021年最新CPU单核性能排行天梯图...
  19. 用python做梦幻手游刷宝图脚本
  20. 无数的讽刺侮辱挖苦打击否定不屑与嘲笑,只有罗永浩才撑得住吧

热门文章

  1. dual,rowid,rownum
  2. 【机器学习】朴素贝叶斯(多分类版本)—— python3 实现方案
  3. 网络管理之网络状态测试命令
  4. 苹果6s出现连接不上服务器未响应,苹果6s的蜂窝移动数据打开没反应怎么办
  5. (项目)在线教育平台(九)
  6. 赵丽5500 第一节课
  7. 戏说python模块
  8. 电商平台-商品表的设计
  9. 图像质量评价方法PSNR+SSIM 评估指标SROCC,PLCC——简记
  10. OrCAD Capture CIS 怎样修改Title_Block