第四章下半部分 Django by example

用户注册和用户profiles

现有的用户已经可以登录,登出,修改他们的密码,以及当他们忘记密码的时候重置他们的密码。现在,我们需要构建一个视图(view)允许访问者创建他们的账号。

用户注册

先创建一个表单,供填写用户名、密码等

from django.contrib.auth.models import User
class UserRegistrationForm(forms.ModelForm):
    password = forms.CharField(widget=forms.PasswordInput, label='Password')  # 新增加的表单字段
    password2 = forms.CharField(label='Repeat password', widget=forms.PasswordInput)  # 新增加的表单字段

    class Meta:
        model = User  # 模型表单使用User模型
        fields = ('username', 'first_name', 'last_name',)  # 表单内容使用元组内的字段
    def clean_password2(self):# 自定义的表单验证,函数命名规则clean_,当通过调用is_valid()方法验证这个表单(form)时这个检查会被执行。
        cd = self.cleaned_data
        if cd['password'] != cd['password2']:
            raise forms.ValidationError('两次密码不同')
        return cd['password2']
# 表单(forms)还包含了一个clean()方法用来验证表单(form)的所有内容,这对验证需要依赖其他字段的字段是非常有用的。

# Django还提供一个UserCreationForm表单(form)给你使用,它位于django.contrib.auth.forms非常类似与我们刚才创建的表单(form)

#表单(forms)还包含了一个clean()方法用来验证表单(form)的所有内容,这对验证需要依赖其他字段的字段是非常有用的。
Django还提供一个UserCreationForm表单(form)给你使用,它位于django.contrib.auth.forms非常类似与我们刚才创建的表单(form)

写registration注册视图

...import省略
def register(request):
    if request.method == 'POST':
        user_form = UserRegistrationForm(request.POST)
        if user_form.is_valid():
            cd = user_form.cleaned_data#获得字典
            password = cd['password']#获取password field
            new_user = user_form.save(commit=False)# 获取User实例new_user,不提交
            new_user.set_password(password)#nwe_user对象设置密码
            new_user.save()#提交
            return render(request,'account/register_done.html',{'new_user': new_user})#渲染到register_done
    else:
        user_form = UserRegistrationForm()
    return render(request, 'account/register.html',{'user_form': user_form})#空表单渲染到注册页

在urls中配置

url(r'^register/$', views.register, name='register'),

html文件

//register.html
{% extends "base.html" %}
{% block title %}Create an account{% endblock %}
{% block content %}
  

Create an account

Please, sign up using the following form:

{{ user_form.as_p }} {% csrf_token %}

{% endblock %}
//register_done.html
{% extends "base.html" %}
{% block title %}Welcome{% endblock %}
{% block content %}
  

Welcome {{ new_user.first_name }}!

Your account has been successfully created. Now you can log in.

{% endblock %}

可以在login.html中添加注册超链接


扩展User的方法

有两种方式来扩展user模型,一种是继承AbstractUser,重写User类,还有一种方式,与django自带的User模型进行OneToOne关联(一对一关联)

为了保持你的代码通用化,当需要定义模型(model)和用户模型的关系时,使用get_user_model()方法来取回用户模型(model)并使用AUTH_USER_MODEL设置来引用这个用户模型,替代直接引用auth的User模型(model)。

from django.db import models
from django.conf import settings


class Profile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL)#如果你没有指定OneToOneField 的related_name 参数,Django 将使用当前模型的小写的名称作为默认值。比如要反向查询User对象的Profile ,使用单个user.profile,如果有related_name,使用user..
    date_of_birth = models.DateField(blank=True, null=True)
    photo = models.ImageField(upload_to='users/%Y/%m/%d', blank=True)#上传图片
    
    def __str__(self):
        return 'Profile for user {}'.format(self.user.username)

user一对一字段允许我们关联用户和profiles。photo字段是一个ImageField字段。你需要安装一个Python包来管理图片,使用PIL(Python Imaging Library)或者Pillow(PIL的分叉),pip安装Pillow包。

为了Django能在开发服务中管理用户上传的多媒体文件,在项目setting.py文件中添加如下设置:
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')

MEDIA_URL 是管理用户上传的多媒体文件的主URL,MEDIA_ROOT是这些文件在本地保存的路径。我们动态的构建这些路径相对我们的项目路径来确保我们的代码更通用化。

现在,编辑bookmarks项目中的主urls.py文件,修改代码如下所示:

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


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

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL,
                        document_root=settings.MEDIA_ROOT)

在这种方法中,Django开发服务器将会在开发时改变对多媒体文件的服务。
static()帮助函数最适合在开发环境中使用而不是在生产环境使用。绝对不要在生产环境中使用Django来服务你的静态文件。
之后,在admin中注册以及数据库迁移
创建表单给用户可编辑

forms文件
from .models import Profile

class UserEditForm(forms.ModelForm):
    class Meta:
        model = User
        fields = ('first_name', 'last_name', 'email')
        
class ProfileEditForm(forms.ModelForm):
    class Meta:
        model = Profile
        fields = ('date_of_birth', 'photo')

这两个表单(forms)的功能:

  • UserEditForm:允许用户编辑它们的first name,last name, e-mail 这些储存在User模型(model)中的内置字段。
  • ProfileEditForm:允许用户编辑我们存储在定制的Profile模型(model)中的额外数据。用户可以编辑他们的生日数据以及为他们的profile上传一张照片。
    创建views文件
