《Python编程:从入门到实践》第19章笔记:用户/用户注册/身份验证

人工智能121

接上篇django最基本的一些日常用法,这是第19章笔记,希望在做"动手试一试"的时候可以让自己方便参考。

本章实现两个功能:

[En]

This chapter implements two functions:

1、让用户能够添加主题Topic和条目Entry,以及编辑既有的条目。

2、建立一个用户注册和身份验证系统,让用户能够注册账户,进而登录和注销。

让用户能够输入数据

一、让用户能够添加新主题(Topic)

关于表单

允许用户输入和提交信息的页面是表单。当用户进入时,我们需要验证提供的信息是正确的数据类型,而不是恶意信息。然后我们对有效信息进行处理,并将其保存到数据库中的适当位置。

[En]

Pages that allow users to enter and submit information are forms. When the user enters, we need to verify that the information provided is the correct data type, not malicious information. Then we process the valid information and save it to the appropriate place in the database.

在Django中,可使用ModelForm创建表单

在models.py所在目录创建forms.py文件。

from django import forms
from .models import Topic

class TopicForm(forms.ModelForm):
    class Meta:
        model = Topic
        fields = ['text']
        labels = {'text': ''}

其中内嵌的Meta类告诉Django根据哪个模型创建表单,以及在表单中包含哪些字段。

URL

在learning_logs/urls.py中

path('new_topic/', views.new_topic, name='new_topic'),

视图

views.py中加入如下内容

from django.http import HttpResponseRedirect
from django.urls import reverse
from .forms import TopicForm

def new_topic(request):
    # 如果未提交数据,创建一个新表单
    if request.method != 'POST':
        form = TopicForm()

    # 否则对数据进行处理
    else:
        # 用户输入的数据存在request.POST中
        form = TopicForm(request.POST)
        # 检查是否有效,有效就保存
        if form.is_valid():
            form.save()
            #保存后就可离开这个页面了,用reverse()获取也页面topics的URL
            return HttpResponseRedirect(reverse('learning_logs:topics'))

    context = {'form': form}
    return render(request, 'learning_logs/new_topic.html', context)

  • 导入部分
  • 导入HttpResponseRedirect类,用户提交主题后使用这个类将用户重定向到网页topics。
  • 函数reverse()根据指定的URL模型确定URL。
  • 关于GET请求和POST请求 ​ 从服务器读取数据的页面,使用GET请求;需要通过表单提交信息时,通常使用POST请求。 ​ 函数new_topic()将请求对象作为参数。用户初次请求该网页时,其浏览器将发送GET请求;用户填写并提交表单时,其浏览器将发送POST请求。根据请求的类型,我们可以确定用户请求的是空表单(GET请求)还是要求对填写好的表单进行处理(POST请求)

模板

创建new_topic.html

{% extends "learning_logs/base.html" %}

{% block content %}
  Add a new topic:

  {% csrf_token %}
  {{ form.as_p }}
  add topic

{% endblock content %}
  • Django使用模板标签{% csrf_token %}来防止攻击者利用表单来获取对服务器未经授权的访问(跨站请求伪造)
  • 修饰符as_p让Django以段落格式渲染所有表单元素。

链接

在页面topics中添加一个到页面new_topic的链接

加入

<a href="{% url 'learning_logs:new_topic' %}">Add a new topic:</a>

二、让用户能够添加新条目(Entry)

表单

form.py

class EntryForm(forms.ModelForm):
    class Meta:
        model = Entry
        fields = ['text']
        labels = {'text': ''}
        widgets = {'text': forms.Textarea(attrs={'cols': 80})}

其中设置属性widgets可以覆盖Django选择的默认小部件。这里让Django使用forms.Textarea,定制来字段'text'的输入小部件,将文本区域的宽度设置为80列。

URL

在learning_logs/urls.py中加入:

path('new_entry/<int:topic_id>', views.new_entry, name='new_entry'),</int:topic_id>

视图

views.py

def new_entry(request, topic_id):
    _topic = Topic.objects.get(id=topic_id)

    if request.method != 'POST':
        form = EntryForm()
    else:
        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)

这个与前面new_topic()类似,区别是

  • 调用save()时,传递来实参commit=False,让Django创建一个新的Entry对象,并将其存储到new_entry中,但不将它保存到数据库中。
  • 调用reverse()时,列表args,其中包含在URL中的所有实参,这里列表中只有一个元素topic_id。

模板

new_entry.html

{% extends "learning_logs/base.html" %}

{% block content %}

{{ topic }}

Add a new entry:

    {% csrf_token %}
    {{ form.as_p }}
    add entry

{% endblock content %}

其中,表单的实参action包含URL中的topic_id,让视图函数能够将新entry关联到正确的主题。

链接

在topic.html中加入


    add new entry

三、让用户能够编辑既有条目

