ホーム >  Python > Django >  Userモデルをカスタマイズしてプロフィール情報を追加する(Django)


Posted:2017/09/19 9:00:06 AM|Category : Django

Userモデルをカスタマイズしてプロフィール情報を追加する(Django)

Vagrantで作ったCentOS7のAnaconda・Django環境に、ユーザ登録ページを作成しました。今回は、Userモデルをカスタマイズして、ユーザ情報を拡張します。

Userモデルをカスタマイズ

前回、自作のユーザ登録、ユーザ情報変更、パスワード変更を作りました。今回は、以下のようなユーザ情報を拡張してUserモデルに無い情報を追加します。

DjangoのUserモデルには、住所や電話番号などの属性はありません。シンプルにUserモデルと紐づくProfileモデルを作成し、Userモデルにない情報を紐づけます

前回から引き継ぐページ

トップページ
(/index)
ドメイン直下のページです。ログイン前はページタイトルのみですが、ログインすると、ヘッダーナビゲーションにようこそ○○さんと表示します。
プロフィール
(/profile)
ログインているユーザ(自分自身)の情報を表示します。ログイン前の状態の場合、ログインページへ遷移します。
ログイン
(/login)
ユーザ名とパスワードを入力してログインします。ログインが完了すると、ログイン状態になってトップページへ遷移します。
ログアウト
(/logout)
ログアウト状態にしてトップページへ遷移します。
ユーザ登録ページ
(/new)
ユーザ登録をします。登録が完了すると、ログイン状態にしてトップページへ遷移します。
ユーザ情報変更ページ
(/change_data)
ユーザ情報を変更します。このページではパスワードを変更できません。ログイン前の状態の場合、ログインページへ遷移します。
パスワード変更ページ
(/change_password)
パスワード変更ページを変更します。ログイン前の状態の場合、ログインページへ遷移します。

今回作る(変更する)ページ

ユーザ登録ページ(/new) ユーザ登録をします。登録が完了すると、ログイン状態にしてトップページへ遷移します。
プロフィール
(/profile)
ログインているユーザ(自分自身)の情報を表示します。ログイン前の状態の場合、ログインページへ遷移します。このページに性別と電話番号を追加します。

仕様

前回から引き継ぐページ

トップページです。「ドメイン/」にアクセスします。

ログインページです。「ドメイン/login」にアクセスします。

ログインページからログインした場合は「ドメイン/」(トップページ)へ遷移します。

プロフィールページです。「ドメイン/profile」にアクセスします。ログイン中のユーザの情報を表示します。

ログアウトを押すと、ログアウト処理後トップページへリダイレクトします。

ユーザ情報変更ページです。変更後、トップページへリダイレクトします。

パスワード変更ページです。変更後、トップページへリダイレクトします。

今回作る(変更する)ページ

ユーザ登録ページです。性別と電話番号フォームを追加しました。

プロフィールページです。性別と電話番号フォームを追加しました。

準備

Vagrantでゲスト環境(仮想環境)を作ります。

①Virtualboxをインストールします。Virtualboxのインストールまでで結構です。

VirtualBoxをインストールする for Ubuntu

②Vagrantをインストールします。centos7環境を作りますので、Vagrantのインストールのみ済ませてください。

Vagrantをインストールしてテスト環境を作る for Ubuntu

Vagrantのcentos7環境の詳細を調べる場合は以下のように確認します。

VagrantのCentOS7の環境を確認(lsb_releaseコマンドなど)

③バージョン管理ツールのpyenvインストールします。Anacondaインストールに使います。

VagrantのCentOS7にバージョン管理ツールをインストール(pyenv)

④Anaconda・Djangoインストールします。

Vgrant(CentOS7)にAnaconda+Django+Apache環境を作る(Anaconda・Djangoインストール)

⑤mariadb、mod_wsgiをインストールし、apacheで動作するように設定します。

Vgrant(CentOS7)にAnaconda+Django+Apache環境を作る(MariaDBのインストール・設定)

⑥管理画面(admin)にCSSを適用します。

Vgrant(CentOS7)にAnaconda+Django+Apache環境を作る(管理画面のCSS)

⑦Bootstrapをインストールします。

VagrantのDjangoで作るWebアプリケーション(その6 Bootstrapのインストール)

⑧自作のログインページを作成します。

自作のログインページ(Django)

⑨ユーザ登録ページを作成します。

ユーザ登録(Django)

⑩Userモデルを使用してユーザ情報変更ページとパスワード変更ページを作ります。

Userモデルを使用してユーザ情報変更ページとパスワード変更ページを作る(Django)

ホスト環境

