Расширенный профайл юзера в Django: редактирование расширенных и встроенных полей через одну форму
Избитая задача: сделать профайл пользователя, расширяющий встроенную модель django.contrib.auth.models.User. Допустим, нужно добавить в профайл юзера поле about, где он может написать кратко о своих интересах и т.п. Предполагается, что система авторизации юзеров на основе встроенных стредств Django у вас на сайте уже имеется.
Делаем, как прописано в мануалах Django. Определяем модель, расширяющую django.contrib.auth.models.User:
from django.db import models from django.contrib.auth.models import User class UserProfile(models.Model): # необходимое поле для связки со встроенной моделью юзера Django user = models.ForeignKey(User, unique=True) # наше добавляемое поле about = models.TextField(blank=True)
ну и сохраняем этот класс в свой models.py
В settings.py проекта прописываем параметр AUTH_PROFILE_MODULE, который позволит обращаться к нашей расширенной модели через вызов метода get_profile у встроенной модели django.contrib.auth.models.User.
AUTH_PROFILE_MODULE = 'models.UserProfile'
В принципе, модель готова. Теперь (например) в шаблонах можно использовать такую конструкцию для вывода нашего поля about:
{{ user.get_profile.about }}
Только не забудьте для такого шаблона использовать RequestContext вместо Context, и подключить соотв.процессор контекста в settings.py:
TEMPLATE_CONTEXT_PROCESSORS = ( ... 'django.contrib.auth.context_processors.auth', ... )
Дальше нужно писать представления для просмотра/редактирования/создания/списка наших профайлов. Но лень.
Берем маленькое приложение Django под названием profiles вот тут, распаковываем архив, копируем каталог profiles в каталог, включенный в sys.path.
(для таких случаев у меня есть каталог django_apps).
Подключаем это приложение в urls.py своего проекта:
urlpatterns = patterns('', ... (r'^profiles/', include('profiles.urls')), ... )
и в settings.py:
INSTALLED_APPS = ( ... 'profiles', )
Добавляем таблицы этого приложения и свою таблицу профайлов в базу:
[~]$ python manage.py syncdb
Осталось сделать шаблоны. Приложение profiles использует четыре штуки. Их имена по умолчанию:
- profiles/create_profile.html
- profiles/edit_profile.html
- profiles/profile_detail.html
- profiles/profile_list.html
За что они отвечают, понятно из их имен. Написание шаблонов для отображения профайла юзера (profile_detail.html) и списка профайлов (profile_list.html) оставим в качестве упражнения для заинтересованных читателей этого поста.
А вот шаблоны создания и редактирования своего профайла юзером сделаем. Для простоты и краткости сделаем их одинаковыми.
В каталоге, указанном в параметре TEMPLATE_DIRS файла settings.py, создаем подкаталог profiles, а в нем шаблоны edit_profile.html и create_profile.html с таким вот (например) содержанием (код кривой отображается, видно из-за экранирования html, как правильно html сюда вводить — непонятно):
{% extends "base.html" %} {% block content %} {% csrf_token %} {{ form.as_p }} /> {% endblock %}
Предполагается, что шаблон base.html с основным html-кодом страниц сайта у вас есть.
Лирическое отступление. Я использую для регистрации юзеров еще одно приложение того же автора — registration. Профайл юзера создается автоматически по сигналу от этого приложения при активации нового юзера на сайте. Так что, лично мне шаблон создания нового профайла вообще не нужен.
Готово! Логинимся каким-нибудь юзером на свой сайт, переходим в браузере по адресу mysite.ru/profiles/edit/ упс…
На станице редактирования профайла только одно поле about из нашей расширенной модели. Имя и фамилию, которые хранятся во встроенной модели, нужно редактировать в админке. Хорошо бы сделать так, чтобы юзер на одной странице мог редактировать имя, фамилию и заметку о себе.
Использованное нами приложение profiles автоматически создает форму редактирования профайла на основе модели, указанной в параметре AUTH_PROFILE_MODULE файла settings.py. А в этой модели у нас единственное поле about (служебное связывающее поле user отбрасывается). Но это приложение позволяет передавать своим функциям-представлениям доп.параметы, среди которых есть параметр form_class, задающий класс формы, используемый для редактирования профайла. Этой фичей и воспользуемся.
Чтобы не изменять элементы внешнего приложения, добавми в urls.py своего проекта строчку перед инклудом урл приложения profiles. Эта строчка перехватит обращение при запросе на редактирование профайла и вместо вызова представления, предоставляемого profiles по умолчанию, вызовет представление с нужным доп.параметром.
Соответсвующий фрагмент urls.py проекта должен выглядеть как-то так:
urlpatterns = patterns('', ... (r'^profiles/edit/$', 'profiles.views.edit_profile', {'form_class': forms.ProfileForm}, 'profiles_create_profile'), (r'^profiles/', include('profiles.urls')), ... )
Теперь нужно добавить определение класса формы ProfileForm в файл forms.py проекта. Идея заключается в том, что мы
- сабклассим форму редактирования профайла на основе модели,
- добавляем два поля для имени и фамилии юзера,
- при создании экземпляра формы запоминаем экземпляр модели профайла, передаваемый в параметре instance,
- считываем из обьекта профайла связанный обьект user и инициализируем значениями first_name/last_name два поля нашей формы,
- при сохранении модели (метод save) присваиваем значения этих полей соотв.полям обьекта user и сохраняем его вместе с нашим профайлом.
Код:
import django class ProfileForm(django.forms.ModelForm): first_name = django.forms.CharField(max_length=30, required=False) last_name = django.forms.CharField(max_length=30, required=False) def __init__(self, *args, **kwargs): # получаем обьект профайла self.prof = kwargs.get('instance', None) initial = {'first_name': self.prof.user.first_name, 'last_name': self.prof.user.last_name} # в два поля нашей формы помещаем значения соотв.полей из модели user kwargs['initial'] = initial super(ProfileForm, self).__init__( *args, **kwargs) class Meta: # форма для нашей модели профайла model = models.UserProfile # для красоты, чтобы поля в форме шли в правильном порядке fields = ('first_name', 'last_name', 'about') def save(self, commit=True): super(ProfileForm, self).save(commit) if commit: self.prof.user.first_name = self.cleaned_data['first_name'] self.prof.user.last_name = self.cleaned_data['last_name'] self.prof.user.save()
Теперь при редактировании своего профайла по адресу mysite.ru/profiles/edit/ залогиненный юзер на одной страничке может редактировать свои имя, фамилию, и заметку ‘о себе’. При этом имя/фамилия сохраняются во встроенной модели django.contrib.auth.models.User в полях first_name/last_name, а заметка ‘о себе’, в поле about нашей модели UserProfile.