URL

    path('edit_entry/', views.edit_entry, name='edit_entry'),

视图

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

模板

edit_entry.html

{% extends "learning_logs/base.html" %}

{% block content %}

{{ topic }}

Edit entry:

    {% csrf_token %}
    {{ form.as_p }}
    save changes

{% endblock content %}

链接

在topic.html中加入


     edit entry

用户注册和身份验证系统

一、创建用户账户

创建应用程序users

输入命令: python manage.py startapp users

将users添加到settings.py中: &#x5728;INSTALLED_APPS&#x52A0;&#x5165; 'users'

应用程序users的URL:在项目根目录的urls.py 加入 path('users/', include('users.urls')),

登录页面

在users中新建一个urls.py
from django.urls import path
from django.contrib.auth.views import LoginView

from . import views

app_name = 'users'
urlpatterns = [
    path('login/', LoginView.as_view(template_name='users/login.html'),
         name='login'),
]

这里书上是旧版,前面引用的是 from django.contrib.auth.views import login,而新版的Django中内置登录视图不再是函数了,而是类。类视图有个as_view方法,template_name是类视图中的一个变量,默认值是"registration/login.html"。

模板

在users中创建一个名为templates的目录,再在该目录下创建一个名为users的目录。在其中login.html

{% extends "learning_logs/base.html" %}

{% block content %}
{% if form.errors %}
Your username and password didn't match. Please try again.

{% endif %}

    {% csrf_token %}
    {{ form.as_p }}

    log in

{% endblock content %}
链接

在base.html中添加登录页面的链接,改成这样


    Learning Log -
    Topics
    {% if user.is_authenticated %}
    Hello, {{user.username}}.

    {% else %}
    log in
    {% endif%}

用户注销

允许用户通过单击链接注销并返回主页。

[En]

Allows the user to log out and return to the home page by clicking a link.

URL

users/urls.py中: path('logout/', views.logout_view, name='logout'),

视图

users/views.py

from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.contrib.auth import logout

def logout_view(request):
    logout(request)
    return HttpResponseRedirect(reverse('learning_logs:index'))
链接

在在base.html中添加注销链接,改成这样


    Learning Log -
    Topics
    {% if user.is_authenticated %}
    Hello, {{user.username}}.

    log out
    {% else %}
    log in
    {% endif%}

注册界面

url: path('register/', views.register, name='register'),

视图

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 UserCreationForm

# Create your views here.

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, 'users/register.html', context)

模板

register.html

{% extends "learning_logs/base.html" %}

{% block content %}

    {% csrf_token %}
    {{ form.as_p }}

    register

{% endblock content %}
链接

base.html加入 <a href="{% url 'users:register' %}">register</a>

二、让用户拥有自己的数据

在这里,您需要确定每个数据属于哪些用户,然后限制对页面的访问,以便用户只能使用自己的数据。

[En]

Here, you need to determine which users each data belongs to, and then restrict access to the page so that users can only use their own data.

使用@login_required限制访问

在函数前面添加此修饰符。它的代码检查用户是否登录,只有在登录时才运行以下函数的代码。如果您未登录,请重定向至登录界面。

[En]

Add this decorator in front of the function. Its code checks whether the user is logged in, and runs the code of the following function only when logged in. Redirect to the login interface if you are not logged in.

为了实现重定向,修改settings.py,在末尾添加: LOGIN_URL = '/users/login/'

然后把learning_logs/views.py中除了index的每个函数都加上这个装饰器。

将数据关联到用户

修改models.py中的Topic

from django.contrib.auth.models import User

再在Topic类中加上字段owner: owner = models.ForeignKey(User)

可以通过shell查看现在有哪些用户:

《Python编程:从入门到实践》第19章笔记:用户/用户注册/身份验证

迁移数据库

python manage.py makemigrations learning_logs

出现提示,选1

It is impossible to add a non-nullable field 'owner' to topic without specifying a default. This is because 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 manually define a default value in models.py.

Select an option:

下面输入的值是将主题(Topic)关联到的用户id号,这里1,关联到eisen

Please enter the default value as valid Python.

The datetime and django.utils.timezone modules are available, so it is possible to provide e.g. timezone.now as a value.

Type 'exit' to exit this prompt
>>> 1

然后 python manage.py migrate

然后可通过shell看到每个Topic所属的User了,都是eisen。

《Python编程:从入门到实践》第19章笔记:用户/用户注册/身份验证

只允许用户访问自己的主题

经过上面操作,虽然......

但是登录了eisen后,复制这个页面的URL localhost:8000/topics/2,登录JX帐号后再输入这个URL也看到下面的内容了。

《Python编程:从入门到实践》第19章笔记:用户/用户注册/身份验证

做点修改即可,views.py中topics函数中,加个fliter,让Django只从数据库中获取owner属性为当前用户的Topic对象。

_topics = Topic.objects.filter(owner=request.user).order_by('date_added')