OS Ubuntu 16.04.1 LTS 64bit
Virtualbox 5.1
Vagrant 1.9.5

ゲスト環境

OS CentOS 7.1.1503
pyenv 1.1.3-5-g7dae197
Anaconda 3-4.3.0
MariaDB 5.5.52-1.el7
Apache 2.4.6
mod_wsgi 4.5.14

Vagrantへログイン

①【ホスト環境】端末を開き、前回構築したVagrantのディレクトリまで移動します。

cd vagrant/django_apps/

②【ホスト環境】仮想マシンを起動します。

vagrant up

③【ホスト環境】ログインします。

vagrant ssh

プロジェクトの設定

プロジェクトディレクトリを「pj」、アプリケーションディレクトリを「app1」とします。プロジェクトの設定は、前回と同じです。

モデルの設定

①models.pyを編集します。

vi pj/app1/models.py

以下のように編集します。Profileクラスを作り、電話番号と性別を追加します。性別は、セレクトボックスになります。

from django.contrib.auth.models import User
from django.db import models

GENDER_CHOICES = (
    ("女性", "女性"),
    ("男性", "男性"),
)

class Profile(models.Model):
    phone = models.CharField("電話番号", max_length=255, blank=True)
    gendar = models.CharField("性別", max_length=2, choices=GENDER_CHOICES, blank=True)
    user = models.OneToOneField(User)

    def __str__(self):
       return self.user

・「OneToOne」を追加します。これにより、profile.userやuser.profileとすることで、相互に呼び出すことができます。

user = models.OneToOneField(User)

③makemigrationsを実行します。

python pj1/manage.py makemigrations app1

以下のような結果が表示されます。

Migrations for 'app1':
  pj1/app1/migrations/0002_profile.py
    - Create model Profile

④実行されるSQLを確認します。

python pj1/manage.py sqlmigrate app1 0002

以下のような結果が表示されます。

