• 【python3】第19章用户账户


    A、让用户能够输入数据

    一、用于添加主题的表单

    Django中创建表单最简单的方式是ModelForm。创建一个名为forms.py的文件,位置同models.py

    forms.py
    from django import forms
    from .models import Topic
     
     
    class TopicForm(forms.ModelForm):
        class Meta:
            model = Topic
            fields = ['text']
            labels = {'text': ''}  # 让Django不要为字段text生成标签

    最简单ModelForm版本只包含一个内嵌的Meta类,它告诉Django根据哪个模型创建表单,以及表单中包含哪些字段。

    二、URL模式new_topic

    将new_topic的url添加到learning_logs文件夹下的urls.py中

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

    三、视图函数new_topic()

    函数new_topic()需要处理俩种情形:刚进入new_top网页(应显示空表单);对提交的表单数据进行处理,并将用户重定向到网页topics。

    views.py
    from django.shortcuts import render
    from django.http import HttpResponseRedirect
    from django.urls import reverse
    from .models import Topic
    from .forms import TopicForm
     
     
    # Create your views here.
     
     
    def index(request):
        """学习笔记的主页"""
         
     
    def topics(request):
        """显示所有的主题"""
     
     
    def topic(request, topic_id):
        """显示单个主题及其所有的条目"""
     
     
    def new_topic(request):
        """添加新主题"""
        if request.method != 'POST':
            # 未提交数据:创建一个新表单
            form = TopicForm()
        else:
            # POST提交的数据,对数据进行处理
            form = TopicForm(request.POST)
            # 函数is_valid()核实用户填写了所有必不可少的字段,且输入的数据与要求的字段类型一致
            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。我们还导入了刚才创建的表单TopicForm。

    三、GET请求和POST请求

    对于只是从服务器读取数据的页面,使用GET请求;在用户需要通过表单提交信息时,通常使用POST请求。处理所有表单时,我们都将指定使用POST方法。

    四、模版new_topic

    new_topic.html
    {% 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>
        </form>
     
    {% endblock content %}

    Django使用模板标签{% csrf_token %}来防止攻击者利用表单来获取对服务器未经授权的访问(这种攻击被称为跨站请求伪装)。{{ form.as_p }}让Django自动创建显示表单所需的全部字段,修饰符as_p让Django以段落格式渲染所有表单元素

    五、链接到页面new_topic

    base.html
    {% 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 %}

    B、添加新条目

    六、用于添加新条目的表单

    forms.py
    from django import forms
    from .models import Topic, Entry
     
     
    class TopicForm(forms.ModelForm):
             
             
    class EntryForm(forms.ModelForm):
        class Meta:
            model = Entry
            fields = ['text']
            labels = {'text': ''}
            widgets = {'text': forms.Textarea(attrs={'cols'80})}

    widget是一个HTML表单元素,如单行文本框、多行文本区域或下拉列表

    七、URL模式new_entry

    将new_entry的url添加到learning_logs文件夹下的urls.py中

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

    八、视图函数new_entry()

    views.py
    from django.shortcuts import render
    from django.http import HttpResponseRedirect
    from django.urls import reverse
    from .models import Topic
    from .forms import TopicForm, EntryForm
     
     
    # Create your views here.
     
    ...
         
    def new_entry(request, topic_id):
        """在特定的主题中添加条目"""
        topic = Topic.objects.get(id=topic_id)
     
        if request.method != 'POST':
            # 未提交数据:创建一个新表单
            form = EntryForm()
        else:
            # POST提交的数据,对数据进行处理
            form = EntryForm(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)

    commit=False让Django创建一个新的条目对象,将其存储到new_entry中,但不保存到数据库。我们将new_entry的属性topic设置为在这个函数开头从数据库中获取的主题,然后调用save(),且不指定任何实参。这将把条目存储到数据库中,并将其与正确的主题相关联。列表args,其中包含要包含在URL中的所有实参

    九、模版new_entry

    new_entry.html
    {% extends "learning_logs/base.html" %}
     
    {% block content %}
        <p><a href="{% url "learning_logs:topic" topic.id %}">{{ topic }}</a></p>
     
        <p>Add 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 %}

    十、链接到页面new_entry

    base.html
    {% 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 %}

    C、编辑条目

    十、URL模式edit_entry

    将edit_entry的url添加到learning_logs文件夹下的urls.py中

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

    十一、视图函数edit_entry()

    views.py
    from django.shortcuts import render
    from django.http import HttpResponseRedirect
    from django.urls import reverse
    from .models import Topic, Entry
    from .forms import TopicForm, EntryForm
     
     
    # Create your views here.
     
    ...
         
    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)

    instance=entry创建EntryForm的实例,这个实参让Django创建一个表单,并使用既有条目对象中的信息填充它。处理器POST请求时,我们传递实参instance=entry, data=request.POST,让Django根据既有条目对象创建一个表单实例,并根据request.POST中的相关数据对其进行修改。

    十二、模版edit_entry

    edit_entry.html
    {% 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 %}

    十三、链接到页面edit_entry

    topic.html
    {% 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 %}

    D、创建应用程序users

    十四、创建名为users的应用程序

    python manage.py startapp users

    十五、将应用程序users添加到settings.py中

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

    十六、包含应用程序users的URL

    修改learning_log文件下的urls.py

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

    E、登陆页面

    十七、创建urls.py

    在users文件夹下创建urls.py文件

    urls.py
    """为应用程序users定义URL模式"""
    from django.conf.urls import url
    from django.contrib.auth.views import LoginView
    from import views
     
     
    urlpatterns = [
        # 登陆页面
        url(r'^login/$', LoginView.as_view(template_name='users/login.html'), name='login'),
    ]

    十八、模版login.html

    login.html
    {% extends "learning_logs/base.html" %}
     
    {% block content %}
     
        {% if form.errors %}
            <p>Your username and password didn't match.Please try again.</p>
        {% endif %}
     
        <form action="{% url "users:login" %}" method="post">
            {% csrf_token %}
            {{ form.as_p }}
     
            <button name="submit">log in</button>
            <input type="hidden" name="text" value="{% url "learning_logs:index" %}"/>
        </form>
    {% endblock content %}

    如果表单的errors属性被设置,我们就显示一条错误消息,指出输入的用户名-密码与数据库中存储的不一致。

    十九、连接到登陆页面

    base.html
    <p>
        <a href="{% url 'learning_logs:index' %}">Learning Log</a>
        <a href="{% url 'learning_logs:topics' %}">Topics</a>
        {% if user.is_authenticated %}
            Hello,{{ user.username }}.
        {% else %}
            <a href="{% url "users:login" %}">log in</a>
        {% endif %}
    </p>
     
    {% block content %}{% endblock content %}

    在Django身份验证系统中,每个模板都可使用变量user,这个变量有一个is_authenticated属性:如果用户已登陆,该属性将为true,否则为False

    二十、使用登陆页面

    F、注销

    二十一、注销URL

    修改users下的urls.py

    urls.py
    # 注销
    url(r'^logout/$', views.logout_view, name='logout'),

    二十二、视图函数logout_view()

    编辑users文件下views.py

    views.py
    from django.shortcuts import render
    from django.http import HttpResponseRedirect
    from django.urls import reverse
    from django.contrib.auth import logout
     
    # Create your views here.
     
     
    def logout_view(request):
        """注销用户"""
        logout(request)
        return HttpResponseRedirect(reverse('learning_logs:index'))

    二十三、链接到注销视图

    base.html
    <p>
        <a href="{% url 'learning_logs:index' %}">Learning Log</a>
        <a href="{% url 'learning_logs:topics' %}">Topics</a>
        {% if user.is_authenticated %}
            Hello,{{ user.username }}.
            <a href="{% url "users:logout" %}">log out</a>
        {% else %}
            <a href="{% url "users:login" %}">log in</a>
        {% endif %}
    </p>
     
    {% block content %}{% endblock content %}

    G、注册页面

    二十三、注册页面的URL模式

    修改users下的urls.py

    urls.py
    # 注册
    url(r'^register/$', views.register, name='register'),

    二十四、视图函数register()

    编辑users文件下views.py

    views.py
    from django.shortcuts import render
    from django.http import HttpResponseRedirect
    from django.urls import reverse
    from django.contrib.auth import logout, login, authenticate
    from django.contrib.auth.forms import UserCreationForm
     
    # Create your views here.
     
     
    def logout_view(request):
        """注销用户"""
     
    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)

    如果相应的是POST请求,我们就根据提交的数据创建一个UserCreationForm实例,并检查这些数据是否有效(用户名为包含非法字符、输入的俩个密码相同、用户没有试图做恶意的事情)。

    保存用户的信息后,我们让用户自动登陆:

    1、调用authenticate(),并将实参new_user.username和密码传递给它。用户注册时,被要求输入密码俩次;由于表单有效的,我们知道输入的这俩个密码是相同的,因此可以使用其中任何一个。这里,从表单POST数据中获取与键“password1”相关联的值。用户名和密码无误,方法authenticate()将返回一个通过了身份验证的用户对象,将其存储在authrnticated_user中。

    2、调用登陆login(),将对象request和suthenticated_user传递给它,这将为新用户创建有效的会话。最后,将用户重定向到主页。

    二十五、注册模版

    register.html
    {% extends "learning_logs/base.html" %}
     
    {% block content %}
        <form action="{% url "users:register" %}" method="post">
            {% csrf_token %}
            {{ form.as_p }}
            <button name="submit">register</button>
            <input type="hidden" name="next" value="{% url "learning_logs:index" %}"/>
        </form>
     
    {% endblock content %}

    二十六、链接到注册页面

    base.html
    <p>
        <a href="{% url 'learning_logs:index' %}">Learning Log</a>
        <a href="{% url 'learning_logs:topics' %}">Topics</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 %}

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

    二十七、使用@login_required限制访问

    修改learning_logs下view.py

    views.py
    from django.shortcuts import render
    from django.http import HttpResponseRedirect
    from django.urls import reverse
    from .models import Topic, Entry
    from .forms import TopicForm, EntryForm
    from django.contrib.auth.decorators import login_required
     
     
    # Create your views here.
     
     
    def index(request):
        """学习笔记的主页"""
        return render(request, 'learning_logs/index.html')
     
     
    @login_required()
    def topics(request):
        """显示所有的主题"""
       
     
    @login_required()
    def topic(request, topic_id):
        """显示单个主题及其所有的条目"""
     
     
    @login_required()
    def new_topic(request):
        """添加新主题"""
     
     
    @login_required()
    def new_entry(request, topic_id):
        """在特定的主题中添加条目"""
     
     
    @login_required()
    def edit_entry(request, entry_id):
        """编辑已有条目"""
    settings.py
    # 我的设置
    LOGIN_URL = '/users/login'

    Django提供了装饰器@login_required,检查用户是否已登陆。仅当用户已登陆时,Django才运行后续代码;如果用户未登陆,就重定向到登陆页面,即settings.py中的LOGIN_URL指定的URL。

    I、将数据关联到用户

    二十八、修改模型Topic

    修改learning_logs下的models.py

    models.py
    from django.db import models
    from django.contrib.auth.models import User
     
    # Create your models here.
     
     
    class Topic(models.Model):
        """用户学习的主题"""
        text = models.CharField(max_length=200)
        date_added = models.DateTimeField(auto_now_add=True)
        owner = models.ForeignKey(User, on_delete=models.CASCADE)
     
        def __str__(self):
            """返回模型的字符串表示"""
            return self.text
     
     
    class Entry(models.Model):
        """学到的有关某个主题的具体知识"""
        topic = models.ForeignKey(Topic, on_delete=models.CASCADE)
        text = models.TextField()
        date_added = models.DateTimeField(auto_now_add=True)
     
        class Meta:
            verbose_name_plural = 'entries'
     
        def __str__(self):
            """返回模型中的字符串表示"""
            return self.text[:50]+'...'

    二十九、确定当前有哪些用户

    二十九、迁移数据库

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

    修改learning_logs下view.py的topics

    views.py
    @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)

    三十一、保护用户的主题

    修改learning_logs下view.py的topic

    views.py
    from django.shortcuts import render
    from django.http import HttpResponseRedirect, Http404
    from django.urls import reverse
    from .models import Topic, Entry
    from .forms import TopicForm, EntryForm
    from django.contrib.auth.decorators import login_required
     
     
    # Create your views here.
     
     
    @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

    修改learning_logs下view.py的edit_entry

    views.py
    @login_required()
    def edit_entry(request, entry_id):
        """编辑已有条目"""
        entry = Entry.objects.get(id=entry_id)
        topic = entry.topic
         
        if topic.owner != request.user:
            raise Http404
     
        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)

    三十三、将新主题关联到当前用户

    修改learning_logs下view.py的new_topic

    views.py
    @login_required()
    def new_topic(request):
        """添加新主题"""
        if request.method != 'POST':
            # 未提交数据:创建一个新表单
            form = TopicForm()
        else:
            # POST提交的数据,对数据进行处理
            form = TopicForm(request.POST)
            if form.is_valid():
                new_topic = form.save(commit=False)
                new_topic.owner = request.user
                new_topic.save()
                return HttpResponseRedirect(reverse('learning_logs:topics'))
     
        context = {'form': form}
        return render(request, 'learning_logs/new_topic.html', context)
  • 相关阅读:
    前端学习笔记系列一:5 在项目中引入阿里图标icon
    前端学习笔记系列一:3 Vue中的nextTick
    前端学习笔记系列一:4 vue中@click.native
    学习习惯
    美团作价27亿美元正式收购摩拜
    北京 一卡通 退卡
    愚人自以慧,智者自以愚。
    袁隆平分享8字成功经验
    性能计数器 叹号
    升级 windows 2016
  • 原文地址:https://www.cnblogs.com/CSgarcia/p/13292483.html
Copyright © 2020-2023  润新知