再限制用户对单个主题的页面的访问。在topic函数中,加个判断,如果不属于这个用户就404

@login_required
def topic(request, topic_id):
    _topic = Topic.objects.get(id=topic_id)
    if _topic.owner != request.user:
        raise Http404
    entries = _topic.entry_set.order_by('-date_added')
    context = {'topic': _topic, 'entries': entries}
    return render(request, 'learning_logs/topic.html', context)

edit_entry中也一样加入这个判断 if _topic.owner != request.user:raise Http404

新主题创建时也应关联到当前用户

new_topic函数中,判断有效后,先调用form.save并传递实参commit=False,先修该新主题,在将其保存到数据库中。再将owner属性设置为当前用户。

        if form.is_valid():
            _new_topic = form.save(commit=False)
            _new_topic.owner = request.user
            _new_topic.save()
            return HttpResponseRedirect(reverse('learning_logs:topics'))

于是就成功了。

最后贴几张图:

《Python编程:从入门到实践》第19章笔记:用户/用户注册/身份验证

《Python编程:从入门到实践》第19章笔记:用户/用户注册/身份验证

《Python编程:从入门到实践》第19章笔记:用户/用户注册/身份验证

《Python编程:从入门到实践》第19章笔记:用户/用户注册/身份验证

《Python编程:从入门到实践》第19章笔记:用户/用户注册/身份验证

《Python编程:从入门到实践》第19章笔记:用户/用户注册/身份验证

《Python编程:从入门到实践》第19章笔记:用户/用户注册/身份验证

Original: https://www.cnblogs.com/eisenji/p/16526726.html
Author: EisenJi
Title: 《Python编程:从入门到实践》第19章笔记:用户/用户注册/身份验证



相关阅读

Title: Opencv之图像边缘检测:3.Laplacian算子(cv2.Laplacian)

3.1 原理介绍

Laplacian(拉普拉斯)算子是一种二阶导数算子,其具有旋转不变性,可以满足不同方向的图像边缘锐化(边缘检测)的要求。通常情况下,其算子的系数之和需要为零。例 如,一个3×3大小的Laplacian算子如图所示。

《Python编程:从入门到实践》第19章笔记:用户/用户注册/身份验证

Laplacian算子类似二阶Sobel导数,需要计算两个方向的梯度值。例如,在图中:

《Python编程:从入门到实践》第19章笔记:用户/用户注册/身份验证

检测值 =(P2+P4+P6+P8)-4*P5

需要注意,在上述图像中,计算结果的值可能为正数,也可能为负数。所以,需要对计算结果取绝对值,以保证后续运算和显示都是正确的。

该函数分别对x、y方向进行二次求导,具体为:

《Python编程:从入门到实践》第19章笔记:用户/用户注册/身份验证

式中,dst代表目标图像,src代表原始图像。

3.2 函数语法

在OpenCV内使用函数cv2.Laplacian()实现Laplacian算子的计算,该函数的语法格式为:

dst=cv2.Laplacian(src,ddepth[,ksize[,scale[,delta[,borderType]]]])

式中:

● dst代表目标图像。

● src代表原始图像。

● ddepth代表目标图像的深度。

● ksize代表用于计算二阶导数的核尺寸大小。该值必须是正的奇数。当ksize的值为1时,Laplacian算子计算时采用的 3×3的核如上所示。

● scale代表计算Laplacian值的缩放比例因子,该参数是可选的。默认情况下,该值为 1,表示不进行缩放。

● delta代表加到目标图像上的可选值,默认为0。

● borderType代表边界样式。

通常情况下,在使用Laplacian算子时,对于参数ksize、scale、delta和borderType,直接采用其默认值即可。因此,函数cv2.boxFilter()的常用形式为:

dst=cv2.Laplacian(src,ddepth)

3.3 程序示例

import cv2  as cv

def cv_show(name, img):
    cv.imshow(name, img)
    cv.waitKey(0)
    cv.destroyAllWindows()

# laplacian算子可对灰度图像和彩色图像使用
img = cv.imread('D:\\qipan.jpg')
if img is None:
    print('Failed to read the image')

lap = cv.Laplacian(img, cv.CV_64F)
img1 = cv.convertScaleAbs(lap)
cv_show('lap', img1)

原图如下:

《Python编程:从入门到实践》第19章笔记:用户/用户注册/身份验证

Laplacian算子:

《Python编程:从入门到实践》第19章笔记:用户/用户注册/身份验证

由上图可知,Laplacian算子比Sobel算子、Scharr算子语法更为简单,不需要在x,y两个方向分别进行检测,检测效果与Sobel算子、Scharr算子相差不大。

Original: https://blog.csdn.net/qq_49478668/article/details/123808815
Author: Justth.
Title: Opencv之图像边缘检测:3.Laplacian算子(cv2.Laplacian)