Python编程--Django入门:用户账户(一)

简介: Python编程--Django入门:用户账户(一)

Python编程:用户账户
Web应用程序的核心是让任何用户都能够注册账户并能够使用它,不管用户身处何方。让用户能够添加主题和条目,以及编辑既有的条目。目标—实现一个用户身份验证系统。

1. 让用户能够输入数据
建立用于创建用户账户的身份验证系统之前,先来添加一个页面,让用户能够输入数据。让用户能够添加新主题、添加新条目以及编辑既有条目。使用Django的表单工具来创建让用户能够输入数据的页面。

1.1 添加新主题
工作流程是:定义一个URL------编写一个视图函数------编写一个模板。

1. 用于添加新主题的表单
在Django中,创建表单的最简单方式是使用ModelForm,创建一个名为forms.py的文件,将其存储到models.py所在的目录中,并在其中编写第一个表单:

forms.py

from django import forms

from .models import Topic


class TopicForm(forms.ModelForm):
    class Meta:
        model = Topic        # 根据模型Topic创建一个表单
        fields = ['text']
        labels = {
   'text': ''}

2. URL模式new_topic
这个新网页的URL应简短而具有描述性,因此当用户要添加新主题时,切换到http://localhost:8000/new_topic/。将其添加到learning_logs/urls.py中。

urls.py

"""定义learning_logs的URL模式"""

from django.conf.urls import url

from . import views


urlpatterns = [
    # 主页
    url(r'^$', views.index, name='index'),

    # 显示所有的主题
    url(r'^topics/$', views.topics, name='topics'),

    # 显示特定主题
    url(r'^topics/(?P<topic_id>\d+)/$', views.topic, name='topic'),

    # 用户添加新主题的网页
    url(r'^new_topic/$', views.new_topic, name='new_topic'),
]

这个URL模式将请求交给视图函数new_topic()。

3. 视图函数new_topic()
函数new_topic()需要处理两种情形:刚进入new_topic网页(在这种情况下, 它应显示一个空表单);对提交的表单数据进行处理,并将用户重定向到网页topics:

views.py

from django.shortcuts import render

from .models import Topic

from django.http import HttpResponseRedirect

from django.core.urlresolvers import reverse

from  . forms import TopicForm


# Create your views here.
def index(request):
    """学习笔记的主页"""
    return render(request, 'learning_logs/index.html')

def topics(request):
    """显示所有的主题"""
    topics = Topic.objects.order_by('date_added')
    context = {
   'topics':topics}
    return render(request, 'learning_logs/topics.html', context)


def topic(request, topic_id):
    """显示单个主题机器所有的条目"""
    topic = Topic.objects.get(id=topic_id)
    entries = topic.entry_set.order_by('-date_added')
    context = {
   'topic': topic, 'entries': entries}
    return render(request, 'learning_logs/topic.html', context)

def new_topic(request):
    """添加新主题"""
    if request.method != 'POST':
        # 未提交数据:创建一个新表单
        form = TopicForm()
    else:
        # POST提交的数据,对数据进行处理
        form = TopicForm(request.POST)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('learning_logs:topics'))
    context = {
   'form':form}
    return render(request, 'learning_logs/new_topic.html', context)

导入HttpResponseRedirect类,用户提交主题后,将使用这个类将用户重定向到网页topics。函数reverse()根据指定的URL模型确定URL,这意味着Django将在页面被请求时生成URL。

4. GET请求和POST请求
创建Web应用程序时,将用到两种主要请求类型是GET请求和POST请求。对于只是从服务器读取数据的页面,使用GET请求;在用户需要通过表单提交信息时,通常使用POST请求。处理所有表单时,将指定使用POST方法。

5. 模板new_topic
创建新模板new_topic.html, 用于显示刚刚创建的表单:

new_topic.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>new_topic</title>
</head>
<body>
{
   % extends "learning_logs/base.html" %}

{
   % block content %}

