django-allauth:使用者個人資料UserProfile擴充套件與編輯
文章轉載於: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>
如果使用者登入但郵箱未驗證就會看到下面效果。