Evgenii Legotckoi
27 квітня 2020 р. 01:08

Django - Урок 052. Перевизначення моделі користувача

Є різні варіанти роботи з користувальницької моделлю для створення профілю користувача і додавання деякої специфічної інфоромаціі, наприклад, фото в профілі. Одним із способів є додавання моделі профілю з OneToOneField полем для користувача. Даний варіант є більш прості, ніж проксі моделі або перевизначення моделі користувача. Але особисто для мене перевизначення моделі користувача виявилося більш ефективним в плані організації коду і написанні різних методів, які дозволяє витягувати потрібну інформацію з об'єкта користувача в шаблонах не вдаючись до написання шаблонних тегів.

Тому давайте продовжимо розглядати саме варіант перевизначення моделі користувача в проекті на Django


Вступ

В якості введення зверну вашу увагу на те, що перевизначення користувальницької моделі краще робити на самому початку проекту, інакше можуть бути проблеми з міграціями, які потрібно буде виправляти вручну.

Сам же я робив перевизначення користувальницької моделі вже, коли сайт існував вже більше двох років. Однак у мене процес перевизначення пройшов відносно без проблем, принаймні я не пам'ятаю, щоб були якісь проблеми з тим, що я перевизначив модель користувача.

Перевизначення моделі користувача

Для того, щоб правильно перевизначити модель користувача необхідно в тому додатку, де у вас буде розташовуватися модель, імпортувати модель абстрактного користувача AbstractUser і успадковуватися від нього.

У своєму додатку evileg_auth я зробив це таким чином

# -*- coding: utf-8 -*-

from django.contrib.auth.models import AbstractUser


class User(AbstractUser):
    pass

Далі вам необхідно вказати цю модель в якості нової моделі користувача в файлі налаштувань settings.py

AUTH_USER_MODEL = 'evileg_auth.User'

Це необхідно для того, щоб третя сторонні додаток почали використовувати свій телевізор користувача замість стандартної.

Після чого можете створити міграції і мігрувати проект

python manage.py makemigrations
python manage.py migrate

Також не забудьте зареєструвати свою модель в адміністративній панелі

# -*- coding: utf-8 -*-

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

from .models import User

admin.site.register(User, UserAdmin)

Примітки

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

settings.AUTH_USER_MODEL

У всіх файлах models.py використовуйте замість стандартної моделі змінну settings.AUTH_USER_MODEL з налаштувань

# -*- coding: utf-8 -*-

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


class SomeModel(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='User')

get_user_model()

Скрізь в коді, де передбачається, що інстанси Django вже запущений, використовуйте динамічне отримання класу моделі користувача через get_user_model()

Наприклад, у мене є такий mixin

class EInUserProfileMixin:
    user_profile = None

    def dispatch(self, request, *args, **kwargs):
        self.user_profile = get_object_or_404(get_user_model(), username=kwargs['user'], is_active=True)
        return super().dispatch(request, *args, **kwargs)

Третьестороннее додаток

Якщо ви пишете третьестороннее додаток, то рекомендації з розділу примітки для вас повинні бути обов'язковими, оскільки в іншому випадку ваше третьестороннее додатки буде марним для тих розробників, які скасовують призначені для користувача моделі в своїх проектах на Django

Переваги перевизначення користувальницької моделі

Перевизначення користувальницької моделі має, на мій погляд, великі переваги в порівнянні з використанням OneToOneField, оскільки дозволяє без милиць перевизначити менеджер об'єктів, а також додати ряд методів, які можуть бути корисні в вашому проекті. А також ці методи можна буде викликати в шаблонах без написання шаблонних тегів.

Ось наприклад частина користувальницької моделі в моєму проекті

class User(AbstractUser):

    last_online = models.DateTimeField(blank=True, null=True)

    objects = UserManager()

    class Meta:
        ordering = ['username']

    def get_absolute_url(self):
        return reverse('users:profile', kwargs={'user': self.username})

Як мінімум мені завжди не вистачало використання стандартного методу get_absolute_url для профілю користувача на сайті.

Вам це подобається? Поділіться в соціальних мережах!

Владислав Меленчук
  • 27 квітня 2020 р. 17:43

Полезный урок, весьма лучше, чем создать профиль. А как всё это объединить в админке? admin.site.register(User, UserAdmin) - UserAdmin убрал мое созданное поле для абстрактного поля.

Я немного не понял, что именно вы хотите объединить? Вы хотите, чтобы группы и пользователи были в одном groupbox'e?
Или хотите видеть абстрактное поле? Если абстрактное поле, то наследуйтесь от UserAdmin и переопределите переменные fields и т.д., как если бы наследовались от ModelAdmin

Я уже нашел в вашем другом уроке как добавить поле аватар к пользователям. Именно то что вы написали) Спасяб:3
Да ещё бы хотелось чтоб группы и пользователи были в одной группе.

Да ещё бы хотелось чтоб группы и пользователи были в одной группе.

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

Думаю, что это может выглядеть так

class ProxyGroups(Groups):
    class Meta:
        proxy = True    
        # Если определить ProxyGroup внутри my_auth/models.py,
        # то его app_label будет установлен как 'my_auth' автоматически.
        # Или можно переопределить его так           
        # app_label = 'my_auth'

        # также можно установить некоторые параметры из существующего Group
        # verbose_name = Groups._meta.verbose_name
        # verbose_name_plural = Groups._meta.verbose_name_plural


# in admin.py
admin.site.register(ProxyGroups)

Суть в том, что проксируем стандартную модель Groups в другое приложение, чтобы они отображались в одном app

Благодарю!

Z M
  • 04 травня 2020 р. 15:56

Подскажите, эта серия уроков для django 2.0?

Evgenii Legotckoi
  • 04 травня 2020 р. 15:59
  • (відредаговано)

Я ещё не переходил на Django 3, поэтому на данный момент все примеры пишутся с использованием Django 2, наиболее старые с использованием Django 1.

Но в принципе, большая часть из статей должна работать и с Django 3. Хотя и не все.

Z M
  • 04 травня 2020 р. 16:02

Понял, большое спасибо! Буду ждать перехода на 3 версию :)

Evgenii Legotckoi
  • 04 травня 2020 р. 16:04

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

t
  • 23 січня 2021 р. 19:28

Добрый день, Я вот написал в admin.py
admin.site.register(User, UserAdmin)
Но у меня не появилось новые поля в админке?

Evgenii Legotckoi
  • 01 лютого 2021 р. 03:30

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

t
  • 23 лютого 2021 р. 18:11

А как дать ему эти права?

t
  • 24 лютого 2021 р. 13:56

В данном случае я заходил под superuser но все равно не появлялись эти поля

N
  • 19 квітня 2022 р. 13:22

def initials(self):
return get_initials(self)

В последнем листинге что такое get_initials(self), пайчарм подчеркивает и предлагает создать функцию get_initials

Evgenii Legotckoi
  • 19 квітня 2022 р. 13:58

Лишний кусок кода (Метод для получения инициалов), удалите его.

Коментарі

Only authorized users can post comments.
Please, Log in or Sign up