1. 程式人生 > >django-allauth:使用者個人資料UserProfile擴充套件與編輯

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>

如果使用者登入但郵箱未驗證就會看到下面效果。