<p>Add a new topic:</p>

<form action="{% url 'learning_logs:new_topic' %}" method='post'>
    {
   % csrf_token %}
    {
   {
    form.as_p }}
    <button name="submit">add topic</button> #Django不会为表单创建提交按钮,因此我们定义了一个这样的按                                                                                                                                                                                        钮。
</form>

{
   % endblock content %}}
</body>
</html>

这个模板继承了base.html,因此其基本结构与项目“学习笔记”的其他页面相同。Django使用模板标签{% csrf_token %}来防止攻击者利用表单来获对服务器未经授权的访问(这种攻击称为跨站请求伪造)。

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

topics.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Topics</title>
</head>
<body>
{
   % extends "learning_logs/base.html" %}

{
   % block content %}

<p>Topics</p>

<ul>
    {
   % for topic in topics %}
    <li><a href="{% url 'learning_logs:topic' topic.id %}">{
   {
    topic }}</a></li>
    {
   % empty %}
    <li>No topics have been added yet.</li>
    {
   % endfor %}
</ul>
<a href="{% url 'learning_logs:new_topic' %}">Add a new topic:</a>
{
   % endblock content %}
</body>
</html>

这个链接放在了既有主题列表的后面,如下图所示:

1.2 添加新条目
现在可以添加新主题了,还需要添加新条目。再次定义URL,编写视图函数和模板,并链接到添加新条目的网页。

1. 用于添加新条目的表单
创建一个与模型Entry相关联的表单,但这个表单的定制程度比TopicForm要高些:

forms.py

from django import forms

from .models import Topic, Entry 

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


class EntryForm(forms.ModelForm):
    class Meta:
        model = Entry
        fields = ['text']
        labels = {
   'text':''} # 给字段'text'指定了空标签
        widgets = {
   'text': forms.Textarea(attrs={
   'cols': 80})} # widget(小部件)是一个HTML表单元                                                                                                                                素,如单行文本框、多行文本区域或下拉                                                                                                                                                                                    列表。

对照之前forms.py中的import语句,除导入Topic外,还导入了Entry。新类EntryForm继承了forms.ModelForm。

2. URL模式new_entry

urls.py

"""定义learning_logs的URL模式"""

from django.conf.urls import url

from . import views


urlpatterns = [
    # 主页
    url(r'^$', views.index, name='index'),

    # 显示所有的主题
    url(r'^topics/$', views.topics, name='topics'),

    # 显示特定主题
    url(r'^topics/(?P<topic_id>\d+)/$', views.topic, name='topic'),

    # 用户添加新主题的网页
    url(r'^new_topic/$', views.new_topic, name='new_topic'),

    # 用于添加新条目的页面
    url(r'^new_entry/(?P<topic_id>\d+)/$', views.new_entry, name='new_entry'),
]

这个URL模式与形式为http://localhost:8000/new_entry/id/的URL匹配,其中id是一个与主题ID匹配的数字。

3. 视图函数new_entry()
视图函数new_entry()与函数new_topic()很像:

导入EntryForm,new_entry()的定义包含形参topic_id,用于存储从URL中获得得值。

views.py

from __future__ import unicode_literals

from django.shortcuts import render

from .models import Topic, Entry

from django.http import HttpResponseRedirect

from django.core.urlresolvers import reverse

from  . forms import TopicForm, EntryForm


# Create your views here.
def index(request):
    """学习笔记的主页"""
    return render(request, 'learning_logs/index.html')

def topics(request):
    """显示所有的主题"""
    topics = Topic.objects.order_by('date_added')
    context = {
   'topics':topics}
    return render(request, 'learning_logs/topics.html', context)


def topic(request, topic_id):
    """显示单个主题机器所有的条目"""
    topic = Topic.objects.get(id=topic_id)
    entries = topic.entry_set.order_by('-date_added')
    context = {
   'topic': topic, 'entries': entries}
    return render(request, 'learning_logs/topic.html', context)

