Django: Create staff user from oneToOneField - django

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!

Related

DoesNotExist error when using custom User model

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.

Profile User object displaying all user django

I have a CustomUser and a Profile app in my profile app i have following models:
class Profile(models.Model):
user = models.OneToOneField(MyUser,unique=True)
name = models.CharField(_('Name'),max_length=100)
work = models.CharField(_('Position'),max_length=200)
company = models.CharField(_('Company'),max_length=200)
gender = models.CharField(_('Gender'),max_length=10)
photo = models.ImageField(_('Profile Pic'),upload_to='images/',blank=True)
bio = models.TextField(_('Bio'),max_length=300)
def __str__(self):
return self.name
My main problem is when i include user field in forms it displays a drop down list of all user who are registered with the app.
And i want to show only loggedin user
I think this approach is better and saves a time:
user = MyUser.objects.filter(username__icontains=request.user)
form.fields['user'].queryset = user
This is a question specific to the form you are using, rather than the model. What you want to do is specify a queryset for the field user.
You may do this after instantiating your initial form. The following would go in your view, where you declare your form for get requests:
# Obtain set of authenticated users (see [1] below)
authenticated_users = []
users = User.objects.all()
for user in users:
if user.is_authenticated():
authenticated_users.append(user)
# Instantiate form and update `user` queryset
form = SomeForm()
form.fields['user'].queryset = authenticated_users
[1] I don't believe it's possible to filter the User object manager by whether a user is authenticated or not, unfortunately, so you must iterate through the queryset and check for each user. If anyone knows such a query, then I'd be happy to change my answer to it.
This will limit the dropdown to authenticated users.

Django save model with anonymous user

I have a Django model:
class Project(models.Model):
user = models.ForeignKey(User)
zipcode = models.CharField(max_length=5)
module = models.ForeignKey(Module)
In my views.py:
def my_view(request):
...
project = Project.objects.create(
user=request.user,
product=product_instance,
...
)
project.save()
I want to be able to save user as an authenticated user OR an AnonymousUser (which I can update later). However, if I'm not logged in I get this error:
ValueError: Cannot assign "<django.utils.functional.SimpleLazyObject object at 0x1b498d0>": "Project.user" must be a "User" instance.
I guess that Django won't save the AnonymousUser because it is not a User as defined in the User model. Do I need to add the anonymous user to the User model, or am I missing something?
Any assistance much appreciated.
The user field is a ForeignKey. That means it must reference some user.
By definition, the AnonymousUser is no user: in Django, there is no AnonymousUserA and AnonymousUserB. They're all the same: AnonymousUser.
Conclusion: you can't put an AnonymousUser in a User ForeignKey.
The solution to your issue is pretty straightforward though: when the User is anonymous, just leave the field blank. To do that, you'll need to allow it:
user = models.ForeignKey(User, blank = True, null = True)

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

Django Interleaving UserProfile with Profile in Admin

I have a User Profile which is currently shown in the Admin via a Stacked Inline. However because I have fields such as last_name_prefix and last_name_suffix (for foreign names such as Piet van Dijk to cover proper sorting by last name) I would like to be able interleave the user profile fields with the normal change user fields. So in the Change User admin interface it would appear like this:
First Name:
Last Name Prefix:
Last Name
Last Name Suffix:
I have tried this solution: http://groups.google.com/group/django-users/browse_thread/thread/bf7f2a0576e4afd1/5e3c1e98c0c2a5b1. But that just created extra fields in the user form that weren't actually coming from the user profile (they stayed empty even though they should get values from the user profile).
Could someone explain to me if this could be done and how?
Thanks very much!
I'm pretty sure you'd need to overwrite normal User admin.
What I would actually do is create a special forms.ModelForm for UserProfile called, say UserProfileAdminForm which included fields from the User model as well. Then you'd register UserProfile for admin and the save function for the UserProfileAdminForm would capture the user-specific fields and either create or update the User record (This is left as an exercise to the OP).
More info
When I say add more fields to a form, I mean manually add them:
class UserProfileAdminForm(forms.ModelForm):
username = forms.CharField(...)
email = forms.EmailField(...)
first_name = ...
last_name = ...
def __init__(self, *args, **kwargs):
super(UserProfileAdminForm, self).__init__(*args, **kwargs)
profile = kwargs.get('instance', None)
if profile and profile.user:
self.user = profile.user
self.fields['username'].initial = self.user.username
self.fields['last_name'].initial = ...
...
class Meta:
model = UserProfile
This question has been solved by the new Django version 1.5: https://docs.djangoproject.com/en/1.5/topics/auth/customizing/#auth-custom-user.