There are various options for working with a user model for creating a user profile and adding some specific information, for example, a profile photo. One way is to add a profile model with the OneToOneField field for the user. This option is simpler than a proxy model or overriding a user model. But for me personally, redefinition of the user model turned out to be more effective in terms of organizing code and writing various methods that allow you to extract the necessary information from the user object in templates without resorting to writing template tags.
Therefore, let's consider exactly the option of redefining the user model in a project in Django
Introduction
As an introduction, I’ll draw your attention to the fact that redefining a user model is best done at the very beginning of the project, otherwise there may be problems with migrations that need to be fixed manually.
I myself did overriding the user model already when the site existed for more than two years. However, my redefinition process went relatively smoothly, at least I don’t remember that there were any problems with the fact that I redefined the user model.
User Model Override
In order to correctly redefine the user model, you need to import the abstract user model AbstractUser and inherit from it in the application where you will have the model.
In my application evileg_auth I did it this way
# -*- coding: utf-8 -*- from django.contrib.auth.models import AbstractUser class User(AbstractUser): pass
Next, you need to specify this model as the new user model in the settings file settings.py
AUTH_USER_MODEL = 'evileg_auth.User'
This is necessary so that a third-party application starts using your user model instead of the standard one.
Then you can create migrations and migrate the project
python manage.py makemigrations python manage.py migrate
Also do not forget to register your model in the admin panel
# -*- coding: utf-8 -*- from django.contrib import admin from django.contrib.auth.admin import UserAdmin from .models import User admin.site.register(User, UserAdmin)
Notes
If you are introducing an overridden user model into an existing project, I recommend that you follow these steps so that the overridden model is used everywhere in your project.
settings.AUTH_USER_MODEL
In all models.py files, use the settings.AUTH_USER_MODEL variable from the settings instead of the standard 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()
Everywhere in the code where it is assumed that the Django instance is already running, use the dynamic get of the user model class via get_user_model()
For example, I have such a 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)
Third Party Application
If you are writing a third-party application, then the recommendations from the notes section should be mandatory for you, because otherwise your third-party application will be useless for those developers who redefine custom models in their projects on Django
Benefits of Overriding a Custom Model
Redefining the user model has, in my opinion, great advantages compared to using OneToOneField, since it allows you to redefine the object manager without crutches, as well as add a number of methods that can be useful in your project. And also these methods can be called in templates without writing template tags.
Here is an example of a part of a user model in my project
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})
At a minimum, I always lacked the use of the standard method get_absolute_url for the user profile on the site.
Полезный урок, весьма лучше, чем создать профиль. А как всё это объединить в админке? admin.site.register(User, UserAdmin) - UserAdmin убрал мое созданное поле для абстрактного поля.
Я немного не понял, что именно вы хотите объединить? Вы хотите, чтобы группы и пользователи были в одном groupbox'e?
Или хотите видеть абстрактное поле? Если абстрактное поле, то наследуйтесь от UserAdmin и переопределите переменные fields и т.д., как если бы наследовались от ModelAdmin
Я уже нашел в вашем другом уроке как добавить поле аватар к пользователям. Именно то что вы написали) Спасяб:3
Да ещё бы хотелось чтоб группы и пользователи были в одной группе.
Насчёт такого никогда не заморачивался, мне это не мешало. Но вообще для этого можно использовать прокси модель.
Думаю, что это может выглядеть так
Суть в том, что проксируем стандартную модель Groups в другое приложение, чтобы они отображались в одном app
Благодарю!
Подскажите, эта серия уроков для django 2.0?
Я ещё не переходил на Django 3, поэтому на данный момент все примеры пишутся с использованием Django 2, наиболее старые с использованием Django 1.
Но в принципе, большая часть из статей должна работать и с Django 3. Хотя и не все.
Понял, большое спасибо! Буду ждать перехода на 3 версию :)
Я тоже его жду. Вернее жду, когда все разработчики третьесторонних библиотек добавят поддержку третьей версии.
Добрый день, Я вот написал в admin.py
admin.site.register(User, UserAdmin)
Но у меня не появилось новые поля в админке?
Если у вашего пользователя нет прав но чтение или изменение модели пользователя, то вы можете и не увидеть эту модель в админке. В этом случае лучше под суперпользователем проверять всё.
А как дать ему эти права?
В данном случае я заходил под superuser но все равно не появлялись эти поля
def initials(self):
return get_initials(self)
В последнем листинге что такое get_initials(self), пайчарм подчеркивает и предлагает создать функцию get_initials
Лишний кусок кода (Метод для получения инициалов), удалите его.