文章转载于:https://mp.weixin.qq.com/s/ZUzI8gcZAqwbERuLdBQAwQ
第一步 创建应用及配置
由于django-allauth已经占用了account这个app名,所以我们需要先创建一个叫myaccount的app,并将其加入到settings.py配置文件INSTALLED_APP里去,同时把urls也加入到项目的urls里去
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myaccount', # 创建的app
'django.contrib.sites',
'allauth',
'allauth.account',
'allauth.socialaccount',
'allauth.socialaccount.providers.weibo',
]
根urls.py文件中,使用一样的accounts的路径,
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/', include('allauth.urls')),
path('accounts/', include('myaccount.urls')),
]
因为我们希望用户在登录或注册后自动跳转到/accounts/profile/, 我们可以在settings.py中加入以下代码。
LOGIN_REDIRECT_URL = '/accounts/profile/'
第二步 编写模型
由于Django自带的User模型字段邮箱,所以我们需要对其扩展,最便捷的方式就是创建UserProfile的模型,如下所示。我们添加了org和phone两个字段。
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
org = models.CharField(
'Organization', max_length=128, blank=True)
phone = models.CharField(
'phone', max_length=50, blank=True)
mod_date = models.DateTimeField('Last modified', auto_now=True)
class Meta:
verbose_name = 'User Profile'
def __str__(self):
return "{}'s profile".format(self.user.__str__())
第三步 编写URLs和视图
我们需要编写2个URLs和对应视图来实现我们的功能。
myaccount/urls.py
from django.urls import path
from . import views
app_name = "myaccount"
urlpatterns = [
path('profile/', views.profile, name='profile'),
path('profile/update/', views.profile_update, name='profile_update'),
]
2个对应视图处理方法如下所示 myaccount/views.py
from django.shortcuts import render, get_object_or_404
from .models import UserProfile
from .forms import ProfileForm
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.contrib.auth.decorators import login_required
@login_required
def profile(request):
user = request.user
return render(request, 'account/profile.html', {'user': user})
@login_required
def profile_update(request):
user = request.user
user_profile = get_object_or_404(UserProfile, user=user)
if request.method == "POST":
form = ProfileForm(request.POST)
# form表单验证提交数据的正确性
if form.is_valid():
# 获取筛选后的数据,参考django的form表单
user.first_name = form.cleaned_data['first_name'] user.last_name = form.cleaned_data['last_name']
user.save()
user_profile.org = form.cleaned_data['org']
user_profile.phone = form.cleaned_data['phone']
user_profile.save()
return HttpResponseRedirect(reverse('myaccount:profile'))
else:
default_data = {'first_name': user.first_name, 'last_name': user.last_name,
'org': user_profile.org, 'phone': user_profile.phone, }
form = ProfileForm(default_data)
return render(request, 'account/profile_update.html', {'form': form, 'user': user})
我们用户更新资料需要用到表单,所以我们把表单单独放在forms.py, 代码如下所示。我们创建了两个表单:一个是更新用户资料时使用,一个是重写用户登录表单。
myaccount/forms.py
from django import forms
from .models import UserProfile
class ProfileForm(forms.Form):
first_name = forms.CharField(label='First Name', max_length=50, required=False)
last_name = forms.CharField(label='Last Name', max_length=50, required=False)
org = forms.CharField(label='Organization', max_length=50, required=False)
phone = forms.CharField(label='phone', max_length=50, required=False)
class SignupForm(forms.Form):
def signup(self, request, user):
user_profile = UserProfile()
user_profile.user = user
user.save()
user_profile.save()
为什么我们需要重写用户登录表单?因为django-allauth在用户注册只会创建User对象,不会创建与之关联的UserProfile对象,我们希望用户在注册时两个对象一起被创建,并存储到数据库中。这点非常重要。通过重写表单,你还可以很容易添加其它字段。
要告诉django-allauth使用我们自定义的登录表单,我们只需要在settings.py里加入一行。(settings.py文件中)
ACCOUNT_SIGNUP_FORM_CLASS = 'myaccount.forms.SignupForm'
第四步 编写模板
因为django-allauth默认会在templates/account/文件夹下寻找模板文件,为方便后续集中美化模板,我们也把模板文件放在这个文件夹中。
myaccount/templates/account/profile.html
{% block content %}
{% if user.is_authenticated %}
<a href="{% url 'myaccount:profile_update' %}">Update Profile</a> | <a href="{% url 'account_email' %}">Manage Email</a> | <a href="{% url 'account_change_password' %}">Change Password</a> |
<a href="{% url 'account_logout' %}">Logout</a>
{% endif %}
<p>Welcome, {{ user.username }}.</p>
<h2>My Profile</h2>
<ul>
<li>First Name: {{ user.first_name }} </li>
<li>Last Name: {{ user.last_name }} </li>
<li>Organization: {{ user.profile.org }} </li>
<li>phone: {{ user.profile.phone }} </li>
</ul>
{% endblock %}
myaccount/templates/account/profile_update.html
{% block content %}
{% if user.is_authenticated %}
<a href="{% url 'myaccount:profile_update' %}">Update Profile</a> | <a href="{% url 'account_email' %}">Manage Email</a> | <a href="{% url 'account_change_password' %}">Change Password</a> |
<a href="{% url 'account_logout' %}">Logout</a>
{% endif %}
<h2>Update My Profile</h2>
<div class="form-wrapper">
<form method="post" action="" enctype="multipart/form-data">
{% csrf_token %}
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
<div class="button-wrapper submit">
<input type="submit" value="Update" />
</div>
</form>
</div>
{% endblock %}
最后进行数据迁移然后启动项目查看效果
在你完成注册或登录后你可以看到个人信息页了。(自动跳转到accounts/profile/下面)
点击Update Profile, 你就可以更新个人资料了,如下图所示。
第六步 思考与改进
我们如何显示用户的邮箱是否验证过,并提醒他们去验证邮箱?Django实现这个也非常容易。我们只需要在模型models.py中新定义一个account_verified方法。
from django.db import models
from django.contrib.auth.models import User
from allauth.account.models import EmailAddress
# Create your models here.
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
org = models.CharField(
'Organization', max_length=128, blank=True)
phone = models.CharField(
'phone', max_length=50, blank=True)
mod_date = models.DateTimeField('Last modified', auto_now=True)
class Meta:
verbose_name = 'User Profile'
def __str__(self):
return "{}'s profile".format(self.user.username)
def account_verified(self):
if self.user.is_authenticated:
result = EmailAddress.objects.filter(email=self.user.email)
if len(result):
return result[0].verified
return False
模板修改
<p>Welcome, {{ user.username }}.
{% if not user.profile.account_verified %}
(Unverified email.)
{% endif %}
</p>
如果用户登录但邮箱未验证就会看到下面效果。