Custom column in Django users profile - python

I want to add custom column in Django admin, on Users (/auth/user/) section.
models.py
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
birthday = models.DateField()
def __str__(self):
return self.user.username
#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()
And in admin.py I have this code:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
class ProfileInline(admin.StackedInline):
model = Profile
can_delete = False
verbose_name_plural = 'Custom fields'
class CustomUser(UserAdmin):
inlines = (ProfileInline, )
list_diplsay = ('birthday')
def get_inline_instances(self, request, obj=None):
if not obj:
return list()
return super(CustomUser, self).get_inline_instances(request, obj)
admin.site.unregister(User)
admin.site.register(User, CustomUser)
I've read here that list_display should do all the work, but in my case it doesn't work. I don't see any changes in my admin panel since I've added that line.
Where is the problem? Thanks!
Edit: Fixed by changing list_diplsay with list_display. Now I get this: type object 'User' has no attribute 'birthday'. Any ideas?

You have a typo: list_diplsay should be list_display. You should probably also add a trailing comma to your list value: ('birthday',). This ensures you end up with a tuple and not a single value.
Edit:
Since the birthday field doesn't belong to the User you'll have to add a method to look it up in your admin class:
class CustomUser(UserAdmin):
list_display = ('birthday',)
def birthday(self, obj):
return obj.profile.birthday
(I have only shown the relevant parts of the admin class; your existing inlines etc. should stay.)

Related

Bulk user import in Django