def new_topic(request):
    """添加新主题"""
    if request.method != 'POST':
        # 未提交数据:创建一个新表单
        form = TopicForm()
    else:
        # POST提交的数据,对数据进行处理
        form = TopicForm(request.POST)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('learning_logs:topics'))
    context = {
   'form':form}
    return render(request, 'learning_logs/new_topic.html', context)


def new_entry(request, topic_id):
    """在特定的主题中添加新条目"""
    topic = Topic.objects.get(id=topic_id)

    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)

4. 模板new_entry
模板new_entry类似于模板new_topic:

new_entry.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>new-entry</title>
</head>
<body>
{
   % extends "learning_logs/base.html" %}

{
   % block content %}

<p><a href="{% url 'learning_logs:topic' topic.id %}">{
   {
    topic }}</a></p>

<p>Add a new entry:</p>
<form action="{%url 'learning_logs:new_entry' topic.id %}" method='post'>
    {
   % csrf_token %}
    {
   {
    form.as_p }}
    <button name='submit'> add entry</button>
</form>

{
   % endblock content %}}
</body>
</html>

5.链接到页面new_entry
在显示特定主题的页面中添加到页面new_entry的链接:

topic.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>topic</title>
</head>
<body>
{
   % extends 'learning_logs/base.html' %}

{
   % block content %}

<p>Topic: {
   {
    topic }}</p>

<p>Entries:</p>
<p>
    <a href="{% url 'learning_logs:new_entry' topic.id %}">add new entry</a>
</p>
<ul>
    {
   % for entry in entries %}
    <li>
        <p>{
   {
    entry.date_added|date:'M d, Y H:i' }}</p>
        <p>{
   {
    entry.text|linebreaks }}</p>       
    </li>
    {
   % empty %}
    <li>There are no entries for this topic yet.</li>
    {
   % endfor %}
</ul>

{
   % endblock content %}

</body>
</html>

在显示条目前添加链接,因为在这种页面中,执行最常见的操作是添加新条目。下图显示了页面new_entry。现在用户可以添加新主题,还可以在每个主题中添加任意数量的条目。尝试使用一下页面new_entry。

1.3 编辑条目
下面创建一个页面,让用户能够编辑既有的条目。

1. URL模式edit_entry
这个页面的URL需要传递要编辑的条目ID。修改后的learning_logs/urls.py如下:

urls.py

"""定义learning_logs的URL模式"""

from django.conf.urls import url

from . import views


urlpatterns = [
    # 主页
    url(r'^$', views.index, name='index'),

    # 显示所有的主题
    url(r'^topics/$', views.topics, name='topics'),

    # 显示特定主题
    url(r'^topics/(?P<topic_id>\d+)/$', views.topic, name='topic'),

    # 用户添加新主题的网页
    url(r'^new_topic/$', views.new_topic, name='new_topic'),

    # 用于添加新条目的页面
    url(r'^new_entry/(?P<topic_id>\d+)/$', views.new_entry, name='new_entry'),

    # 用于编辑条目的页面
    url(r'^edit_entry/(?P<topic_id>\d+)/$', views.edit_entry, name='edit_entry'),

]

2. 视图函数edit_entry()
页面edit_entry收到GET请求时,edit_entry()将返回一个表单,让用户能够对条目进行编辑。该页面收到POST请求(条目文本经过修订)时,它将修改后的文本保存到数据库中:

views.py

from django.shortcuts import render

from .models import Topic, Entry

from django.http import HttpResponseRedirect

from django.core.urlresolvers import reverse

from  . forms import TopicForm, EntryForm


# Create your views here.
def index(request):
    """学习笔记的主页"""
    return render(request, 'learning_logs/index.html')

def topics(request):
    """显示所有的主题"""
    topics = Topic.objects.order_by('date_added')
    context = {
   'topics':topics}
    return render(request, 'learning_logs/topics.html', context)


