@seocoder

Расширение модели User в Django — AUTH_PROFILE_MODULE

Есть модель.
class Team(models.Model):
name = models.CharField(max_length=25, unique=True)

def __unicode__(self):
return self.name

class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
team = models.ForeignKey(Team, unique=True)

settings.py:
AUTH_PROFILE_MODULE = 'project.pm.UserProfile'

views.py
if request.method == 'POST':
r = RegisterForm(request.POST)
if r.is_valid():
team = Team(name=request.POST.get('team'))
team.save()
user = User.objects.create_user(username=request.POST.get('email'),
email=request.POST.get('email'),
password=request.POST.get('password'))
user.get_profile.team = team.id
user.save()

Валится с ошибкой на сохранении team
AttributeError at /register
'instancemethod' object has no attribute 'team'

Вопроса собственно два. Первый — как запустить нормально то что дал выше, и второе — как бы сделать это красивее в джанго стиле.
p.s. Ну новичок я в джанго, прочитал только доки и посмотрел пару туториалов.
  • Вопрос задан
  • 6898 просмотров
Пригласить эксперта
Ответы на вопрос 5
@marazmiki
Укротитель питонов
Не советую нормально запускать то что написали: слишком уж много идеологических ошибок.

Во-первых, Вы не проверяете пользовательский ввод. Два примера: у Вас в модели Team уникальный индекс на поле name. Если пользователь введёт в POST-форме имя команды, которое уже существует, вывалится ошибка базы данных. Аналогичная ситуация с User.

Во-вторых, Вы Вы создаёте User, но не создаёте UserProfile. Сам он создаваться не будет, следовательно, вызов user.get_profile() (у Вас, кстати, скобочек не было, отсюда и AttributeError).

В-третьих, Вы пытались в поле внешнего ключа, которое должно принимать объект модели, пытаетесь передать целочисленное значение. Надо было так:
user.get_profile().team = team


Как правильно? Используйте ModelForm. Они возьмут на себя рутинную работу по грамотной валидации данных и будут возвращать сконструированные инстансы моделей.

Хотя конкретно в этом случае ModelForm не очень подойдёт, потому что данные сохраняются в несколько разных моделей. В таких случаях приходится использовать Form и чуть-чуть програмировать, а именно описывать нестандартную логику валидациитам, где это требуется (метод clean_something описывает пользовательскую валидацию поля something, подробности в разделе Form and field validation документации).

Код формы (forms.py) будет примерно таким (писалось экспромтом и не тестировалось, не надо бездумно копипастить):
# -*- coding: utf-8 -*-
from django import forms
from django.contrib.auth.models import User

class RegisterForm(forms.Form):
    username = forms.CharField()
    email    = forms.EmailField()
    password = forms.CharField()
    teamname = forms.CharField()

    def clean_username(self):
        """
        Проверим уникальность юзернейма
        """
        username = self.cleaned_data.get('username')

        if User.objects.filter(username=username).count() > 0:
            raise forms.ValidationError, 'User %s is already exists' % username
        return username

    def clean_team(self):
        """
        Проверим уникальность имени команды
        """
        name = self.cleaned_data.get('teamname')

        if Team.objects.filter(name=name).count() > 0:
            raise forms.ValidationError, 'Team %s is already exists' % name
        return name
    
    def clean(self):
        """
        Подготовка чистых данных для вставки в модель
        """
        data = super(RegisterForm, self).clean()

        data['user'] = User.objects.create_user(
            username = data['username'],
            password = data['password'],
            email    = data['email'],
        )
        data['team'] = Team.objects.create(
            name = data['teamname'],
        )

        return data


А кусок с самой регистрацией в views.py будет выглядеть примерно так:
form = RegisterForm(request.POST or None)
if form.is_valid():
    data = form.cleaned_data
    profile, created = UserProfile.objects.get_or_create(
        user = data['user'], # user - модель, а не строка
        team = data['team'], # team тоже модель
    )


При желании можно инкапсулировать создание UserProfile в классе формы. Это даже правильнее, но в данном случае непринципиально :)

Если я где-то ошибся или непонятно — спрашивайте и добро пожаловать в клуб :)
Ответ написан
@Fak3
1) до того как обращаться к профилю — его нужно создать (после создания и сохранения user и team):
UserProfile.objects.create(user=user, team=team)
это создаст и сохранит в БД профиль с нужными параметрами.
2) Тут ошибка —
user.get_profile.team = team.id
get_profile — это функция, обращаться к ней нужно так:
user.get_profile().team = team
но в вашем случае — эта строчка не нужна вообще, если вы создали профиль, как я написал выше.
Ответ написан
Комментировать
un1t
@un1t
Нужно сделать чтобы профиль автоматически создавался при создании пользователся
from django.db.models.signals import post_save
def create_profile(sender, **kwargs):
__user = kwargs['instance']
__if kwargs["created"]:
____profile = UserProfile(user=user)
____profile.save()
post_save.connect(create_profile, sender=User)


coderiver.ru/2011/01/avtomaticheskoe-sozdanie-profilej-pri-sozdanii-yuzera/
Ответ написан
@marazmiki
Укротитель питонов
И я, пожалуй, оставлю тут ссылку на топик смежной тематики
Ответ написан
Комментировать
@seocoder Автор вопроса
Хм. Получается вообще смысла в таком связывании мало, так как всё делать руками.

А можно перенаследовать базовую модель авторизации, добавив нужные аттрибуты, без промежуточной таблицы и унаследовав изменить создание юзера и проверку авторизации?
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы