Django расширение модели user: Django расширение модели User

Содержание

Django расширение модели User

23 Янв 2021 ,
1373

Если вы создаете новый проект на Django , то я рекомендую использовать пользовательскую модель User , которая расширяется от подкласса AbstractBaseUser. Вы конечно , можете этого не делать и использовать другие стратегии , такие как:

Но по моему личному мнению расширение от подкласса  AbstractBaseUser является самым гибким способом, хоть и вначале требует определенных усилий для его реализации.

Вначале я вкратце расскажу о других стратегиях расширения модели User. Об их достоинствах и недостатках. А потом мы реализуем создание пользовательской модели с помощью расширения от подкласса AbstractBaseUser

Использование прокси-модели

Эта стратегия используется в том случае , когда нам не нужны новые поля для модели User или переопределения существующих полей, но нужны поведенческие изменения , такие как переопределение сортировки по умолчанию, добавление новых методов для работы с моделью ,использование пользовательских менеджеров.



class CustomUser(User):
    objects = PersonManager()

    class Meta:
        proxy = True
        ordering = ('first_name', )


Тут мы создаем прокси-модель Person , которая наследуется от User.Внутри Meta мы указываем proxy=True , чтобы указать , что это модель является прокси. И для этой модели в базе данных не создается таблица.

Достоинством этой стратегии является простота реализации.И эту стратегию вы можете использовать не только при создании проекта , но на любом этапе жизненнего цикла вашего проекта.

Недостатком — ограниченность, так как мы не можем создавать новые поля или переопределять существующие поля.

Использование связи один-к-одному с пользовательской моделью

Если нам нужно хранить дополнительную информацию о существующей модели пользователя и которая не связана с аутентификацией , то мы можем создать новую модель , которая будет связана с существующим моделем User c помощью связи один-к-одному.



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

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    avatar = models.TextField(max_length=500, blank=True)
    bith_date = models.TextField(max_length=500, blank=True)

   @receiver(post_save, sender=User)
    def create_user_profile(sender, instance, created, **kwargs):
        if created:
             Profile.objects.create(user=instance)

    @receiver(post_save, sender=User)
    def save_user_profile(sender, instance, **kwargs):
          instance.profile.save()
   




Достоинством данной стратегии является то , что мы можем создать новые поля и это можно сделать не только при создании проекта , но в любой момент времени когда вам это понадобится.

Недостатком данной стратегии является то , что у нас будет еще одна таблица с полями для пользователя и создаются лишние запросы при обращении к связанным данным. Это можно в определенной мере решить с использованием selected_related

Расширение от подкласса

AbstractUser

Этот способ в отличие от предыдущих , нужно реализовывать вначале создания проекта перед применением миграций.

Этот метод используется в том случае если вас устраивает аутентификация в том виде , которая предоставляется стандартно , но вам нужно добавить новые данные , но в отличие от прокси-модели не создаете новый класс или создание новой модели с таблицей , как при использовании стратегии использование связи один-к-одному с пользовательской моделью.

Класс django.contrib.auth.models.AbstractUser обеспечивает полную реализацию пользователя по умолчанию как абстрактную модель




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

class User(AbstractUser):
    birth_date = models.DateField(null=True, blank=True)





AUTH_USER_MODEL = 'users.User'


Расширение от подкласса

AbstractBaseUser

Ну и в конце я создам пользовательскую модель путем расширения от класса AbstractBaseUser. Этот способ считается сложным , а некоторые советуют его применять в крайнем случае, но по мне для сложных проектов этот способ является самым предпочитаемым. Но это дело вкуса.

Часто в моих проектах в качестве логина используется либо email или номер телефона. А поле username нам вообще не нужен. Так что мы при создании модели , который наследуются от AbstractBaseUser , можем указать поле , который используется в качестве логина. Хотя , я видел статью где это можно сделать и при расширении от класса AbstractUser.

Ну довольно теории. Создадим виртуальное окружение , установим Django и создадим новый проект.


Создадим новое приложение users и в файле models.py создадим модель User , который будет наследоваться от AbstractBaseUser и от миксина PermissionsMixin




import os
import datetime
import os.path
from django.db import models
from django.conf import settings
from django.utils import timezone
from django.core.validators import RegexValidator

from django.contrib.auth.models import (
    BaseUserManager, AbstractBaseUser, PermissionsMixin
)


class UserManager(BaseUserManager):

    def create_user(self, email, password=None,**kwargs):
        if not email:
            raise ValueError('Users must have an Email')

        user = self.model(
            email=email,**kwargs)

        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, password):
        """
        Creates and saves a superuser with the given email and password.
        """
        user = self.create_user(
            email,
            password=password
        )
        user.is_admin = True
        user.save(using=self._db)
        return user


class User(AbstractBaseUser,PermissionsMixin):
    email = models.EmailField(max_length=255, unique=True)
    first_name = models.CharField('Фамилия', max_length=255, blank=True, null=True)
    last_name = models.CharField('Имя', max_length=255, blank=True, null=True)
    avatar = models.ImageField(null=True, blank=True, upload_to='avatars')
    date_of_birth = models.DateField(verbose_name="Дата рождения", null=True, blank=True)
    last_time_visit = models.DateTimeField(default=timezone.now)
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)

    objects = UserManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    def __str__(self):
        return self.email

    class Meta:
        verbose_name = 'Пользователь'
        verbose_name_plural = 'Пользователи'



Создайте миграции для users. Важно , это вы должны сделать до применения первоначальных миграций



python manage.py makemigrations


Применяем все миграции проекта



python manage.py migrate


Заключение

Для простых проектов вы можете использовать встроенную модель без расширения, так как он из коробки работает прекрасно и выполняет базовые вещи. Для простых сайтов , где не нужна особо работа с пользователями , то применятся вариант из коробки. Для этого блога это вполне хватает ))

Но если вы разрабатываете сложные проекты , то я рекомендую расширять пользовательскую модель. Вначале это сложно и требует некоторых усилий , но в дальнейшем это окупится.

Please enable JavaScript to view the comments powered by Disqus.
comments powered by

Расширение модели User · Django в примерах

Расширение модели User

При работе с учетными записями пользователей вы узнаете, что модель User механизма аутентификации с помощью Джанго подходит для распространенных случаев. Однако модель User поставляется с довольно базовыми возможностями. Пользователь может расширить модель User, включив в нее дополнительные данные. Лучшим способом для этого является создание модели профиля, которая содержит все дополнительные поля и связь «один к одному» с моделью User.

Откройте файл models.py приложения account и внесите в него следующий код:

from django.db import models
from django.conf import settings

class Profile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL)
    date_of_birth = models.DateField(blank=True, null=True)
    photo = models.ImageField(upload_to='users/%Y/%m/%d', blank=True)

    def __str__(self):
        return 'Profile for user {}'.format(self.user.username)

In order to keep your code generic, use the get_user_model() method to retrieve the user model and the AUTH_USER_MODEL setting to refer to it when defining model’s relations to the user model, instead of referring to the auth User model directly.

Связь «один к одному» позволяет связывать профили с пользователями. Поле photo является полем ImageField . Вам потребуется установить один из пакетов Python для управления изображениями. Установите Pillow, запустив в терминале следующую команду:

pip install Pillow==2.9.0

Для обслуживания файлов мультимедиа, загруженных пользователями с сервероа разработки, добавьте следующие параметры в файл settings.py проекта:

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')

MEDIA_URL — это базовый URL-адрес для обслуживания файлов мультимедиа, отправляемых пользователями, а MEDIA_ROOT — локальный путь, в котором они находятся. Мы динамически строим путь относительно нашего пути проекта, чтобы сделать код более универсальным.

Отредактируйте основной файл urls.py проекта bookmarks и добавьте в него следующий код:

from django.account/', include('account.urls')),
]
if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Таким образом, сервер разработки Джанго будет отвечать за службу мультимедийных файлов во время разработки.

Вспомогательная функция static() подходит для разработки, но не для использования в продакшн версии.Никогда не обслуживайте статические файлы с Джанго в продакшн версии.

Откройте оболочку и выполните следующую команду, чтобы создать миграцию базы данных для новой модели:

python manage.py makemigrations

Вы увидите следующее:

Migrations for 'account':
    0001_initial.py:
        - Create model Profile

Затем синхронизируйте базу данных следующей командой:

python manage.py migrate

Вы увидите следующее:

Applying account.0001_initial... OK

Измените файл admin.py приложения account и зарегистрируйте модель Profile на сайте администрирования:

from django.contrib import admin
from .models import Profile

class ProfileAdmin(admin.ModelAdmin):
    list_display = ['user', 'date_of_birth', 'photo']

admin.site.register(Profile, ProfileAdmin)

Запустите сервер разработки снова с помощью команды python manage.py runserver. Теперь вы можете видеть модель Profile в административной части сайта вашего проекта:

Теперь мы позволим пользователям редактировать свой профиль на веб-сайте. Добавьте следующие модели формы в файл forms.py приложения account:

from .models import Profile

class UserEditForm(forms.ModelForm):
    class Meta:
        model = User
        fields = ('first_name', 'last_name', 'email')

class ProfileEditForm(forms.ModelForm):
    class Meta:
        model = Profile
        fields = ('date_of_birth', 'photo')

Немного о коде выше:

  • UserEditForm : Позволит пользователям изменять свое имя, фамилию и электронную почту, хранящиеся во встроенной пользовательской модели.
  • ProfileEditForm : Позволит пользователям редактировать дополнительные данные, сохраняемые в пользовательской модели Profile. Пользователи смогут изменить дату рождения и отправить фотографию для своего профиля.

Отредактируйте файл views.py приложения account и сделайте импорт модели Profile:

from .models import Profile

И добавьте следующие строки в представление register под new_user.save():


profile = Profile.objects.create(user=new_user)

Когда пользователи регистрируются на нашем сайте, мы создаем пустой профиль, связанный с ними. Необходимо создать объект Profile вручную с помощью административной части сайта для созданных ранее пользователей.

Теперь мы позволим пользователям редактировать их профиль. Добавьте следующий код в тот же файл:

from .forms import LoginForm, UserRegistrationForm, UserEditForm, ProfileEditForm

@login_required
def edit(request):
    if request.method == 'POST':
        user_form = UserEditForm(instance=request.user, data=request.POST)
        profile_form = ProfileEditForm(instance=request.user.profile, data=request.POST, files=request.FILES)
        if user_form.is_valid() and profile_form.is_valid():
            user_form.save()
            profile_form.save()
    else:
        user_form = UserEditForm(instance=request.user)
        profile_form = ProfileEditForm(instance=request.user.profile)
        return render(request,
                      'account/edit.html',
                      {'user_form': user_form,
                       'profile_form': profile_form})

Мы используем декоратор login_required, так как пользователи должны авторизоваться для редактирования своего профиля. В этом случае используются две модели форм: UserEditForm для хранения данных встроенной модели User и ProfileEditForm для хранения дополнительных данных профиля. Чтобы проверить представленные данные, мы проверяем, что метод is_valid() обеих форм возвращает значение true.edit/$’, views.edit, name=’edit’),

Наконец, создайте шаблон для этого представления в templates/account/ и назовите его edit.html. Добавьте в него следующий код:

{% extends "base.html" %}

{% block title %}Edit your account{% endblock %}

{% block content %}
    <h2>Edit your account</h2>
    <p>You can edit your account using the following form:</p>
    <form action="." method="post" enctype="multipart/form-data">
        {{ user_form.as_p }}
        {{ profile_form.as_p }}
        {% csrf_token %}
        <p><input type="submit" value="Save changes"></p>
    </form>
{% endblock %}

We include enctype=»multipart/form-data» in our form to enable file uploads. We use one HTML form to submit both the user_form and the profile_form forms.

Зарегистрируйте нового пользователя и пройдите по адресу http://127.0.0.1:8000/account/edit/ . Вы увидите следующую страницу:

Теперь можно также отредактировать страницу панели мониторинга и включить ссылки для редактирования страниц профиля и смены пароля. Откройте шаблон account/dashboard.html и замените эту строку:

<p>Welcome to your dashboard.</p>

…на эту:

<p>Welcome to your dashboard. You can <a href="{% url "edit" %}">edit your profile</a> or <a href="{% url "password_change" %}">change your password</a>.</p>

Теперь пользователи могут получить доступ к форме для редактирования профиля в панели управления.

Пользовательская модель User | Советы для Джанго

Каждый новый проект Django должен использовать пользовательскую модель User. Официальная документация Django гласит, что это «настоятельно рекомендуется», но я сделаю еще один шаг и без колебаний скажу: вы просто с ума сошли, если не использовали пользовательскую модель раньше.

Зачем? Потому что вам придется внести изменения в пользователя в какой-то момент в жизни вашего проекта — добавить поле даты рождения, возраст, что угодно — и если вы не начали с пользовательской модели User до самой первой выполненной вами команды переноса, тогда вы попадете в мир боли.

Однако, если вы используете пользовательскую модель, вы можете легко добавлять и изменять ее.

Можно ли переключиться на пользовательскую модель в середине проекта? Да. Хочешь ли ты это сделать? Лучше не делать.

Вот самый простой способ, чтобы начать каждый новый проект с правильного пути.

Шаг 1. Создание нового проекта

В командной строке перейдите в новый каталог для своих проектов, используйте Pipenv для установки Django, активируйте виртуальную среду и создайте новый проект с именем new_project. Давайте предположим, что мы хотим использовать папку code в Desktop, так пример на Mac.


$ cd ~/Desktop
$ mkdir code && cd code
$ pipenv install django
$ pipenv shell
(code) $ django-admin startproject new_project .

Теперь нам нужно создать приложение пользователя, а затем обновить 4 файла. Готовы?

Шаг 2. Создание приложения пользователя


(code) $ python manage.py startapp users

Теперь давайте расскажем Django о новом приложении и обновим AUTH_USER_MODEL, чтобы Django знал, что нужно использовать нашу новую модель CustomUser вместо модели User по умолчанию.

Откройте new_project/settings.py в текстовом редакторе и внесите следующие два изменения:


# new_project/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # Local
    'users.apps.UsersConfig', # новое
]
...
AUTH_USER_MODEL = 'users.CustomUser' # новое

Шаг 3. Модель CustomUser

Мы хотим расширить (или скопировать) существующую модель User и назвать ее как-то иначе, в нашем случае CustomUser. Это все, что нам нужно сделать. Просто сделайте копию, и тогда мы сможем настроить ее так, как нам нравится, но при этом использовать все преимущества встроенного User.

Нам даже не нужно добавлять поле на этом этапе!


# users/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models

class CustomUser(AbstractUser):
    pass
    # add additional fields in here

Шаг 4: Обновление форм

Django использует модель User — теперь нашу модель CustomUser, поскольку мы указали ее в AUTH_USER_MODEL повсюду. Два основных места — это когда создается новый пользователь и когда мы что-то меняем у пользователя. Поэтому мы должны снова расширить встроенные формы для этого и указать их для нашей новой модели CustomUser.

Создайте новый файл users/forms.py и заполните его следующим текстом:


# users/forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import CustomUser

class CustomUserCreationForm(UserCreationForm):

    class Meta(UserCreationForm):
        model = CustomUser
        fields = ('username', 'email')

class CustomUserChangeForm(UserChangeForm):

    class Meta:
        model = CustomUser
        fields = ('username', 'email')

Шаг 5: Обновление admin.py

Модель Django User тесно связана с превосходным встроенным приложением администратора admin, поэтому мы должны указать Django использовать вместо этого CustomUser. Вот как:


# users/admin.py
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin

from .forms import CustomUserCreationForm, CustomUserChangeForm
from .models import CustomUser

class CustomUserAdmin(UserAdmin):
    add_form = CustomUserCreationForm
    form = CustomUserChangeForm
    model = CustomUser
    list_display = ['email', 'username',]

admin.site.register(CustomUser, CustomUserAdmin)

Всё!!!

И это все. Создайте файл миграции для наших изменений, а затем впервые запустите миграцию, чтобы инициализировать нашу базу данных с помощью CustomUser вместо User.


(code) $ python manage.py makemigrations users
(code) $ python manage.py migrate

Поздравляем! Ваш проект Django рассчитан на будущее и вы можете продолжить работу без проблем.

Перевод статьи https://wsvincent.com/django-tips-custom-user-model/

Поделитесь с другими:


Расширение модели пользователя с помощью пользовательских полей в Django

Как лучше всего расширить модель пользователя (в комплекте с приложением аутентификации Django) с помощью пользовательских полей? Я также, возможно, хотел бы использовать email в качестве имени пользователя (для целей аутентификации).

Я уже видел несколько способов сделать это, но не могу решить, какой из них лучше.

django

django-models

django-authentication

django-users

Поделиться

Источник


Farinha    

04 сентября 2008 в 16:19

12 ответов




269

Наименее болезненный и действительно Django-рекомендуемый способ сделать это-через свойство OneToOneField(User) .

Если вы хотите сохранить информацию, связанную с User, вы можете использовать отношение one-to-one к модели, содержащей поля для получения дополнительной информации. Эта модель one-to-one часто называется моделью профиля, так как она может хранить не связанную с аутентификацией информацию о пользователе сайта.

Тем не менее, расширение django.contrib.auth.models.User и его замена также работают…

Некоторые виды проектов могут иметь требования к аутентификации, для которых встроенная модель Django User не всегда подходит. Например, на некоторых сайтах имеет смысл использовать адрес email в качестве идентификационного маркера вместо имени пользователя.

[Эд: следуют два предупреждения и уведомление, в котором упоминается, что это довольно радикально .]

Я бы определенно держался подальше от изменения фактического класса пользователя в вашем исходном дереве Django и/или копирования и изменения модуля auth.

Поделиться


Ryan Duffield    

04 сентября 2008 в 17:02



232

Примечание: этот ответ устарел. см.Другие ответы, если вы используете Django 1.7 или более позднюю версию.

Вот как я это делаю.

#in models.py
from django.contrib.auth.models import User
from django.db.models.signals import post_save

class UserProfile(models.Model):  
    user = models.OneToOneField(User)  
    #other fields here

    def __str__(self):  
          return "%s's profile" % self.user  

def create_user_profile(sender, instance, created, **kwargs):  
    if created:  
       profile, created = UserProfile.objects.get_or_create(user=instance)  

post_save.connect(create_user_profile, sender=User) 

#in settings.py
AUTH_PROFILE_MODULE = 'YOURAPP.UserProfile'

Это приведет к созданию профиля пользователя при каждом сохранении пользователя, если он будет создан.
Затем вы можете использовать

  user.get_profile().whatever

Вот еще несколько сведений из документов

http://docs.djangoproject.com/en/dev/темы/auth/#storing-additional-information-about-users

Обновление: Обратите внимание, что AUTH_PROFILE_MODULE устарел с v1.5: https://docs.djangoproject.com/en/1.5/ref/settings/#auth-profile-module

Поделиться


Raisins    

08 июня 2009 в 16:53


  • Django: UserProfile с уникальным внешним ключом в Django Admin

    Я расширил модель пользователя Django, используя пользовательский профиль пользователя под названием UserExtension . Он связан с пользователем через уникальную связь ForeignKey, которая позволяет мне редактировать его в admin В встроенной форме! Я использую сигнал для создания нового профиля для…

  • Django пользовательские менеджеры для модели пользователя

    Как бы я расширил модель пользователя по умолчанию с помощью пользовательских менеджеров? В моем приложении есть много типов пользователей, которые будут определены с помощью встроенной модели групп. Таким образом, пользователь может быть клиентом, сотрудником и т. д. Было бы идеально иметь…



204

Что ж, с 2008 года прошло некоторое время, и пришло время для нового ответа. Начиная с Django 1.5 вы сможете создавать пользовательский класс пользователя. На самом деле, в то время, когда я пишу это, он уже слился с master, так что вы можете попробовать его.

Есть некоторая информация об этом в документах или, если вы хотите копнуть глубже, в этом коммите .

Все, что вам нужно сделать, это добавить AUTH_USER_MODEL в настройки с путем к пользовательскому классу пользователя, который расширяет либо AbstractBaseUser (более настраиваемая версия), либо AbstractUser (более или менее старый класс пользователя, который вы можете расширить).

Для людей, которым лень нажимать, вот пример кода (взят из docs ):

from django.db import models
from django.contrib.auth.models import (
    BaseUserManager, AbstractBaseUser
)


class MyUserManager(BaseUserManager):
    def create_user(self, email, date_of_birth, password=None):
        """
        Creates and saves a User with the given email, date of
        birth and password.
        """
        if not email:
            raise ValueError('Users must have an email address')

        user = self.model(
            email=MyUserManager.normalize_email(email),
            date_of_birth=date_of_birth,
        )

        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, username, date_of_birth, password):
        """
        Creates and saves a superuser with the given email, date of
        birth and password.
        """
        u = self.create_user(username,
                        password=password,
                        date_of_birth=date_of_birth
                    )
        u.is_admin = True
        u.save(using=self._db)
        return u


class MyUser(AbstractBaseUser):
    email = models.EmailField(
                        verbose_name='email address',
                        max_length=255,
                        unique=True,
                    )
    date_of_birth = models.DateField()
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)

    objects = MyUserManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['date_of_birth']

    def get_full_name(self):
        # The user is identified by their email address
        return self.email

    def get_short_name(self):
        # The user is identified by their email address
        return self.email

    def __unicode__(self):
        return self.email

    def has_perm(self, perm, obj=None):
        "Does the user have a specific permission?"
        # Simplest possible answer: Yes, always
        return True

    def has_module_perms(self, app_label):
        "Does the user have permissions to view the app `app_label`?"
        # Simplest possible answer: Yes, always
        return True

    @property
    def is_staff(self):
        "Is the user a member of staff?"
        # Simplest possible answer: All admins are staff
        return self.is_admin

Поделиться


Ondrej Slinták    

28 сентября 2012 в 22:22




53

Начиная с Django 1.5 вы можете легко расширить модель пользователя и сохранить одну таблицу в базе данных.

from django.contrib.auth.models import AbstractUser
from django.db import models
from django.utils.translation import ugettext_lazy as _

class UserProfile(AbstractUser):
    age = models.PositiveIntegerField(_("age"))

Вы также должны настроить его как текущий класс пользователя в файле настроек

# supposing you put it in apps/profiles/models.py
AUTH_USER_MODEL = "profiles.UserProfile"

Если вы хотите добавить много предпочтений пользователей, вариант OneToOneField может быть лучшим выбором.

Примечание для людей, разрабатывающих сторонние библиотеки: если вам нужно получить доступ к пользовательскому классу, помните, что люди могут его изменить. Используйте официальный помощник, чтобы получить правильный класс

from django.contrib.auth import get_user_model

User = get_user_model()

Поделиться


Riccardo Galli    

20 апреля 2013 в 21:56


Поделиться


Dmitry Mukhin    

04 сентября 2008 в 16:35



23

Ниже приведен еще один подход к расширению пользователя.
Я чувствую,что это более ясно,легко, читаемо, чем выше двух подходов.

http://scottbarnham.com/blog/2008/08/21/extending-the-django-user-model-with-inheritance/

Использование вышеуказанного подхода:

  1. вам не нужно использовать
    user.get_profile().новый атрибут для доступа к дополнительной информации
    , относящейся к пользователю
  2. вы можете просто напрямую получить доступ
    к дополнительным новым атрибутам через
    user.newattribute

Поделиться


Rama Vadakattu    

01 апреля 2009 в 13:01



17

Вы можете просто расширить профиль пользователя, создавая новую запись каждый раз, когда пользователь создается с помощью сигналов Django post save

from django.db.models.signals import *
from __future__ import unicode_literals

class UserProfile(models.Model):

    user_name = models.OneToOneField(User, related_name='profile')
    city = models.CharField(max_length=100, null=True)

    def __unicode__(self):  # __str__
        return unicode(self.user_name)

def create_user_profile(sender, instance, created, **kwargs):
    if created:
        userProfile.objects.create(user_name=instance)

post_save.connect(create_user_profile, sender=User)

Это автоматически создаст экземпляр сотрудника при создании нового пользователя.