BEGIN;
--
-- Create model Profile
--
CREATE TABLE `app1_profile` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `phone` varchar(255) NOT NULL, `gendar` varchar(2) NOT NULL, `user_id` integer NOT NULL UNIQUE);
ALTER TABLE `app1_profile` ADD CONSTRAINT `app1_profile_user_id_04d51e3a_fk_auth_user_id` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`);
COMMIT;

⑤migrateを実行します。

python pj1/manage.py migrate

以下のような結果が表示されます。

Operations to perform:
  Apply all migrations: admin, app1, auth, contenttypes, sessions
Running migrations:
  Applying app1.0002_profile... OK

アプリケーションの設定

①forms.pyを編集します。

vi pj/app1/forms.py

前回のforms.pyに加えて、以下の内容を追加します。

from django import forms
from django.contrib.auth.forms import UserCreationForm
from .models import Profile

・・・省略・・・

class UserCreateForm(UserCreationForm):

・・・省略・・・

class ProfileForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['gendar'].widget.attrs['class'] = 'form-control'
        self.fields['phone'].widget.attrs['class'] = 'form-control'

    class Meta:
        model = Profile
        fields = (
            "gendar", "phone"
        )

②アプリケーションディレクトリのviews.pyを編集します。

vi pj1/app1/views.py

前回のviews.pyに加えて、以下の内容を追加します。(new関数を変更します。)

from django.contrib.auth import login
from django.shortcuts import render, redirect
from .forms import ProfileForm, UserCreateForm

・・・省略・・・

def new(request):

    form = UserCreateForm(request.POST or None)
    profile_form = ProfileForm(request.POST or None)

    if request.method == "POST" and form.is_valid() and profile_form.is_valid():

        #Userモデル処理
        user = form.save(commit=False)
        user.is_staff = True
        user.save()

        #Profileモデルの処理
        profile = profile_form.save(commit=False)
        profile.user = user
        profile.save()

        login(
            request, user, backend="django.contrib.auth.backends.ModelBackend")


        return redirect("app1:index")

    context = {
        "form": form,
        "profile_form": profile_form,
    }
    return render(request, 'form.html', context)

・・・省略・・・

templateへ複数のフォームを渡すことができます。またそれを受け取ることも可能です。

・・・省略・・・

    form = UserCreateForm(request.POST or None)
    profile_form = ProfileForm(request.POST or None)
 
・・・省略・・・

    context = {
        "form": form,
        "profile_form": profile_form,
    }
    return render(request, 'form.html', context)

・・・省略・・・

Userモデルを作成します。「commit=False」は、データベースには保存せず、保存する前のモデルオブジェクトを返します。よって、「user.is_staff」等のアクセスが可能です。

        # Userモデルの処理。ログインできるようis_staffをTrueにし保存
        user = form.save(commit=False)
        user.is_staff = True
        user.save()

.save(commit=False) : 保存すると、モデルオブジェクトが得られます。

is_staff : この値が真なら、ユーザは admin サイトにアクセスできます。

「login()」でログインします。すでにユーザ名・パスワードが存在する場合は、先に「authenticate()」を呼び出しますが、ここでは新規にユーザを作りますので呼び出しません。「authenticate()」を使わずにログインさせる場合はbackendを必ず指定します。ここで指定する「django.contrib.auth.backends.ModelBackend」は、Djangoのデフォルトのバックエンドです。

        login(
            request, user, backend="django.contrib.auth.backends.ModelBackend")

login()

ユーザをログインさせるには、ビューの中でこの関数を使います。この関数は、HttpRequestオブジェクトとUserオブジェクトを引数にとります。login()は、Djangoのセッションフレームワークを使って、ユーザのIDをセッションに保存します。従って、セッションミドルウェアをインストールしておかねばなりません。

・authenticate()

ユーザを手動でログインさせる場合、「login()」を呼び出す前に必ず 「authenticate()」を呼び出してください。「authenticate()」は、Userオブジェクトに、そのユーザが 認証バックエンドによって正しく認証されたことを示す属性を付加します。この情報が後々ログイン処理で必要になります。

テンプレートの設定

アプリケーションディレクトリ配下のtemplatesディレクトリへhtmlテンプレートを作成します。

base.html、index.html、login.html、logout.html、profile.htmlは前回と同じです。

①form.htmlを変更します。

vi pj1/app1/templates/form.html

以下のように記述します。

{% extends "base.html" %}
{% block content %}

<form class="my-form" action="" method="POST">
  <div class="form-group">
    <label for="id_username">ユーザネーム</label>
    {{ form.username }}
    {{ form.username.errors }}
    <p class="help-block">{{ form.username.help_text }}</p>
  </div>

  <div class="form-group">
    <label for="id_email">Email</label>
    {{ form.email }}
    {{ form.email.errors }}
    <p class="help-block">{{ form.email.help_text }}</p>
  </div>

  <div class="form-group">
    <label class="control-label" for="id_password1">パスワード</label>
    {{ form.password1 }}
    {{ form.password1.errors }}
  </div>

  <div class="form-group">
    <label class="control-label" for="id_password2">パスワード(確認)</label>
      {{ form.password2 }}
      {{ form.password2.errors }}
      <p class="help-block">{{ form.password2.help_text }}</p>
  </div>

  <div class="form-group">
    <label for="id_firstname">FirstName</label>
    {{ form.first_name }}
    {{ form.first_name.errors }}
    <p class="help-block">{{ form.first_name.help_text }}</p>
  </div>

  <div class="form-group">
    <label for="id_firstname">FirstName</label>
    {{ form.first_name }}
    {{ form.first_name.errors }}
    <p class="help-block">{{ form.first_name.help_text }}</p>
  </div>

  <div class="form-group">
    <label for="id_lastname">LastName</label>
    {{ form.last_name }}
    {{ form.last_name.errors }}
    <p class="help-block">{{ form.last_name.help_text }}</p>
  </div>

  <div class="form-group">
    <label for="id_gendar">性別</label>
    {{ profile_form.gendar }}
  </div>

  <div class="form-group">
    <label for="id_phone">電話番号</label>
    {{ profile_form.phone }}
  </div>

  <div class="form-group">
    <div>
      <input type="submit" class="btn btn-default" value="登録">
    </div>
  </div>
  {% csrf_token %}
</form>
{% endblock %}

②profile.htmlを変更します。

vi pj1/app1/templates/profile.html

以下のように記述します。

{% extends "base.html" %}
{% block content %}
user.username(名前) : {{ user.username }}<hr>
user.is_staff(/adminにログインできるか) : {{ user.is_staff }}<hr>
user.is_active(アカウントはアクティブか、通常のログインはできるか) : {{ user.is_active }}<hr>
user.is_superuser(すうぱあゆうざあ ですか) : {{ user.is_superuser }}<hr>
user.last_login(最期のログイン) : {{ user.last_login }}<hr>
user.date_joined(アカウントの作られた日) : {{ user.date_joined }}<hr>
性別:{{ user.profile.gendar }}<br>
電話:{{ user.profile.phone }}<br>
{% endblock %}

トラックバック用のURL
プロフィール

名前:イワサキ ユウタ 職業:システムエンジニア、ウェブマスター 誕生:1986年生まれ 出身:静岡県 特技:ウッドベース 略歴 2008年04月 金融機関系I

最近の投稿
人気記事
カテゴリー
広告