DoesNotExist error when using custom User model - django

I have a Group model in my group/models.py file:
class Group(models.Model):
leader = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=55)
description = models.TextField()
joined = models.ManyToManyField(User, blank=True)
and an Account model, which is an extension of django's standard User, in users/models.py:
class Account(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
joined_groups = models.ManyToManyField(Group, related_name='joined_group')
created_groups = models.ManyToManyField(Group)
in users/admin.py:
class AccountInline(admin.StackedInline):
model = Account
can_delete = False
verbose_name_plural = 'Accounts'
class CustomUserAdmin(UserAdmin):
inlines = (AccountInline,)
admin.site.unregister(User)
admin.site.register(User, CustomUserAdmin)
The issue I'm having trouble understanding is when I create a new User, the Account for that User doesn't seem to really be registering. At the bottom of the new User's page (via django admin site) the new Account looks like this:
Now, this new User seems to have an account which contains joined_groups and created_groups but when I try to join or create a Group with that new User, I get an error DoesNotExist - Account matching query does not exist
I'm not sure why the new User/Account isn't really registering its Account. In comparison, inside my AdminUser page its Account info looks like this:
Account: #1 for the new User vs. Account: Acount object (6) for Admin User.
Finally, when I go onto the django admin site and add my new User to a Group and hit save, Account: #1 changes to Account: Acount object (7) which then allows the new User to create and join other Groups.
I'm completely lost on what is happening and why it is. It's important because I want new Users who register to be able to join and create Groups with an admin starting them off. Did I mess up my Account model? Or is this something to do with django's general User model? Or is it something else entirely?

Basically you have two models connected by a relationship, but I can't see the code for creating an account object. It is a good practice to create a user-related profile with the post_save signal.
from django.contrib.auth.models import User
from django.dispatch import receiver
from django.db.models.signals import post_save
from .models import Account
#receiver(post_save, sender=User)
def create_save_account(sender, instance, created, **kwargs):
if created:
Account.objects.create(user=instance)
instance.account.save()
In addition, I refer to the documentation and examples.

Related

How model field will be field automatically with the user ids

I am creating a payment/paid-subscription for my django project. I decided to create a separate payment app and connect it to my django project. In below, you see the model for payment which I expect to have user ids with their payment status(for now just want to start with default=False):
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
class Payment(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
paid = models.BooleanField(default=False)
class Meta:
db_table = 'payment'
I created this, but in the database table, I see the user_id and
paid are empty, while I have already a lot of users signed up. How
to bring those ids here, with a default false paid?
And what should I do to say django that after each new sign up fill
this model as well?
Part 1 - Updating existing users to have a Payment
Django won't automatically do this for you, you can go into the shell, and create Payment instances for each user:
Enter the shell (python manage.py shell)
from myapp.models import Payment
users = User.objects.all()
for user in users:
Payment.objects.create(user=user, paid=False)
If you want to be more effecient you could do something like this:
payments = [Payment(user=user, paid=False) for user in User.objects.all()]
Payment.objects.bulk_create(payments)
If this is an app that you have already deployed somewhere else you should create a data-migration to do this for you:
from django.db import migrations
def create_payments(apps, schema_editor):
Payment = apps.get_model('yourappname', 'Payment')
User = apps.get_model('yourappname', 'User')
payments = [Payment(user=user, paid=False) for user in User.objects.all()]
Payment.objects.bulk_create(payments)
class Migration(migrations.Migration):
dependencies = [
('yourappname', '0001_initial'),
]
operations = [
migrations.RunPython(create_payments),
]
Part 2 - Creating Payments on every new sign-up
This will depend alot on how you are doing your sign-ups, so its difficult to give an exact answer. But wherever your new user object is created you just want to add something like:
Payment.objects.create(user=user, paid=False)
If you have a form that is handling user sign-ups maybe do it in the save method of that form. If you're using something like django rest framework, it would go in whatever view creates the User.

Django: Create staff user from oneToOneField

I have a model in order to extend the user model with some extra fields.
The "therapeut" model has a user field that's a OneToOneField connected to User from django.contrib.auth.models. Here's the code:
from django.db import models
from django.contrib.auth.models import User
class Therapeut(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
# some more fields here
Now when I want to add a "therapeut" from the model through the Django Admin, I can choose from the available Users or add a new one.
When click I add a new one (green + next to the User dropdown), I would like that new user to have staff status and add it to the user group "therapeuten", in order to manage the permissions for this new user.
I dont see how to archieve this (automatically), neither do I have the option to set staff status and user group in the popup. Note I am logged in as the superuser. See pic:
Any help on how to do this would be much appreciated!
OK so I figured out how to do it, I'm adding the solution here for reference:
Override the save method on the Therapeut class like so:
class Therapeut(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
# some more fields here
# override save method to add staff status to connected user and add it to therapeutengroup
def save(self, *args, **kwargs):
userObj = self.user
userObj.is_staff = True
userObj.save()
therapGroup = Group.objects.get(name='therapeut')
therapGroup.user_set.add(userObj)
super(Therapeut, self).save(*args, **kwargs)
However, if someone else has a better or different solution, More than welcome to suggest it here!

Django User belongs to Company

I am really new to Django, I would like to have users, that belong to a company, so many users to a single company. Do I need to copy the existing user model and add to my project? Where would I find the User model to extend?
Sorry if this is not very descriptive it is my first project with python and django.
(If you need many companies to one user) you don't need to copy the user model. Just create a "Company" model and use "ForeignKey".
Example:
from django.contrib.auth import get_user_model
User = get_user_model()
class Company(models.Model):
user = models.ForeignKey(User)
Opposite(If you need many users to one company):
#settings.py
AUTH_USER_MODEL = 'myapp.User'
#myapp.models.py
from django.contrib.auth.models import User as BaseUser, UserManager
class User(BaseUser):
company = models.ForeignKey(Company)
# Use UserManager to get the create_user method, etc.
objects = UserManager()

Django: Issues with extending 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.

Django user profile

When adding additional fields to a user profile, such as location, gender, employer, etc., should I be adding additional columns to django.contrib.auth.models.User and saving it there? Or should I be creating a new table to save user profile information?
Also, when a user uploads a profile picture, should I be saving this in the same table? (Note this is not a production server, I'm just doing this on my local runserver to figure things out). Thank you
You have to make a model for the user profile:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
location = models.CharField(max_length=140)
gender = models.CharField(max_length=140)
employer = models.ForeignKey(Employer)
profile_picture = models.ImageField(upload_to='thumbpath', blank=True)
def __unicode__(self):
return u'Profile of user: %s' % self.user.username
Then configure in settings.py:
AUTH_PROFILE_MODULE = 'accounts.UserProfile'
Conceptually, OneToOneField is similar to a ForeignKey with unique=True, but the “reverse” side of the relation will directly return a single object. This is the recommended way of extending User class.
class UserProfile(models.Model):
user = models.OneToOneField(User)
...
Current Django is 1.9 and here are some updates to the outdated accepted answer
use models.OneToOneField(User)
add related_name='profile'
use .__str__() and .format() for Python 3
like so
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile')
location = models.CharField(max_length=140)
gender = models.CharField(max_length=140)
...
def __str__(self):
return 'Profile of user: {}'.format(self.user.username)
Using related_name you can access a user's profile easily, for example for request.user
request.user.profile.location
request.user.profile.gender
No need for additional lookups.
Django provides a way of storing additional information about users in a separate table (called user profile).
Starting with Django 1.5 you can replace the default User with your custom user object using a simple settings entry:
AUTH_USER_MODEL = 'myapp.MyUser'
For slightly more details, check this Django documentation entry.
There's a solution I found here. Basically you just extend the default form UserCreationForm but keeping the same name. It works seamlessly with the way Django's docs tell you to do UserProfiles.
Answer can be updated to add signal receiver which will create the profile if it does not exist and update if it is already there.
#receiver(post_save, sender=User)
def create_or_update_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
instance.profile.save()
This https://simpleisbetterthancomplex.com/tutorial/2016/11/23/how-to-add-user-profile-to-django-admin.html post also includes how to edit, list the custom profile in admin panel.
The current 2 top answers are outdated
If you reference User directly (for example, by referring to it in a foreign key), your code will not work in projects where the AUTH_USER_MODEL setting has been changed to a different user model. [..] Instead of referring to User directly [..] when you define a foreign key or many-to-many relations to the user model, you should specify the custom model using the AUTH_USER_MODEL setting.
from django.conf import settings
from django.db import models
class UserProfile(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name="userprofile",
)
https://docs.djangoproject.com/en/3.2/topics/auth/customizing/#referencing-the-user-model
If you want to get user profile data from user objects.
from django.contrib.auth.models import User
request.user.profile