Если вы хотите расширить модель пользователя и хотите добавить дополнительную информацию при создании пользователя, вы можете использовать django-betterforms ( http://django-betterforms.readthedocs.io/en/latest/multiform.html ). Это создаст форму добавления пользователя со всеми полями, определенными в модели UserProfile.

from django.db.models.signals import *
from __future__ import unicode_literals

class UserProfile(models.Model):

    user_name = models.OneToOneField(User)
    city = models.CharField(max_length=100)

    def __unicode__(self):  # __str__
        return unicode(self.user_name)
from django import forms
from django.forms import ModelForm
from betterforms.multiform import MultiModelForm
from django.contrib.auth.forms import UserCreationForm
from .models import *

class ProfileForm(ModelForm):

    class Meta:
        model = Employee
        exclude = ('user_name',)


class addUserMultiForm(MultiModelForm):
    form_classes = {
        'user':UserCreationForm,
        'profile':ProfileForm,
    }
from django.shortcuts import redirect
from .models import *
from .forms import *
from django.views.generic import CreateView

class AddUser(CreateView):
    form_class = AddUserMultiForm
    template_name = "add-user.html"
    success_url = '/your-url-after-user-created'

    def form_valid(self, form):
        user = form['user'].save()
        profile = form['profile'].save(commit=False)
        profile.user_name = User.objects.get(username= user.username)
        profile.save()
        return redirect(self.add-user/$', AddUser.as_view(), name='add-user'),
]

Поделиться


Atul Yadav    

25 июня 2016 в 03:09




9

Расширение модели пользователя Django (UserProfile) как профессионал

Я нашел это очень полезным: ссылка

Выписка:

от django.contrib.auth.models пользователя импорта

class Employee(models.Model):
    user = models.OneToOneField(User)
    department = models.CharField(max_length=100)

>>> u = User.objects.get(username='fsmith')
>>> freds_department = u.employee.department

Поделиться


Massimo Variolo    

13 апреля 2016 в 08:09



3

Новое в Django 1.5, теперь вы можете создать свою собственную пользовательскую модель пользователя (что, по-видимому, хорошо в приведенном выше случае). См. раздел «Настройка аутентификации в Django».

Вероятно, самая крутая новая функция в выпуске 1.5.

Поделиться


chhantyal    

12 марта 2013 в 10:01



2

Это то, что я делаю, и, на мой взгляд, это самый простой способ сделать это. определите диспетчер объектов для новой настраиваемой модели, а затем определите свою модель.

from django.db import models
from django.contrib.auth.models import PermissionsMixin, AbstractBaseUser, BaseUserManager

class User_manager(BaseUserManager):
    def create_user(self, username, email, gender, nickname, password):
        email = self.normalize_email(email)
        user = self.model(username=username, email=email, gender=gender, nickname=nickname)
        user.set_password(password)
        user.save(using=self.db)
        return user

    def create_superuser(self, username, email, gender, password, nickname=None):
        user = self.create_user(username=username, email=email, gender=gender, nickname=nickname, password=password)
        user.is_superuser = True
        user.is_staff = True
        user.save()
        return user



  class User(PermissionsMixin, AbstractBaseUser):
    username = models.CharField(max_length=32, unique=True, )
    email = models.EmailField(max_length=32)
    gender_choices = [("M", "Male"), ("F", "Female"), ("O", "Others")]
    gender = models.CharField(choices=gender_choices, default="M", max_length=1)
    nickname = models.CharField(max_length=32, blank=True, null=True)

    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    REQUIRED_FIELDS = ["email", "gender"]
    USERNAME_FIELD = "username"
    objects = User_manager()

    def __str__(self):
        return self.username

Не забудьте добавить эту строку кода в свой settings.py :

AUTH_USER_MODEL = 'YourApp.User'

Это то, что я делаю, и это всегда работает.

Поделиться


Milad Khodabandehloo    

25 июля 2018 в 05:00



1

Простой и эффективный подход-это
models.py

from django.contrib.auth.models import User
class CustomUser(User):
     profile_pic = models.ImageField(upload_to='...')
     other_field = models.CharField()

Поделиться


NeerajSahani    

22 февраля 2020 в 18:36


Поделиться


David Torrey    

18 ноября 2019 в 19:18


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

Расширение модели django.contrib.auth.models.User с помощью пользовательских полей в Django

Я использую Django 1.8.2 с python 2.7.3, rest framework и allauth. Я пытаюсь расширить django.contrib.auth.models.User для добавления пользовательских полей, но возвращаемый json пуст, и есть…

добавление пользовательских полей пользователя с помощью 5NF+

Q-ищете примеры / учебник 5NF/или 6NF, pref для пользовательских полей пользователя, подробности ниже Проводя некоторые исследования по добавлению пользовательских полей пользователя, таких как in…

Расширение формы модели пользователя с помощью пользовательских полей

После регистрации я хотел бы запросить у пользователя: Полное имя (хотя я хочу сохранить его как имя и фамилию) Название компании Email Пароль Я прочитал десятки подобных ситуаций на StackOverflow….

Расширение модели пользователя с помощью пользовательских полей в Django

Я пытаюсь расширить пользовательскую модель, чтобы добавить свои собственные пользовательские поля, но постоянно получаю сообщение об ошибке: ‘NoneType’ объект не имеет атрибута ‘_default_manager’…

Расширение пользовательского объекта в Django: наследование модели пользователя или использование UserProfile?

Чтобы расширить пользовательский объект с помощью пользовательских полей, в документах Django рекомендуется использовать UserProfiles . Однако, согласно этому ответу на вопрос об этом примерно год…

Django: UserProfile с уникальным внешним ключом в Django Admin

Я расширил модель пользователя Django, используя пользовательский профиль пользователя под названием UserExtension . Он связан с пользователем через уникальную связь ForeignKey, которая позволяет…

Django пользовательские менеджеры для модели пользователя

Как бы я расширил модель пользователя по умолчанию с помощью пользовательских менеджеров? В моем приложении есть много типов пользователей, которые будут определены с помощью встроенной модели…

В Django расширение формы пользователя для пользовательского пользователя

Я расширил свою пользовательскую модель, как описано в этой публикации SO: Расширение модели пользователя с помощью пользовательских полей в Django Тем не менее, я пытаюсь создать форму создания…

Расширение модели пользователя в django

http://scottbarnham.com/blog/2008/08/21/extending-the-django-user-model-with-inheritance / Когда дело доходит до расширения модели пользователя, в приведенной выше статье перечислены два метода:…

Расширьте модель пользователя Django с помощью пользовательских полей, приемников и бэкенда

Я разрабатываю приложение Django (v1.6) и должен сделать несколько вещей с пользователями: Добавление пользовательских полей, таких как внешний ключ для отдела пользователей Запускает изменения базы…

Расширение модели auth.User, проксированных полей и Django admin

(Правка: я знаю, что в Django есть совершенно отдельная функция под названием «Proxy Models». Эта функция мне не помогает, потому что мне нужно иметь возможность добавлять поля в UserProfile.)

Итак, я запускаю новое приложение Django и создаю модель UserProfile, которая является расширением django.contrib.auth.models.User и неудачными запросами атрибутов обратно к пользователю, следующим образом:

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

class UserProfile(models.Model):
    user = models.OneToOneField(User, related_name='profile')

    def __getattr__(self, name, *args):
        if name == 'user' or name == '_user_cache':
            raise AttributeError(name)

        try:
            return getattr(self.user, name, *args)
        except AttributeError, e:
            raise AttributeError(name)

В целом это работает нормально, но ломается, когда я пытаюсь использовать поле User в UserProfileAdmin.list_display. Проблема заключается в коде проверки администратора здесь:

def validate(cls, model):
    """
    Does basic ModelAdmin option validation. Calls custom validation
    classmethod in the end if it is provided in cls. The signature of the
    custom validation classmethod should be: def validate(cls, model).
    """
    # Before we can introspect models, they need to be fully loaded so that
    # inter-relations are set up correctly. We force that here.
    models.get_apps()

    opts = model._meta
    validate_base(cls, model)

    # list_display
    if hasattr(cls, 'list_display'):
        check_isseq(cls, 'list_display', cls.list_display)
        for idx, field in enumerate(cls.list_display):
            if not callable(field):
                if not hasattr(cls, field):
                    if not hasattr(model, field):
                        try:
                            opts.get_field(field)
                        except models.FieldDoesNotExist:
                            raise ImproperlyConfigured("%s.list_display[%d], %r is not a callable or an attribute of %r or found in the model %r."
                                % (cls.__name__, idx, field, cls.__name__, model._meta.object_name))

Проблема в том, что в то время как экземпляр UserProfile будет иметь проксированные поля, например email, сам класс UserProfile этого не делает. Предназначалась в Django shell:

>>> hasattr(UserProfile, 'email')
False
>>> hasattr(UserProfile.objects.all()[0], 'email')
True

После некоторого копания, похоже, я хотел бы переопределить django.db.models.options.Options.get_field для UserProfile._meta. Но, похоже, нет никакого нехакового способа сделать это (прямо сейчас у меня есть очень Хак-решение, которое включает в себя обезьянье исправление UserProfile._meta.[get_field, get_field_by_name])…есть предложения? Спасибо.

python

django

django-models

django-admin

proxy-classes

Поделиться

Источник


rfrankel    

06 марта 2011 в 01:38

3 ответа


  • django admin сортировка списка полей внешнего ключа

    Есть ли опция в представлении django admin для упорядочения полей внешнего ключа? т. е. у меня есть внешний ключ к модели School, который отображается в виде выпадающего списка, отсортированного по pk-я бы хотел, чтобы он был отсортирован в алфавитном порядке.

  • Как использовать пользовательские поля формы для полей модели в Django admin?

    Я хочу, чтобы Django admin использовал пользовательское поле формы для ввода некоторых полей. До сих пор я делал пользовательское поле модели, к которому было привязано поле формы, которое отлично работает, но оно вводит ненужное поле модели, которое не добавляет никакой пользы. Я предполагаю, что…



2

Будь проще. Вот пример модели UserProfile из библиотеки, которую мы используем:

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    accountcode = models.PositiveIntegerField(null=True, blank=True)

Вот и все. Не беспокойтесь о переопределении __getattr__ . Вместо этого настройте интерфейс администратора:

from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User

class UserProfileInline(admin.StackedInline):
    model = UserProfile

class StaffAdmin(UserAdmin):
    inlines = [UserProfileInline]
    # provide further customisations here

admin.site.register(User, StaffAdmin)

Это позволяет вам CRUD объект User с доступом к UserProfile в качестве встроенного. Теперь вам не нужно прокси-поиск атрибутов из UserProfile в пользовательскую модель. Чтобы получить доступ к UserProfile из экземпляра User u , используйте u.get_profile()

Поделиться


Josh Smeaton    

06 марта 2011 в 05:45



0

Если вы просто хотите, чтобы поле от пользователя было в list_display в вашем UserProfileAdmin, попробуйте:

class UserProfileAdmin(admin.ModelAdmin):
    list_display = ('user__email',)

Если вы хотите, чтобы он был частью формы, добавьте его в UserProfileForm в качестве дополнительного поля и проверьте его в форме.

Поделиться


Matthew Schinckel    

06 марта 2011 в 05:14



0

Это не прокси-класс, это отношения. Подробнее о прокси-модели s, которые являются подклассом исходной модели, с Meta.proxy = True

Поделиться


Matthew Schinckel    

06 марта 2011 в 02:03


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

Django admin поиск и редактирование внешних полей

У меня есть вопрос из двух частей, касающийся Django Admin. Во-первых, у меня есть модель Django Classified , которая имеет поле внешнего ключа из другой таблицы Address . При настройке данных у…

Вложенные наборы полей на странице django admin

Пытаюсь понять Django Admin немного лучше, но сталкиваюсь с проблемой при размещении вложенных наборов полей в django admin Я хочу сгруппировать поля моей модели, как показано на рисунке ниже. Я…

расширение модели django admin

Представление по умолчанию для модели на странице django admin показывает список элементов в этом представлении, но дает только одно поле. Как можно показать несколько полей в списке?

django admin сортировка списка полей внешнего ключа

Есть ли опция в представлении django admin для упорядочения полей внешнего ключа? т. е. у меня есть внешний ключ к модели School, который отображается в виде выпадающего списка, отсортированного по…

Как использовать пользовательские поля формы для полей модели в Django admin?

Я хочу, чтобы Django admin использовал пользовательское поле формы для ввода некоторых полей. До сих пор я делал пользовательское поле модели, к которому было привязано поле формы, которое отлично…

django, где ‘auth.User-проходите мимо.

В каком-то проекте я обнаружил, что определение модели приложения выглядит следующим образом: from django.db import models class CustomUser(models.Model): user = models.ForeignKey(‘auth.User’) мой…

Django: ValueError: ошибка поиска модели, на которую ссылается поле account.UserProfile.user: auth.User

Получение этой ошибки при запуске python manage.py migrate : ValueError: не удалось выполнить поиск модели, на которую ссылается поле account.UserProfile.user: auth.User Шаги, которые я сделал: 1….

Описание модели в django-admin

Можно ли поместить описание модели или описание на страницу отображения списка определенной модели в django-admin? Я говорю о чем-то вроде того, когда вы нажимаете ссылку на название модели на…

Отражение/поиск в модели Django не находит интернационализированных (теневых) полей

Я использую CMS, который выполняет отображение моих моделей через API во время выполнения. Это работает прекрасно, за исключением локализованных полей, потому что я использую…

Есть ли виджет django admin, который позволяет администратору сортировать объекты модели по значениям полей?

Я создаю приложение в Django. Я обнаружил, что существует очень простой способ интегрировать виджет в django admin, который позволяет администратору фильтровать объекты модели по значениям полей….

Расширяем модель User в Django – apirobot

Для работы с пользователями, Django предоставляет готовую модель User. Часто, одной этой модели недостаточно. Приходится ее расширять, либо переписывать, если не устраивает стандартная реализация.

Несколько причин, почему может не устраивать стандартная реализация:

  1. Вам нужно вместо двух полей first_name и last_name, одно поле full_name.
  2. Не устраивает то, что поле email – необязательно (blank=True).
  3. Не устраивает то, что USERNAME_FIELD = ‘username’USERNAME_FIELD указывает на поле, которое является уникальным идентификатором для пользователя. Кроме того, это поле используется на странице с авторизацией. Получается, что по умолчанию, пользователь вводит username и password. Если вам нужна авторизация через email, то USERNAME_FIELD нужно переопределить на ‘email’.

Рекомендую посмотреть исходный код модели User здесь. Так будет проще понять, о чем я говорю.

В этом уроке поговорим о двух методах расширения модели User:

(1) Создание модели User, которая наследуется либо от AbstractUser, либо от AbstractBaseUser.

Класс AbstractUser, по функционалу, является той самой моделью User, которую вы получаете от Django из коробки. Если вас устраивает стандартная реализация, но нужно ее расширить, то наследуйтесь от AbstractUser. Если нет, то наследуйтесь от AbstractBaseUser и переопределяйте поля сами.

(2) Создание двух моделей: User и Profile, которые связаны друг с другом отношением один-к-одному (OneToOneField).

Зачем создавать две модели? Дело в том, что в программировании есть концепция Single Responsibility Principle (Принцип единственной обязанности).

«На каждый объект должна быть возложена одна единственная обязанность»

Single Responsibility Principle

Другими словами, класс и метод должны делать только одну вещь. Не нужно создавать так называемый God Object, который делает все, что только можно. Не нужно создавать метод, в котором реализована и валидация, и сохранение объекта в файл, и отправка сообщения пользователю… Для каждого метода должна существовать только одна причина его изменения. Если в методе вы хотите изменить как происходит валидация, то это одна причина изменения. Если хотите изменить реализацию отправки сообщения пользователю, то это другая причина. Когда причин больше чем одна, это значит, что метод делает слишком много.

Итак, следуя принципу единственной обязанности, мы создаем:

  1. Модель User, которая отвечает только за аутентификацию и авторизацию пользователя в системе.
  2. Модель Profile, которая хранит всевозможную информацию о пользователе для отображения на странице.

User, наследуемый от AbstractUser

Это самый простой способ, т.к. класс AbstractUser уже предоставляет все, что нужно.

Cоздаем приложение:

$ django-admin startapp users

Создаем модель:

# users/models.py

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


class User(AbstractUser):
    bio = models.CharField(max_length=160, null=True, blank=True)
    birthday = models.DateField(null=True, blank=True)

    def __str__(self):
        return self.username

Добавляем путь к модели User в настройках проекта, чтобы Django использовал нашу модель вместо стандартной:

# settings.py

AUTH_USER_MODEL = 'users.User'

User, наследуемый от AbstractBaseUser

Cоздаем приложение:

$ django-admin startapp users

Создаем модель:

# users/models.py

from django.core.mail import send_mail
from django.contrib.auth.base_user import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.validators import UnicodeUsernameValidator
from django.db import models
from django.utils.translation import ugettext_lazy as _


class User(AbstractBaseUser, PermissionsMixin):
    username_validator = UnicodeUsernameValidator()

    username = models.CharField(
        max_length=150,
        unique=True,
        validators=[username_validator],
    )
    email = models.EmailField(unique=True)
    full_name = models.CharField(max_length=255)
    bio = models.CharField(
        max_length=160,
        null=True,
        blank=True
    )
    birthday = models.DateField(
        null=True,
        blank=True
    )
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username', 'full_name']

    objects = UserManager()

    def __str__(self):
        return self.email

    def get_short_name(self):
        return self.email

    def get_full_name(self):
        return self.full_name

    def email_user(self, subject, message, from_email=None, **kwargs):
        send_mail(subject, message, from_email, [self.email], **kwargs)
  • USERNAME_FIELD – уникальный идентификатор пользователя. Это поле, вместе с паролем, используется при авторизации.
  • REQUIRED_FIELDS – список полей, которые потребуется ввести при создании пользователя через команду createsuperuser. Также этот список нередко используется сторонними библиотеками, при создании формы с регистрацией. Нормальная форма с регистрацией включает в себя: USERNAME_FIELDREQUIRED_FIELDS и password.
  • is_active – активен ли пользователь или нет. Когда пользователь пытается удалить аккаунт, мы присваиваем полю is_active=false. Аккаунт из базы данных не удаляется. Это делается ради сохранения информации об активности пользователя.
  • is_staff – имеет ли пользователь доступ к панели администратора или нет.

Создаем свой UserManger и переопределяем методы, которые отвечают за создание пользователя:

# users/models.py

from django.contrib.auth.base_user import BaseUserManager


class UserManager(BaseUserManager):
    use_in_migrations = True

    def _create_user(self, email, username, full_name, password, **extra_fields):
        """
        Create and save a user with the given username, email,
        full_name, and password.
        """
        if not email:
            raise ValueError('The given email must be set')
        if not username:
            raise ValueError('The given username must be set')
        if not full_name:
            raise ValueError('The given full name must be set')
        email = self.normalize_email(email)
        username = self.model.normalize_username(username)
        user = self.model(
            email=email, username=username, full_name=full_name,
            **extra_fields
        )
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_user(self, email, username, full_name, password=None, **extra_fields):
        extra_fields.setdefault('is_staff', False)
        extra_fields.setdefault('is_superuser', False)
        return self._create_user(
            email, username, full_name, password, **extra_fields
        )

    def create_superuser(self, email, username, full_name, password, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError('Superuser must have is_staff=True.')
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')

        return self._create_user(
            email, username, full_name, password, **extra_fields
        )

Добавляем путь к модели User в настройках проекта, чтобы Django использовал нашу модель вместо стандартной:

# settings.py

AUTH_USER_MODEL = 'users.User'

User и Profile со связью один-к-одному

Cоздаем приложение:

$ django-admin startapp profiles

Модель User переопределять не будем. Возьмем ту, что предоставляет Django из коробки. Создадим модель Profile:

# profiles/models.py

from django.conf import settings
from django.db import models


class Profile(models.Model):
    user = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE
    )
    bio = models.CharField(
        max_length=160,
        null=True,
        blank=True
    )
    birthday = models.DateField(
        null=True,
        blank=True
    )

    def __str__(self):
        return self.user.username

Осталось решить две проблемы:

  1. После создания пользователя, не создается новый Profile, прикрепленный к этому пользователю.
  2. После вызова метода save у пользователя, не вызывается метод save у прикрепленного к нему профиля. Из-за этого приходится каждый раз вызывать метод save после изменения профиля:
>>> user.username = 'apirobot'
>>> user.profile.bio = 'Something about me'
>>> user.profile.save()
>>> user.save()

Signals to the rescue! Сигналы позволяют определённым отправителям (senders) уведомлять некоторый набор получателей (receivers) о совершении действий. Используем встроенный в Django сигнал post_save, который отсылается после завершения работы метода save:

# profiles/signals.py

from django.contrib.auth import get_user_model
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Profile

User = get_user_model()


@receiver(post_save, sender=User)
def create_or_update_user_profile(sender, instance, created, **kwargs):
    if created:
        instance.profile = Profile.objects.create(user=instance)
    instance.profile.save()

Не забудьте подключить сигналы в методе ready конфигурационного класса:

# profiles/apps.py

from django.apps import AppConfig


class ProfilesConfig(AppConfig):
    name = 'profiles'

    def ready(self):
        import profiles.signals

Тестируем профиль через shell:

>>> from django.contrib.auth import get_user_model
>>> User = get_user_model()

>>> User.objects.create_user(username='apirobot', password='password')
<User: apirobot>
>>> user = User.objects.first()
>>> user.profile
<Profile: apirobot>
>>> user.profile.bio = 'Something about me'
>>> user.save()
>>> User.objects.first().profile.bio
'Something about me'

Напоследок хотелось бы сказать, что не стоит забывать про оптимизацию запросов к базе данных. По умолчанию, Django ORM не включает в результат связанные объекты. Поэтому, при каждом обращении к пользователю через профиль, делается новый запрос к базе данных:

# Запрос к базе данных
profile = Profile.objects.get(id=1)

# Снова запрос к базе данных для получения объекта User
user = profile.user

Это может стать проблемой, когда вы получаете список всех профилей и отображаете в html шаблоне данные профиля и связанного с ним пользователя:

# profiles/views.py

from django.views import generic
from .models import Profile


class ProfileListView(generic.ListView):
    model = Profile
<!-- profiles/templates/profiles/profile_list.html -->


{% for profile in profile_list %}
  {{ profile.user.username }} {# Делает запрос к базе данных для каждого профиля #}
  {{ profile.bio }}
{% endfor %}

Такая проблема решается с помощью метода select_related, который добавляет к результату запроса связанный объект:

# Запрос к базе данных
profile = Profile.objects.select_related('user').get(id=1)

# Не делает запрос к базе данных, т.к. `profile.user`
# был получен в предыдущем запросе
user = profile.user

Исправляем представление из предыдущего примера:

# profiles/views.py

class ProfileListView(generic.ListView):
    queryset = Profile.objects.select_related('user')

Заключение

В этом уроке мы поговорили о методах расширения модели User. Если вы не определились с выбором между User + Profile или просто User, то следуйте своему сердцу. После просмотра исходного кода проектов на GitHub, я понял, что каждый делает так, как хочет. В одних проектах всё пихают в модель User, в других используют User + Profile.

Имеет смысл создавать модель Profile, когда в моделе User много кода или когда вы хотите, чтобы модель User отвечала только за аутентификацию и авторизацию пользователя. Если же ваша модель User небольшая и вы не хотите париться по поводу создания сигналов и оптимизации запросов, то Profile вам не нужен.

python — Расширение модели пользователя Django и добавление в список администраторов

Я пытаюсь расширить свою модель пользователя с помощью профиля, а затем добавить новые поля профиля в отображение списка пользователей, чтобы он был доступен для поиска. Все работает до тех пор, пока не добавится в список администратора.

Я продолжаю получать эту ошибку 'User' object has no attribute 'MyProfile'

Models.py

from django.db import models

# Create your models here.
from django.contrib.auth.models import User
from django.utils.translation import ugettext as _
from userena.models import UserenaBaseProfile

class MyProfile(UserenaBaseProfile):
    user = models.OneToOneField(User,
                                unique=True,
                                verbose_name=_('user'),
                                related_name='my_profile')
    dealer_num = models.CharField(blank=True,
                                max_length=15,
                                verbose_name="Dealer Number")

Admin.py

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User

from .models import MyProfile

class ProfileInline(admin.StackedInline):
    model = MyProfile
    can_delete = False
    verbose_name_plural = 'Profile'
    fk_name = 'user'
    fields = ('user', 'dealer_num')

class UserAdmin(UserAdmin):
    inlines = (ProfileInline, )
    list_display = ('username', 'get_dealer_num')


    def get_inline_instances(self, request, obj=None):
        if not obj:
            return list()
        return super(UserAdmin, self).get_inline_instances(request, obj)
    def get_dealer_num(self, obj):
        return obj.MyProfile.dealer_num


admin.site.unregister(User)
admin.site.register(User, UserAdmin)

0

Chris Wendel

7 Мар 2019 в 23:41

1 ответ

Лучший ответ

Попробуй это:

def get_dealer_num(self, obj):
        return MyProfile.objects.get(user=obj).dealer_num

0

webbyfox
7 Мар 2019 в 21:13

Расширение модели User с помощью настраиваемых полей в Django

Вы можете просто расширить профиль пользователя, создавая новую запись каждый раз, когда пользователь создается с помощью сигналов сохранения сообщений Django.

  из импорта django.db.models.signals *
from __future__ импортировать unicode_literals

класс UserProfile (models.Model):

    user_name = models.OneToOneField (Пользователь, related_name = 'profile')
    city ​​= models.CharField (max_length = 100, null = True)

    def __unicode __ (сам): # __str__
        вернуть unicode (self.имя пользователя)

def create_user_profile (отправитель, экземпляр, создано, ** kwargs):
    если создано:
        userProfile.objects.create (имя_пользователя = экземпляр)

post_save.connect (create_user_profile, sender = Пользователь)
  

Это автоматически создаст экземпляр сотрудника при создании нового пользователя.

Если вы хотите расширить модель пользователя и хотите добавить дополнительную информацию при создании пользователя, вы можете использовать django-betterforms (http://django-betterforms.readthedocs.io/en/latest/multiform.html).Это создаст форму добавления пользователя со всеми полями, определенными в модели UserProfile.

  из импорта django.db.models.signals *
from __future__ импортировать unicode_literals

класс UserProfile (models.Model):

    user_name = models.OneToOneField (Пользователь)
    city ​​= models.CharField (max_length = 100)

    def __unicode __ (сам): # __str__
        вернуть unicode (self.user_name)
  
  из форм импорта django
из django.forms импортировать ModelForm
из betterforms.multiform import MultiModelForm
из джанго.contrib.auth.forms импорт UserCreationForm
из .models import *

класс ProfileForm (ModelForm):

    класс Мета:
        model = Сотрудник
        exclude = ('имя_пользователя',)


класс addUserMultiForm (MultiModelForm):
    form_classes = {
        'пользователь': UserCreationForm,
        "профиль": ProfileForm,
    }
  
  из перенаправления импорта django.shortcuts
из .models import *
из .forms import *
из django.views.generic import CreateView

класс AddUser (CreateView):
    form_class = AddUserMultiForm
    template_name = "добавить пользователя.html "
    success_url = '/ ваш-url-после-созданный пользователем'

    def form_valid (self, form):
        user = form ['пользователь']. save ()
        profile = form ['profile']. save (commit = False).
        profile.user_name = User.objects.get (имя пользователя = user.username)
        profile.save ()
        возврат перенаправления (self.success_url)
  
  

    
        
         Заголовок 
    
    
        
python - Как добавить новые поля в модель пользователя django

Есть несколько способов сделать это. Вы можете прочитать обо всех из них в официальной документации. Здесь.

Вы можете либо расширить модель пользователя, создав AbstractUser, либо создать свою собственную модель под названием «Профиль» (например), которая связана с экземпляром пользователя следующим образом:

  models.py
Профиль класса (models.Model):
   user = models.OneToOneField (Пользователь, on_delete = models.КАСКАД)
   phonenumber = models.CharField (verbose_name = "номер телефона", max_lenght = 10)
   Birthdate = models.DateField (verbose_name = "дата рождения")
  

, затем вы создаете формы, которые человек будет заполнять во время регистрации. Это будет форма модели пользователя и форма вашего пользовательского профиля.

  forms.py
класс UserForm (UserCreationForm):
    email = forms.EmailField ()

    класс Мета:
        model = Пользователь
        fields = ['username', 'first_name', 'email', 'password1', 'password2']


класс ProfileForm (forms.ModelForm):

    класс Мета:
        model = Профиль
        fields = ['дата рождения', 'номер телефона']
        widgets = {
            'Birthdate': DateInput (attrs = {'type': 'date'}),
        }
  

, то вам нужно сохранить данные обеих форм в экземпляре пользователя, когда он завершит регистрацию. Я использую этот метод:

  views.py
def регистр (запрос):
    если request.method == "POST":
        u_form = UserForm (request.POST)
        p_form = ProfileForm (request.POST)
        если u_form.is_valid () и p_form.is_valid ():
            пользователь = u_form.save ()
            p_form = p_form.save (фиксация = ложь)
            p_form.user = пользователь
            p_form.save ()
            messages.success (request, f'Регистрация завершена! Вы можете авторизоваться! ')
            возврат перенаправления ('логин')
    еще:
        u_form = UserForm (request.POST)
        p_form = ProfileForm (request.POST)
    вернуть рендеринг (запрос, 'users / register.html', {'u_form': u_form, 'p_form': p_form})
  

Итак, когда человек переходит на страницу регистрации, он / она видит 2 формы, форму пользователя и форму профиля, и ему необходимо заполнить их, чтобы пройти регистрацию.При нажатии кнопки отправки (отправка запроса) просмотр проверяет правильность всех данных и создает профиль пользователя со стандартными полями и настраиваемый экземпляр профиля с необходимыми дополнительными полями, которые связаны с этим пользователем и к которым можно получить доступ (например, User.profile.birthdate).

Надеюсь, что это поможет.

python - Django - расширить модель пользователя с помощью профиля, но также и другого типа пользователя

Я хочу расширить модель пользователя в Django (2.2) и объединить ее с сущностями Host и Guest, которые также имеют определенные поля.

В официальной документации рекомендуется создать класс «Профиль» с полем OneToOne, которое ссылается на первичный ключ пользователя.

Я вижу 3 способа сделать это:

Решение 1. Профиль, модель хоста и гостя:

 Профиль класса  (models.Model):
    k_user = models.OneToOneField (Пользователь, on_delete = models.CASCADE)
    language = models.CharField (max_length = 2)

класс Host (models.Model):
    k_user = models.OneToOneField (Пользователь, on_delete = models.КАСКАД)
    host_field = models.CharField (max_length = 500)

класс Гость (models.Model):
    k_user = models.OneToOneField (Пользователь, on_delete = models.CASCADE)
    guest_field = models.BooleanField (null = Ложь)
  

Решение 2. Модель хоста и гостя (с дублированными полями профиля)

  класс Host (models.Model):
    k_user = models.OneToOneField (Пользователь, on_delete = models.CASCADE)
    language = models.CharField (max_length = 2)
    host_field = models.CharField (max_length = 500)

класс Гость (models.Модель):
    k_user = models.OneToOneField (Пользователь, on_delete = models.CASCADE)
    language = models.CharField (max_length = 2)
    guest_field = models.BooleanField (null = Ложь)
  

Решение 3. Модель профиля (содержащая поля гостя и хоста)

 Профиль класса  (models.Model):
    k_user = models.OneToOneField (Пользователь, on_delete = models.CASCADE)
    language = models.CharField (max_length = 2)
    is_host = models.BooleanField (null = Ложь)
    guest_field = модели.BooleanField (null = ложь)
    host_field = models.CharField (max_length = 500)
  

Все эти решения работают.

Мой вопрос: «Какой из них самый умный с учетом всех обстоятельств» (меньше доступа к базе данных, меньше кода для написания, проще в обслуживании, меньше ограничений и т. Д.)

Что мне делать: расширить базовую модель пользователя django или создать собственную модель пользователя?

Как рекомендует Django

Если вы начинаете новый проект, настоятельно рекомендуется настроить пользовательскую модель пользователя, даже если вам достаточно модели пользователя по умолчанию.

  из django.contrib.auth.models import AbstractUser

класс User (AbstractUser):
    проходить
  

по моему опыту, лучше переопределить и его, но я делаю это путем переопределения AbstractBaseUser с помощью менеджера клиентов, поэтому я делаю то, что хочу!

Менеджер

  из django.contrib.auth.base_user импорт BaseUserManager


класс UserManager (BaseUserManager):
    use_in_migrations = Верно

    def _create_user (собственное имя, имя пользователя, пароль, ** дополнительные поля):
        если не имя пользователя:
            Raise ValueError ('Необходимо указать данное имя пользователя')
        имя пользователя = себя.model.normalize_username (имя пользователя)
        user = self.model (имя пользователя = имя пользователя, ** дополнительные_поля)
        если пароль None:
            пароль = self.make_random_password ()
        user.set_password (пароль)
        user.save ()
        возвратный пользователь

    def create_user (self, username, password = None, ** extra_fields):
        extra_fields.setdefault ('is_staff'; ложь)
        extra_fields.setdefault ('is_superuser'; ложь)
        вернуть self._create_user (имя пользователя = имя пользователя, пароль = пароль, ** дополнительные_поля)

    def create_staff (self, имя пользователя, пароль = None, ** extra_fields):
        extra_fields.setdefault ('is_staff', Истина)
        extra_fields.setdefault ('is_superuser'; ложь)
        вернуть self._create_user (имя пользователя = имя пользователя, пароль = пароль, ** дополнительные_поля)

    def create_superuser (собственное имя, имя пользователя, пароль, ** дополнительные_поля):
        extra_fields.setdefault ('is_staff', Истина)
        extra_fields.setdefault ('is_superuser', Истина)

        если extra_fields.get ('is_staff') не True:
            поднять ValueError ('Суперпользователь должен иметь is_staff = True.')
        если extra_fields.get ('is_superuser') не True:
            Raise ValueError ('Суперпользователь должен иметь is_superuser = True.')

        вернуть self._create_user (имя пользователя = имя пользователя, пароль = пароль, ** дополнительные_поля)
  

Модель пользователя

  из django.contrib.auth.base_user import AbstractBaseUser
из django.contrib.auth.models импорт PermissionsMixin
из django.contrib.auth.validators импортировать ASCIIUsernameValidator
из django.core.mail импорт send_mail
из моделей импорта django.db

из account.managers импортировать UserManager


класс User (AbstractBaseUser, PermissionsMixin):
    имя пользователя = модели.CharField (max_length = 150, unique = True,
                                help_text = 'Обязательно. 150 символов или меньше. Только буквы, цифры и @ /. / + / - / _. ',
                                валидаторы = [ascii_username_validator],
                                error_messages = {'unique': "Пользователь с таким именем пользователя уже существует."})
    first_name = models.CharField (max_length = 30, null = True, blank = True)
    last_name = models.CharField (max_length = 150, null = True, blank = True)
    is_staff = models.BooleanField ('статус персонала', по умолчанию = False)
    is_active = модели.BooleanField ('активно', по умолчанию = True)
    created_at = models.DateTimeField (auto_now_add = True)
    updated_at = models.DateTimeField (auto_now = True)

    objects = UserManager ()

    EMAIL_FIELD = 'электронная почта'
    USERNAME_FIELD = 'имя пользователя'
    REQUIRED_FIELDS = []

    def get_full_name (сам):
        вернуть '{} {}'. format (self.first_name, self.last_name) .strip ()

    def email_user (сам, тема, сообщение, from_email = None, ** kwargs):
        send_mail (тема, сообщение, from_email, [self.email], ** kwargs)

    def __str __ (сам):
        return str (self.имя пользователя)
  

, а затем в настройках вы должны установить AUTH_USER_MODEL :

  AUTH_USER_MODEL = 'accounts.User'
  

также, проверьте эти ссылки:

Как расширить модель пользователя в Django

В предыдущем посте я обсуждал, как создать пользовательскую модель пользователя в Django, но что делать, если вы не хотите создавать пользовательскую модель.

В этом случае вы можете просто расширить модель пользователя с помощью отношения модели OneToOne.

  • Мы можем легко добавить еще одно поле, такое как «Местоположение», «Дата рождения» и т. Д.

Создать проект Django

Настройте виртуальную среду и создайте проект Django.

Примечание - код настройки доступен в предыдущем посте.

Расширение модели пользователя

Импортируйте модель пользователя из "django.contrib.auth.models", и мы создадим другую модель, которая будет относиться к этой модели пользователя

  из django.модели импорта БД
из django.contrib.auth.models импортировать пользователя
из модели импорта django.db.models.base
из django.db.models.deletion импортировать КАСКАД
# Создайте свои модели здесь.
класс ExtendUser (models.Model):
    r = models.OneToOneField (Пользователь, on_delete = models.CASCADE)
    date_of_birth = models.DateField (null = Истина)
    city ​​= models.CharField (max_length = 30)
    def __str __ (сам):
        вернуть self.r.username
  

Войти в полноэкранный режимВыйти из полноэкранного режима

Добавьте эту модель в админку.py

Отображение данных

Теперь вопрос в том, как мы можем получить доступ к этим данным и показать их во внешнем интерфейсе.

Это просто ..

В файле views.py я создал единственную функцию, которая будет отправлять данные в виде контекста.

  def home (запрос):
    data = request.user
    вернуть рендеринг (запрос, 'core / index.html', {'data': data})
  

Войти в полноэкранный режимВыйти из полноэкранного режима

Теперь в index.html вы можете получить доступ к этим данным

  

{{данные.имя пользователя}}

{{data.extenduser.city}}

{{data.extenduser.date_of_birth}}

Войти в полноэкранный режимВыйти из полноэкранного режима

Минусы

  • С помощью этого метода вы не можете изменить основной метод входа в систему, который является именем пользователя.

Вот репозиторий GitHub для кода

Как расширить модель пользователя в Django

Рекомендации по Django: пользовательская модель

  • Уилл Винсент

  • 7 декабря 2020 г.

Django поставляется со встроенной моделью User для аутентификации, и если вы хотите получить базовое руководство о том, как реализовать вход, выход, регистрацию и т. Д., См. Руководство по входу и выходу Django для получения дополнительной информации.

Однако для реального проекта официальная документация Django настоятельно рекомендует использовать вместо пользовательскую модель пользователя. Это обеспечивает гораздо большую гибкость в дальнейшем, поэтому, как правило, всегда использует пользовательскую модель для всех новых проектов Django .

Но как его реализовать? Официальный пример документации - это не то, что рекомендуют использовать многие эксперты Django. Существует гораздо более простой, но все же эффективный подход к запуску новых проектов Django с пользовательской моделью, которую я продемонстрирую здесь.

Настройка

Для начала создайте новый проект Django из командной строки. Нам нужно сделать несколько вещей:

  • создать и перейти в специальный каталог под названием учетные записи для нашего кода
  • установить Django
  • создать новый проект Django под названием config
  • создать новое приложение аккаунтов
  • запустить локальный веб-сервер

Вот команды для запуска:

 $ cd ~ / Рабочий стол
Аккаунты $ mkdir и аккаунты cd
$ pipenv install django ~ = 3.1.0
оболочка $ pipenv
(учетные записи) $ django-admin.py startproject config.
(учетные записи) учетные записи $ python manage.py startapp
(учетные записи) $ python manage.py runserver
 

Обратите внимание, что мы не запускали migrate для настройки нашей базы данных. Перед тем, как сделать это, важно подождать, пока мы не создадим нашу новую пользовательскую модель.

Если вы перейдете на http://127.0.0.1:8000, вы увидите экран приветствия Django.

Сладкое. На данный момент остановите локальный сервер с помощью Control + c , потому что в противном случае он начнет выдавать множество ошибок, поскольку мы реализуем настраиваемую модель пользователя.

AbstractUser против AbstractBaseUser

Существует два современных способа создания пользовательской модели пользователя в Django: AbstractUser и AbstractBaseUser . В обоих случаях мы можем создать подклассы для расширения существующих функциональных возможностей, однако AbstractBaseUser требует гораздо больше работы. Серьезно, не связывайтесь с этим, если вы действительно не знаете, что делаете. А если бы вы это сделали, вы бы не стали читать этот учебник, не так ли?

Итак, мы будем использовать AbstractUser , который на самом деле является подклассом AbstractBaseUser , но обеспечивает большую конфигурацию по умолчанию.

Пользовательская модель пользователя

Для создания нашей первоначальной пользовательской модели требуется четыре шага:

  • обновление config / settings.py
  • создать новую модель CustomUser
  • создать новый UserCreation и UserChangeForm
  • обновите админку

В settings.py мы добавим приложение account и используем конфигурацию AUTH_USER_MODEL , чтобы сообщить Django использовать нашу новую пользовательскую модель вместо встроенной модели User .Мы будем называть нашу пользовательскую модель CustomUser .

В пределах INSTALLED_APPS добавьте учетных записей внизу. Затем в конце всего файла добавьте конфигурацию AUTH_USER_MODEL .

 # config / settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'accounts', # new
]
...
AUTH_USER_MODEL = 'accounts.CustomUser' # новое
 

Теперь обновите accounts / models.py , добавив новую модель User, которую мы назовем CustomUser .

 # accounts / models.py
из django.contrib.auth.models импортировать AbstractUser
из моделей импорта django.db

класс CustomUser (AbstractUser):
    проходить
    # добавьте сюда дополнительные поля

    def __str __ (сам):
        вернуть self.username
 

Нам нужны новые версии двух методов форм, которые будут активно использоваться при работе с пользователями.Остановите локальный сервер с помощью Control + c и создайте новый файл в приложении accounts с именем forms.py .

 (учетные записи) $ touch accounts / forms.py
 

Мы обновим его следующим кодом, чтобы в значительной степени создать подкласс существующих форм.

 # accounts / forms.py
из форм импорта django
из django.contrib.auth.forms импортировать UserCreationForm, UserChangeForm
из .models import CustomUser

класс CustomUserCreationForm (UserCreationForm):

    класс Мета:
        model = CustomUser
        fields = ('имя пользователя', 'электронная почта')

класс CustomUserChangeForm (UserChangeForm):

    класс Мета:
        model = CustomUser
        fields = ('имя пользователя', 'электронная почта')
 

Наконец-то обновляем admin.py , поскольку администратор сильно привязан к модели пользователя по умолчанию.

 # accounts / admin.py
от администратора импорта django.contrib
из django.contrib.auth.admin импортировать UserAdmin

из .forms import CustomUserCreationForm, CustomUserChangeForm
из .models import CustomUser

класс CustomUserAdmin (UserAdmin):
    add_form = CustomUserCreationForm
    form = CustomUserChangeForm
    model = CustomUser
    list_display = ['электронная почта', 'имя пользователя',]

admin.site.register (CustomUser, CustomUserAdmin)
 

И готово! Теперь мы можем запустить makemigrations и , перенести в первый раз, чтобы создать новую базу данных, которая использует пользовательскую модель пользователя.

 (учетные записи) $ python manage.py makemigrations accounts
(учетные записи) $ python manage.py migrate
 

Суперпользователь

Полезно создать суперпользователя, которого мы сможем использовать для входа в систему с правами администратора и проверки входа в систему / выхода из системы. В командной строке введите следующую команду и просмотрите подсказки.

 (учетные записи) $ python manage.py создает суперпользователя
 

Шаблоны / Просмотры / URL

Наша цель - создать домашнюю страницу со ссылками для входа, выхода и регистрации. Начните с обновления настроек .py для использования каталога шаблонов уровня проекта.

 # config / settings.py
ШАБЛОНЫ = [
    {
        ...
        'DIRS': [str (BASE_DIR.joinpath ('templates'))], # новое
        ...
    },
]
 

Затем установите ссылки перенаправления для входа и выхода, которые будут переходить в наш шаблон home . Добавьте эти две строки в конец файла.

 # config / settings.py
LOGIN_REDIRECT_URL = 'дом'
LOGOUT_REDIRECT_URL = 'дом'
 

Создайте новую папку шаблонов уровня проекта и внутри нее папку registration , поскольку именно там Django будет искать шаблон входа в систему.Мы также поместим туда наш шаблон signup.html .

 (аккаунты) шаблоны $ mkdir
(аккаунты) шаблоны $ mkdir / регистрация
 

Затем создайте четыре шаблона:

 (аккаунты) $ touch templates / registration / login.html
(аккаунты) $ touch templates / registration / signup.html
(аккаунты) $ touch templates / base.html
(аккаунты) $ touch templates / home.html
 

Обновите файлы следующим образом:

 



  
   {% block title%} Учебное пособие по аутентификации Django {% endblock%} 


  <основной>
    {% блокировать содержание%}
    {% endblock%}