视图文件
from .forms import LoginForm, UserRegistrationForm, \
UserEditForm, ProfileEditForm
@login_required
def edit(request):
    if request.method == 'POST':
        user_form = UserEditForm(instance=request.user,
                                data=request.POST)
        profile_form = ProfileEditForm(instance=request.user.profile,
                                        data=request.POST,
                                        files=request.FILES)
        if user_form.is_valid() and profile_form.is_valid():
            user_form.save()
            profile_form.save()
            return redirect('dashboard')
        #redirect使用文档https://docs.djangoproject.com/en/dev/topics/http/shortcuts/
    else:
        user_form = UserEditForm(instance=request.user)
        profile_form = ProfileEditForm(instance=request.user.profile)
    return render(request,
                 'account/edit.html',
                 {'user_form': user_form,
                 'profile_form': profile_form})

创建url规则

url(r'^edit/$', views.edit, name='edit'),

最后,在templates/account/中创建一个新的模板(template)命名为edit.html,为它添加如下内容:

{% extends "base.html" %}
{% block title %}Edit your account{% endblock %}
{% block content %}
    

Edit your account

You can edit your account using the following form:

{{ user_form.as_p }} {{ profile_form.as_p }} {% csrf_token %}

{% endblock %}

我们在表单(form)中包含enctype="multipart/form-data"用来支持文件上传。我们使用一个HTML表单来提交两个表单(forms): user_form和profile_form。

使用一个定制User模型(model)

Django还提供一个方法可以使用你自己定制的模型(model)来替代整个User模型(model)。你自己的用户类需要继承Django的AbstractUser类,这个类提供了一个抽象的模型(model)用来完整执行默认用户。你可访问 https://docs.djangoproject.com/en/1.8/topics/auth/customizing/#substituting-a-custom-user-model来获得这个方法的更多信息。
使用一个定制的用户模型(model)将会带给你很多的灵活性,但是它也可能给一些需要与User模型(model)交互的即插即用的应用集成带来一定的困难。

使用messages框架

一次性展示信息的框架
from django.contrib import messages
常用方法:

  • success():当操作成功后显示成功的messages
  • info():展示messages
  • warning():某些还没有达到失败的程度但已经包含有失败的风险,警报用
  • error():操作没有成功或者某些事情失败
  • debug():在生产环境中这种messages会移除或者忽略
    html文件添加
{% if messages %}
 
    {% for message in messages %}
  • {{ message|safe }}
  • {% endfor %}
{% endif %}

views中添加

from django.contrib import messages
@login_required
def edit(request):
    if request.method == 'POST':
    # ...
        if user_form.is_valid() and profile_form.is_valid():
            user_form.save()
            profile_form.save()
            messages.success(request, 'Profile updated '\
                                     'successfully')
        else:
            messages.error(request, 'Error updating your profile')
    else:
        user_form = UserEditForm(instance=request.user)
        # ...

创建一个定制的认证(authentication)后台

Django允许你通过不同的来源进行认证(authentication)。AUTHENTICATION_BACKENDS(默认设置,并不在settings文件中显示的显示出来)设置包含了所有的给你的项目的认证(authentication)后台。默认的,这个设置如下所示:

('django.contrib.auth.backends.ModelBackend',)

https://docs.djangoproject.com/en/1.8/topics/auth/customizing/#other-authentication-sources
当你使用django.contrib.auth的authenticate()函数,Django会通过每一个定义在AUTHENTICATION_BACKENDS中的后台一个接一个地尝试认证(authentication)用户,直到其中有一个后台成功的认证该用户才会停止进行认证。只有所有的后台都无法进行用户认证(authentication),他或她才不会在你的站点中通过认证(authentication)。
Django提供了一个简单的方法来定义你自己的认证(authentication)后台。一个认证(authentication)后台就是提供了如下两种方法的一个类:

  • authenticate():将用户信息当成参数,如果用户成功的认证(authentication)就需要返回True,反之,需要返回False。
  • get_user():将用户的ID当成参数然后需要返回一个用户对象。

创建一个定制认证(authentication)后台非常容易,就是编写一个Python类实现上面两个方法。我们要创建一个认证(authentication)后台让用户在我们的站点中使用他们e-mail替代他们的用户名来进行认证(authentication)

在应用路径下创建authentication文件

from django.contrib.auth.models import User


class EmailAuthBackend(object):
    def authenticate(self,username=None, password=None):
        try:
            user = User.objects.get(email=username)
            if user.check_password(password):
                return user
            return None
        except User.DoesNotExist:
            return None

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

在settings中添加认证后台


AUTHENTICATION_BACKENDS = (
   'django.contrib.auth.backends.ModelBackend',
   'account.authentication.EmailAuthBackend',
)

这样,就可以在登陆中,使用邮箱来登录了。


为你的站点添加社交认证(authentication)

1.需要安装python-social-auth模块
2.在settings中添加应用

INSTALLED_APPS = (
    #...
    'social.apps.django_app.default',
)

3.数据迁移
4.在主urls中设置

url('social-auth/',
    include('social.apps.django_app.urls', namespace='social')),

5.为了确保社交认证(authentication)可以工作,你还需要配置一个hostname,因为有些服务不允许重定向到127.0.0.1或localhost。为了解决这个问题,在Linux或者Mac OSX下,编辑你的/etc/hosts文件添加如下内容:

127.0.0.1 mysite.com

这是用来告诉你的计算机指定mysite.com hostname指向你的本地机器。如果你使用Windows,你的hosts文件在 C:\Winwows\ System32\Drivers\etc\hosts。

为了验证你的host重定向是否可用,在浏览器中打开 http://mysite.com:8000/account/login/ 。如果你看到你的应用的登录页面,host重定向已经可用。


你可能感兴趣的:(第四章下半部分 Django by example)