django 1.8 のmodelformを使って、画像を登録・更新する
環境
- django 1.8
- python 2.7
目的
ユーザが自分自身の画像を登録できるようにする。
formで画像を登録するときの動きはほかのmodel でも利用可能です。
modelform を利用します。
変更に必要なファイルは次の通り。
- original_auth/models.py
- original_auth/urls.py
- original_auth/views.py
- original_auth/forms.py
- original_auth/templates/original_auth/original_user_update.html
一つずつ見ていきましょう。
original_auth/models.py
original_auth/models.py をみます。
主な初期値からの変更点は次の通り
- カスタムユーザを作成
- ログイン名をusernameからemail に変更
なお、2つとも画像登録に関係ない変更です。
どんなフィールドを使用しているか見てもらえればいいかなと。
// original_auth/models.py
#-*- coding: utf-8 -*-
from django.db import models
from django.contrib.auth.models import AbstractUser,AbstractBaseUser,PermissionsMixin,UserManager
from django.core.urlresolvers import reverse
from django.dispatch import receiver
from django.db.models.signals import post_save
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from django.utils import timezone
from django.contrib.auth.models import (
BaseUserManager, AbstractBaseUser, _user_has_perm, _user_has_module_perms
)
from django.core import validators
from django.core.mail import send_mail
class OriginalUser(AbstractBaseUser,PermissionsMixin):
"""User """
image = models.ImageField(_('image URL'),upload_to='user/images/%Y/%m/%d/', blank=True)
username = models.CharField(_('username'),
max_length=30,
blank=True,
help_text=_('Required. 30 characters or fewer. Letters, numbers and '
'@/./+/-/_ characters'))
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=30, blank=True)
email = models.EmailField(verbose_name=_('email address'), max_length=255, unique=True)
is_active = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
def __str__(self):
return self.username
def get_full_name(self):
"""
Returns the first_name plus the last_name, with a space in between.
"""
full_name = '%s %s' % (self.first_name, self.last_name)
return full_name.strip()
def get_short_name(self):
"Returns the short name for the user."
return self.first_name
def email_user(self, subject, message, from_email=None, **kwargs):
"""
Sends an email to this User.
"""
send_mail(subject, message, from_email, [self.email], **kwargs)
def get_absolute_url(self):
return "/user/%i/" % self.id
original_auth/urls.py
つぎ original_auth/urls.py
from django.conf.urls import patterns, url
from original_auth.views import user_update
urlpatterns = patterns('',
url(r'^(?P<pk>\d+)/update$',
user_update,
name='original_user_update'
),
)
original_auth/views.py
つぎ、original_auth/views.py をみます。
- ログインユーザと違うユーザが変更画面にアクセスしたら表示させない
- 新規画像ファイルがなかったら、user情報を更新。
- 新規画像ファイルがあったら、あたらしくinstance を作成し、user情報を上書き。
もっといい方法があればしりたい。
// original_auth/views.py
from django.http import HttpResponseRedirect
from django.core.exceptions import PermissionDenied
from django.contrib.auth.decorators import login_required
from original_auth.models import OriginalUser
from original_auth.forms import OriginalUserUpdateForm
@login_required
def user_update(request, pk):
'''
:pk: unicode
:request.user.pk: integer
''''
request.user.pk == int(pk):
u = OriginalUser.objects.get(id=pk)
form = OriginalUserUpdateForm(request.POST or None, request.FILES or None,instance=u)
args = {}
if form.is_valid():
if request.FILES:
instance = OriginalUser(image = request.FILES['image'])
else:
instance = u
instance.id = u.id
instance.email = u.email
instance.password = u.password
instance.username = form.cleaned_data['username']
instance.first_name = form.cleaned_data['first_name']
instance.last_name = form.cleaned_data['last_name']
instance.is_active = u.is_active
instance.is_staff = u.is_staff
instance.date_joined = u.date_joined
instance.save()
return HttpResponseRedirect("/user/%s" % (pk))
else:
form = OriginalUserUpdateForm(request.POST or None, instance=u)
args['form'] = form
return render(request, 'original_auth/original_user_update.html', args)
else:
raise PermissionDenied
original_auth/forms.py
つぎ、 original_auth/forms.py をみます。
fields = '__all__'にしてしまうと、(暗号化された)パスワードも見えるので、パスワード変更は別フォームで行ったほうが楽です。
変更したいフィールドだけ指定するようにします。
#-*- coding: utf-8 -*-
from django import forms
from original_auth.models import OriginalUser
class OriginalUserUpdateForm(forms.ModelForm):
image = forms.ImageField(required=False)
class Meta:
model = OriginalUser
#fields = '__all__'
fields = ['username','image','first_name','last_name']
original_auth/templates/original_auth/original_user_update.html
最後、templates です。
enctype="multipart/form-data"を忘れずに。これがないと画像を扱えません。- 当然のことですが、
{% csrf_token %}つけましょう
{% extends "base.html" %}
{% block content %}
<div>
{% if form.has_errors %}
{% for field in form.fields %}
{% if field.error %}
{{ field.error }}
{% endif %}
{% endfor %}
{% endif %}
<form method="POST" class="post-form" enctype="multipart/form-data">{% csrf_token %}
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="{% trans 'Submit' %}" />
</form>
</div>
{% endblock %}
以上です。