def topic(request, topic_id):
    """显示单个主题机器所有的条目"""
    topic = Topic.objects.get(id=topic_id)
    entries = topic.entry_set.order_by('-date_added')
    context = {
   'topic': topic, 'entries': entries}
    return render(request, 'learning_logs/topic.html', context)

def new_topic(request):
    """添加新主题"""
    if request.method != 'POST':
        # 未提交数据:创建一个新表单
        form = TopicForm()
    else:
        # POST提交的数据,对数据进行处理
        form = TopicForm(request.POST)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('learning_logs:topics'))
    context = {
   'form':form}
    return render(request, 'learning_logs/new_topic.html', context)


def new_entry(request, topic_id):
    """在特定的主题中添加新条目"""
    topic = Topic.objects.get(id=topic_id)

    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)


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

3. 模板edit_entry
下面是模板edit_entry.html,它与模板new_entry.html类似:

edit_entry.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>edit-entry</title>
</head>
<body>
{
   % extends "learning_logs/base.html" %}

{
   % block content %}
<p><a href="{% url 'learning_logs:topic' topic.id %}">{
   {
    topic }}</a></p>

<p>Edit entry:</p>


<form action="{% url 'learning_logs:edit_entry' entry.id %}" method='post'>
    {
   % csrf_token %}
    {
   {
    form.as_p }}
    <button name='submit'>save changes</button>
</form>

{
   % endblock content %}
</body>
</html>

4. 链接到页面edit_entry
在显示特定主题的页面中,需要给每个条目添加到页面edit_entry的链接:

topic.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>topic</title>
</head>
<body>
{
   % extends 'learning_logs/base.html' %}

{
   % block content %}

<p>Topic: {
   {
    topic }}</p>

<p>Entries:</p>
<p>
    <a href="{% url 'learning_logs:new_entry' topic.id %}">add new entry</a>
</p>
<ul>
    {
   % for entry in entries %}
    <li>
        <p>{
   {
    entry.date_added|date:'M d, Y H:i' }}</p>
        <p>{
   {
    entry.text|linebreaks }}</p>
        <p>
            <a href="{% url 'learning_logs:edit_entry' entry.id %}">edit entry</a>
        </p>
    </li>
    {
   % empty %}
    <li>There are no entries for this topic yet.</li>
    {
   % endfor %}
</ul>

{
   % endblock content %}

</body>
</html>

编辑链接放在每个条目的日期和文本后面。如下图所示:

  1. 创建用户账户
    建立一个用户注册和身份验证系统,让用户能够注册账户,进而登录和注销。创建一个新的应用程序,其中包含与处理用户账户相关的所有功能。

2.1 应用程序users
使用命令startapp来创建一个名为users的应用程序:

(11_env) (base) liuxiaowei@MacBook-Air learning_log % python manage.py startapp users
(11_env) (base) liuxiaowei@MacBook-Air learning_log % ls
11_env init.py db.sqlite3 learning_log learning_logs manage.py users
(11_env) (base) liuxiaowei@MacBook-Air learning_log % ls users
init.py admin.py apps.py migrations models.py tests.py views.py

这个命令新建一个名为users的目录,结构与应用程序learning_logs相同。

1. 将应用程序users添加到settings.py中
在settings.py中,将这个新的应用程序添加到INSTALLED_APPS中, 如下所示:

settings.py

"""
Django settings for learning_log project.

Generated by 'django-admin startproject' using Django 1.11.

For more information on this file, see
https://docs.djangoproject.com/en/1.11/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.11/ref/settings/
"""

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = ')-lv47!$0c!j5-7th)l_-osv&ugkws7!6pv&+oe_0=p_xo(g@_'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # My app
    'learning_logs',
    'users',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'learning_log.urls'

