(Django 1.10.) I'm trying to follow this advice on extending the user model using OneToOneField. In my app 'polls' (yes, I'm extending the app made in the 'official' tutorial) I want to store two additional pieces of information about each user, namely, a string of characters and a number.
In my models.py I now have the following:
from django.contrib.auth.models import User
class Employee(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
stopien = models.CharField(max_length=100)
pensum = models.IntegerField()
and in admin.py the following:
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.models import User
from polls.models import Employee
class EmployeeInline(admin.StackedInline):
model = Employee
can_delete = False
verbose_name_plural = 'employee'
class UserAdmin(BaseUserAdmin):
inlines = (EmployeeInline, )
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
When adding a user using the admin panel my two new fields display correctly. However, when I click 'save', or if I don't add any user and just click on the name of my sole admin user in the admin panel, I get the following error:
OperationalError at /admin/auth/user/1/change/
no such table: polls_employee
I see some questions and answers related to similar problems, but they seem to be relevant for older version of Django. Could anyone give me a tip as to what I should do? Ideally I'd want my two additional fields display in the admin panel, though I suspect this might be a task for the future.
I have to confess I do not understand this paragraph from the documentation just following the advice I'm using:
These profile models are not special in any way - they are just Django models that happen to have a one-to-one link with a User model. As such, they do not get auto created when a user is created, but a django.db.models.signals.post_save could be used to create or update related models as appropriate.
Do I need to tie this 'post-save' to some element of the admin panel?
I'd be very greatful for any help!
You need run makemigrations to create a migration for your new model, and then migrate to run the migration and create the database table.
./manage.py makemigrations
./manage.py migrate
Related
The model itself:
from django.db import models
from django.contrib.auth.models import AbstractUser
class UserModel(AbstractUser):
class UserType(models.TextChoices):
MANAGER = 'm', 'Manager'
CUSTOMER = 'c', 'Customer'
first_name = models.CharField(max_length=120)
last_name = models.CharField(max_length=120)
type = models.CharField(choices=UserType.choices, max_length=1)
USER_MODEL is registered in settings.py.
in admin.py it's registered as:
from django.contrib import admin
from .models import UserModel
admin.site.register(UserModel)
I can create new model in the panel with existing superuser I have. i.e. - it works.
I can add new super users with manage.py and they appear in the same place in the panel.
But later on I can't login with users I created in that panel.
saff status - checked.
The problem might be with passwords, because those created with createsuperuser shown hashed in the panel or I don't know even.
If I did smth completely wrong - let me know, I only need to extend users to have a couple of additional fields.
Django version 3.2
No worries django doesn't store raw passwords it always hash the password for security reasons, imagine someone hacked into your database people usually use the same password for all websites, not nice huh?!
so try python manage.py changepassword <user_name> and write your new password
and access the shell to check is_staff attr
So i have this model where I added user field as foreign key to User model
from django.db import models
from django.contrib.auth.models import User
from django.conf import settings
class Post(models.Model):
url = models.URLField()
title = models.CharField(max_length=140)
user = models.ForeignKey(settings.AUTH_USER_MODEL)
Than I run
python3 manage.py makemigrations
And get:
You are trying to add a non-nullable field 'user' to comment without a default;
we can't do that (the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows)
2) Quit, and let me add a default in models.py
I understand that I need to give it default user but I don't get how to do that.
P.S. Django version - 1.8.3
Ok, so it happens migration utility's question hadn't appeared intuitive enough for me. What migration utility was really asking were required fields of User model. So basically you need to type in some data 3 times (for username, password and email). The problem is utility isn't really saying what field is it expecting.
If I create a CustomUser model which inherits from django.contrib.auth.models.User, like so:
in models.py
class CustomUser(django.contrib.auth.models.User):
customfield = TextField()
...
Should I still be able to use
django.contrib.auth.{authenticate, login, logout} in the normal way? Do I have to make some additional configuration change? I know these methods only work on User objects, but technically my CustomUser is-a User.
Currently, authenticate(username=u, password=p) is always returning None, even with valid credentials.
Since Django 1.5 (officially but it doesn't worked for me) and "stable" in 1.6 there is a functionality to extend the User model in a clean way.
At first:
-> Take care that you load the User model only via:
from django.contrib.auth import get_user_model
User = get_user_model()
-> Once you have built the database theres no easy way to change the User model. The database relations will break and Django / South isn't able to fix it.
-> third party modules have to be compatible with that new layout and refer in it's models to "get_user_model()", too.
You have to add some Code for the admin to respect your new model:
See: https://docs.djangoproject.com/en/dev/topics/auth/customizing/#extending-the-existing-user-model
To Override the model you need to inherit from AbstractBaseUser:
from django.contrib.auth.models import AbstractBaseUser
class MyUser(AbstractBaseUser):
...
date_of_birth = models.DateField()
height = models.FloatField()
...
REQUIRED_FIELDS = ['date_of_birth', 'height']
AbstractBaseUser provides you all attributes of the default user model. So you don't have to take care of email, username, first_name, last_name, password etc.
More info about overriding the user model: https://docs.djangoproject.com/en/dev/topics/auth/customizing/#django.contrib.auth.models.CustomUser
In your settings link your new model:
AUTH_USER_MODEL = 'customauth.MyUser'
Please read the whole documentation of customizing the user model, there are some interesting hints for overriding the default manager, admin forms etc. Just remember that bigger changes in an existing project can be a big pain.
A short overview:
- Extend models.AbstractUser
- Set AUTH_USER_MODEL in settings.py
All details can be found here: https://docs.djangoproject.com/en/dev/topics/auth/customizing/#specifying-a-custom-user-model
I'm trying to add fields to the User model and add them to the admin page. There is a recommended method in the django docs here:
https://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users
So, I created a OneToOne field for my new model:
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User)
designs = models.ManyToManyField('Design', blank=True)
prints = models.ManyToManyField('Print', blank=True)
rating = models.IntegerField(null=True, blank=True)
reliability = models.IntegerField(null=True, blank=True)
av_lead_time = models.IntegerField(null=True, blank=True)
Added an AUTH_PROFILE_MODULE to settings.py:
AUTH_PROFILE_MODULE = 'website.UserProfile'
Tried to add the UserProfile fields to the admin page:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from website.models import UserProfile
from django.contrib.auth.models import User
# Define an inline admin descriptor for UserProfile model
# which acts a bit like a singleton
class UserProfileInline(admin.StackedInline):
model = UserProfile
can_delete = False
verbose_name_plural = 'profile'
# Define a new User admin
class UserAdmin(UserAdmin):
inlines = (UserProfileInline, )
# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
Now, when I try to access a registered user via the admin menu, I get:
Caught DoesNotExist while rendering: User matching query does not exist.
In template /usr/local/lib/python2.7/dist-packages/django/contrib/admin/templates/admin/includes/fieldset.html, error at line 19
19 {{ field.field }}
And when I try to add a new user via the admin menu, I get:
Caught DoesNotExist while rendering: User matching query does not exist.
In template /usr/local/lib/python2.7/dist-packages/django/contrib/admin/templates/admin/includes/fieldset.html, error at line 19
19 {{ field.field }}
Why doesn't it recognise that particular field?
Edit: After looking on the full error message I can see the error is not solely related to extending User. The error happens when rendering checkboxes and corresponding labels that are used to assign prints to UserProfile you are editing/adding. Django admin is calling Print.__unicode__ for rendering label for each Print instance, which in turn access (on line 33 of /threedee/website/models.py) the Print's "printer" attribute which is a foreign key to User. And for some reason one of the Prints does have invalid printer value which doesn't point to any User.
Can't really tell what is really happening here without seeing the Print model, I recommend you checking the Print database table (should be named website_print) and find if there is anything unusual (are you using PostgreSQL?). If you are not having any important data there, truncating whole Print table should do the trick.
This is my old answer which you should still follow but it's not related to the error you are experiencing:
I would just comment on others answers but there doesn't seem to be a way of doing that for me. You need to combine both Alexey Sidorov's and Like it's answers:
First use django shell to create UserProfile instances for existing users - just run commads provided by Like it's answer in the shell (python manage.py shell).
After that you should setup signal that will automatically create UserProfile for each new user according to answer from alexey-sidorov.
Add this to models.py, after UserProfile class.
from django.db.models.signals import post_save
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
post_save.connect(create_user_profile, sender=User)
more info https://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users
Add UserProfile entry for you existing users:
from django.contrib.auth.models import User
from website.models import UserProfile
for user in User.objects.all():
profile = UserProfile.objects.get_or_create(user = user)
and create profile for new user as well.
use signals for what.
Scenario:
Let's say I want to extend Django's User model using multi-table inheritance. Let's say the model I created for that is called CustomUser.
Now let's assume that there are already existing records in the database corresponding to the User model and the table corresponding to the CustomUser model is still empty.
Now I want CustomUser model to be accessible from the Django's Admin app. What I noticed is only User model records which has a corresponding record in the CustomUser table is included in the change list of CustomUser, as if an INNER JOIN is being done behind the scene in the query... (I checked using connection.queries and it was indeed an INNER JOIN).
Now I want to change this behaviour so that a LEFT JOIN is done to retrieve records pertaining to CustomerUser.
How can I achieve this in Django?
Thank you very much!
Put below in any working admin.py.
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
#### below imports your custom user model
from accounts.models import CustomUser
admin.site.unregister(User)
class UserProfileInline(admin.StackedInline):
model = CustomUser
class UserProfileAdmin(UserAdmin):
inlines = [ UserProfileInline, ]
admin.site.register(User, UserProfileAdmin)
Above will show your CustomUser model in User in admin. now you can access User fields from UserProfileAdmin by User__first_name etc. pardon for bad english.