I like to bulk import users from xlsx or csv to my original User model. I don't use AbstractUser or AbstractBaseUser and I don't like to because my site is working and I don't want to abuse my schema.
I am using the original User model where I add the users (no user registration allowed) and I store the extra fields in my Profile model with a OneToOne relation.
I'm not so experienced so I tried to use code snippets that I found but I am still not able to achieve my goal. If I try to use import-export module in my admin panel it works with other models but not with the User model. Tablib or other solutions would be also interesting to me.
models.py
(I'm using the original User model that sends a signal to Profile model when a user is created)
class Profile(models.Model):
def __str__(self):
return str(self.user)
user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
date = models.DateField(auto_now_add=True, auto_now=False, blank=True)
projekt = models.ForeignKey(Projekt, on_delete=models.CASCADE, default=1)
#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()
forms.py
class RegisterForm(UserCreationForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username', 'email', 'last_name', 'first_name', 'password1', 'password2']
admin.py
from django.contrib.auth.models import User
from import_export.admin import ImportExportModelAdmin
#admin.register(User)
class UserAdmin(ImportExportModelAdmin):
pass
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
I got this error message:
django.contrib.admin.sites.AlreadyRegistered: The model User is already registered with 'auth.UserAdmin'.
I understand that my User model is in use but what could I do?

How to select a OnetoOne field from a QuerySet in a view?

See all users (that don't have search_hidden enabled) view
#login_required
def users(request):
"""List all users page"""
t_users = User.objects.all()
users = t_users.usersettings.filter(search_hidden=False).select_related('user')
context = {'users': users}
return render(request, 'users/users.html', context)
UserSettings model
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class UserSettings(models.Model):
"""Stores the user's settings."""
user = models.OneToOneField(User, related_name='usersettings', on_delete=models.CASCADE)
public_profile = models.BooleanField(default=True)
search_hidden = models.BooleanField(default=False)
class Meta:
verbose_name_plural = 'usersettings'
def __str__(self):
return f"{self.user}'s settings"
#receiver(post_save, sender=User)
def create_user_usersettings(sender, instance, created, **kwargs):
if created:
UserSettings.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_usersettings(sender, instance, **kwargs):
instance.usersettings.save()
All users have a UserSettings model tied to them when their accounts are created. In my view, I want to select all users that have search_hidden disabled, however what I've tried doesn't work.The error 'QuerySet' object has no attribute 'usersettings' is displayed whenever the page is requested. I probably need to select each user and retrieve the settings, but I don't know how to do that in an efficient manner.
iliya commented that filtering using t_users.objects.filter(search_hidden=False) would return users where search_hidden is not true in their settings object.

Django models: Access to a multilevel link between tables

I have a problem to access certain data in my models.
I have a User model giving its id to a Profile model which is giving its id to a ProfileA model.
And when I create a User it automatically creates a Profile.
Here is my user_model
from django.db import models
from django.contrib.auth.models import AbstractUser
from django_countries.fields import CountryField
from .model_custom_user_manager import CustomUserManager
class User(AbstractUser):
"""auth/login-related fields"""
is_a = models.BooleanField('a status', default=False)
is_e = models.BooleanField('e status', default=False)
# objects = CustomUserManager()
def __str__(self):
return "{} {}".format(self.first_name, self.last_name)
My profile_model:
from django.db import models
from django_countries.fields import CountryField
from django.contrib.auth import get_user_model
User = get_user_model()
from django.db.models.signals import post_save
from django.dispatch import receiver
class Profile(models.Model):
"""non-auth-related/cosmetic fields"""
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
birth_date = models.DateTimeField(auto_now=False, auto_now_add=False, null=True)
nationality = CountryField(null=True)
def __str__(self):
return f'{self.user.username} Profile'
"""receivers to add a Profile for newly created users"""
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
And what I'm trying to do is create a ProfileA when a Profile is created AND when a User has is_a==True.
Here is my profilea_model:
from django.db import models
from .model_profile import *
from django.db.models.signals import post_save
from django.dispatch import receiver
class ProfileA(models.Model):
profile = models.ForeignKey(Profile, null=True, on_delete=models.CASCADE, related_name='profile_a')
biography = models.CharField(max_length=200, null=True)
def __str__(self):
return "{}".format(self.profile)
#receiver(post_save, sender=Profile)
def create_profile_profile_a(sender, instance, created, **kwargs):
if created & Profile.user.is_a == True:
ProfileA.objects.create(profile=instance)
And when I try creating a User with Postman:
{
"username":"Pepe",
"password":"Yolo1234",
"first_name":"Pepe",
"last_name":"Pepito",
"email":"pepe#yolo.com",
"is_a":true,
"is_e":false
}
I get the error:
AttributeError at /users/
'ForwardOneToOneDescriptor' object has no attribute 'is_a'
I've tried a lot of things but nothing woks and using the DjangDocs I can't understand.
What am I doing wrong?
Thanks for your responses!
The instance argument of the create_profile_profile_a function is the instance of Profile which can be easily pointed to User and further get the target attribute is_a.
The receiver part in profilea_model should change to:
#receiver(post_save, sender=Profile)
def create_profile_profile_a(sender, instance, created, **kwargs):
if created & instance.user.is_a == True:
ProfileA.objects.create(profile=instance)

Django Admin Create Form Inline OneToOne

I have the following model:
from django.db import models
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
last_password_reset = models.DateTimeField(auto_now_add=True)
needs_password_reset = models.BooleanField(default=True)
image_url = models.URLField(max_length=500, default=None, null=True, blank=True)
I am trying to inline this into the admin. I have the following:
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserCreationForm
class UserProfileInline(admin.StackedInline):
"""User profile inline."""
model = Profile
can_delete = False
verbose_name_plural = "Profile"
class CustomUserCreationForm(UserCreationForm):
"""Create user form."""
class Meta:
model = User
fields = ("username", "first_name", "last_name", "email")
class CustomUserAdmin(UserAdmin):
"""Custom user admin."""
add_form = CustomUserCreationForm
inlines = (UserProfileInline,)
admin.site.unregister(User)
admin.site.register(User, CustomUserAdmin)
This is working fine up to a point; when I go to create user, I can see the inlined profile information. However, when I try to submit the form I get the following error (on /admin/auth/user/add/):
psycopg2.errors.NotNullViolation: null value in column "user_id" violates not-null constraint
Why is the user_id field not getting populated in the inline form? How can I set this attribute to the id of the user created by the form?
Turns out I needed to remove some signals I had written for automatic profile creation:
# Create a profile for new users
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_user_profile(sender, instance=None, created=False, **kwargs):
if created:
Profile.objects.get_or_create(user=instance)
# Update profile on user change
#receiver(post_save, sender=User)
def save_user_profile(sender, instance=None, created=False, **kwargs):
instance.profile.save()

How can I create user profile after registering user in django using Signals?

I am trying to create userprofile after user has been registered in django app.
User creation is working fine but it is not profile models in admin page.
It is not showing any errors.
So far I have done this.
users/signals.py
from django.db.models.signals import post_save
from django.contrib.auth.models import User
#reciever
from django.dispatch import receiver
from .models import Profile
#receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_profile(sender, instance, **kwargs):
instance.profile.save()
users/app.py
from django.apps import AppConfig
class UsersConfig(AppConfig):
name = 'users'
def ready(self):
import users.signals
users/models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.jpg', upload_to='profile_pic')
def __str__(self):
return f'{self.user.username} Profile'
Add this line of code to your app's __init__.py file as #Mohit Harshan mentioned
default_app_config = 'my_app.apps.MyAppConfig'
Why RelatedObjectDoesNotExist error?
Some of your User object has no active relation with Profile instance.So run the following code in your Django shell
users_without_profile = User.objects.filter(profile__isnull=True)
for user in users_without_profile:
Profile.objects.create(user=user)
In your settings.py you should change installed apps
if your settings like this
INSTALLED_APPS = ['users']
you should change it below like this.
INSTALLED_APPS = ['users.apps.UsersConfig']

Categories

Resources