TEMPLATES = [
    {
   
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
   
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'learning_log.wsgi.application'


# Database
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases

DATABASES = {
   
    'default': {
   
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}


# Password validation
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
   
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
   
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
   
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
   
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/

STATIC_URL = '/static/'

2. 包含应用程序users的URL
需要修改项目根目录中的urls.py,使其包含我们将为应用程序users定义的URL:

urls.py


from django.conf.urls import url, include
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    url(r'^users/', include('users.urls', namespace='users')),
    url(r'', include('learning_logs.urls', namespace='learning_logs')),
]

接下文。Python编程--Django入门:用户账户(二)https://developer.aliyun.com/article/1618615

相关文章
|
1天前
|
存储 Shell 数据库
Python编程--Django入门:用户账户(二)
Python编程--Django入门:用户账户(二)
|
5月前
|
前端开发 数据库 Python
Python Web 开发: 解释 Django 框架的 MVC 架构是什么?
Python Web 开发: 解释 Django 框架的 MVC 架构是什么?
107 0
|
5月前
|
存储 关系型数据库 MySQL
Python Django框架下将MySQL数据库的内容在网页上动态展示(修订版-2021-05-17)
Python Django框架下将MySQL数据库的内容在网页上动态展示(修订版-2021-05-17)
30693 0
|
2月前
|
机器学习/深度学习 数据采集 数据可视化
基于爬虫和机器学习的招聘数据分析与可视化系统,python django框架,前端bootstrap,机器学习有八种带有可视化大屏和后台
本文介绍了一个基于Python Django框架和Bootstrap前端技术,集成了机器学习算法和数据可视化的招聘数据分析与可视化系统,该系统通过爬虫技术获取职位信息,并使用多种机器学习模型进行薪资预测、职位匹配和趋势分析,提供了一个直观的可视化大屏和后台管理系统,以优化招聘策略并提升决策质量。
117 4
|
2月前
|
搜索推荐 前端开发 数据可视化
【优秀python web毕设案例】基于协同过滤算法的酒店推荐系统,django框架+bootstrap前端+echarts可视化,有后台有爬虫
本文介绍了一个基于Django框架、协同过滤算法、ECharts数据可视化以及Bootstrap前端技术的酒店推荐系统,该系统通过用户行为分析和推荐算法优化,提供个性化的酒店推荐和直观的数据展示,以提升用户体验。
106 1
|
2月前
|
搜索推荐 前端开发 数据可视化
基于Python协同过滤的旅游景点推荐系统,采用Django框架,MySQL数据存储,Bootstrap前端,echarts可视化实现
本文介绍了一个基于Python协同过滤算法的旅游景点推荐系统,该系统采用Django框架、MySQL数据库、Bootstrap前端和echarts数据可视化技术,旨在为用户提供个性化的旅游推荐服务,提升用户体验和旅游市场增长。
159 9
基于Python协同过滤的旅游景点推荐系统,采用Django框架,MySQL数据存储,Bootstrap前端,echarts可视化实现
|
2月前
|
前端开发 关系型数据库 MySQL
Python基于Django框架图书管理系统,Bootstrap框架UI,后台EasyUI框架UI,有登录,实现增删改查的富文本效果
本文介绍了一个使用Python Django框架开发的图书管理系统,该系统采用Bootstrap框架进行前端UI设计,EasyUI框架用于后台UI界面,集成了富文本编辑器,并实现了登录及增删改查功能。
|
2月前
|
设计模式 API Python
Python Web:Django、Flask和FastAPI框架对比
Python Web:Django、Flask和FastAPI框架对比
57 0
|
3月前
|
存储 关系型数据库 数据库
我将提供一个简化的Python代码示例和详解,以展示如何使用Python和Django框架来构建智能化小区综合物业管理系统的一部分功能。
我将提供一个简化的Python代码示例和详解,以展示如何使用Python和Django框架来构建智能化小区综合物业管理系统的一部分功能。
|
5月前
|
存储 设计模式 前端开发
Python Django框架总介绍
Python Django框架总介绍
39 0