Django How to create a custom user from admin? - python

So I have this method:
def create_editor(self, email, dob, password):
user = self.create_user(
email,
dob,
accepted_tos=True,
password=password
)
try:
editors = Group.objects.get(name__iexact="Editors")
except Group.DoesNotExist:
editors = Group.objects.create(name="Editors")
editors.permissions.add(Permission.objects.get(codename="can_give_discount")) # add can_give_discount permission
user.groups.add(editors)
user.save()
return user
To create a normal user and then add the user to the editor group
I want to be able to create a manager from the normal django admin.
So in the image below I want another button called Add Manager

At first it looks like what you want to do is create a new Manager model that has a foreignkey to user. Then from the admin side you have the option to first click add user, then navigate to the Manager model and add a manager (where you also supply the user id so they are linked by foreignkey).
However if this is only done to accommodate permissions and groups you can also go to the groups model in django admin.

Spoiler alert, the django admin is not really made for customizations. But there are some think which django is prepared for, checkout the django admin docs here https://docs.djangoproject.com/en/1.11/ref/contrib/admin/#custom-template-options.
It might be a solution for you to extend/override your existing create user template (see here: https://docs.djangoproject.com/en/1.11/ref/contrib/admin/#overriding-vs-replacing-an-admin-template) to e.g. add ad flag that makes the new user an editor or not and you could override the User.objects.create() method to use the flag.
The solution with the least amount of work but 2 steps would be to add an admin action (if you want the button in the detail view: django object action https://github.com/crccheck/django-object-actions) to "upgrade" a normal user to an editor.

Or maybe you could add another choice field extending the User to say whether the added guy is 'Editor' or 'Manager' and on save check if the added user is 'Manager' or 'Editor', and override save to add the new user to the corresponding group.

Related

How to create Workspaces and manage them for all the users in Django?

I have a complete Login and Registration system in my Django app, that lets me register users, log in users, logout users, change passwords, reset passwords, invite users. I have all the basic functionality.
I want now to have Workspaces for users, as per following points:
There will be a workspace admin of each workspace.
Workspace admins can only add/remove (register/delete) users to his own workspaces.
Users can react to (log in to) only those workspaces to which they have been added.
A superuser (main admin) can manage all workspaces, all workspaces-admins and all users.
How do I accomplish this? You can say this is similar to a Slack thing. I just need a guidelines/roadmap and I will implement it myself.
I have already created a Workspace Model, which looks like below:
class Workspace(models.Model):
name = models.CharField(max_length=254)
created_at = models.DateTimeField(auto_now_add=True)
def make_admin(self, user):
user.is_workspace_admin = True
user.save()
def remove_admin(self, user):
user.is_workspace_admin = False
user.save()
and my User model has following two attributes beside other default Django fields:
class User(AbstractBaseUser, PermissionsMixin):
is_workspace_admin = models.BooleanField(default=True)
workspaces = models.ManyToManyField(Workspace)
Is this approach correct? If not please guide me to the proper way. BTW, using this approach, I can add/assign workspaces to any user, but how will I be able to manage the users logging in their own workspaces and reacting with only their workspaces to which they have been assigned. And also workspaces admins controlling their workspaces’ users etc?
I know about using Groups. So let's say I create all relevant permissions (Can you also tell me how to create permissions?) to add workspace user, remove workspace user, make workspace user a workspace admin, remove workspace admin from workspace adminship etc. and create different Groups and add relevant permissions in each group. Suppose my groups looks like manage_workspace_a to manage (add/remove) the workspace users groups, manage_workspace_admins to manage (add/remove) workspace admins, and default permissions that Django provides for each Model.
So, how will i be able to have the functionality that when a "User A" that has is_superuser=True, makes the is_workspace_admin=True of "User B", then "User B" should automatically gets all the Workspace Admin Permissions. Something like this:
workspace_user = User.objects.get(email="some-email-address")
if request.user.is_superuser:
wordspace_user.permissions.add([Workspace Admin Permissions])
Can somebody explain the whole process with a small code example?
This is a very long, multi-part question but hopefully I can point you in the right direction
I would suggest adding another Many-to-Many field on your User model that handles administrator status. At the moment, you have it set to Boolean flag - so an administrator can either manage all workspaces or none.
Personally, I would reverse the M2M status and put users and administrators on the workspace, rather than on the user model. It's not problematic to have on the user model but I feel it makes more sense to check that the user is in the workspace's permitted users/admins rather than the workspace is in the user's list of workspaces and admin workspaces.
You will need to change your code that adds an administrator to a workspace as you won't want to use a boolean flag:
def make_admin(self, user):
self.administrators.add(user)
As to how you manage the workspace itself, you can just put ORM filters at the very start of your relevant views:
def workspace_view(request, workspace_id):
workspace = get_object_or_404(Workspace, workspace_id)
if request.user not in workspace.users:
return redirect(...)
...the rest of your view
Bear in mind that this doesn't allow administrators in unless they are in the users group - you will either need to add them to users or add another condition to check if they are in administrators.
If you want an overview of all the workspaces in some sort of index/home page, you would just use the m2m reverse accessor which depends on your reverse name (or /relation/_set by default):
def workspaces(request):
workspaces = request.user.workspaces.all()
You can definitely leverage Django's in-built permissions system, I would point you to the documentation because that is a long subject:
https://docs.djangoproject.com/en/4.0/topics/auth/default/#permissions-and-authorization

How do I define multiple user types in Django using the existing User model?

Django has an awesome user model coupled with authentication. Using that, I want to define multiple user types, say a student and a professor. I want to do this using minimal change to the existing model.
One of the ways would be the User Groups. Another would be to extend the user model and store a flag. Which would be a better method for my problem, given that the two entities aren't entirely independent and a member of type one can also be a member of type two.
If I understand exactly your problem my choice would be an OneToOneField.
When I'm working on projects where the clients want customized users, one of the best solution is to create a new model with a OneToOneField pointing to the Django User like a Profile model. When you have an User object, you can do user.profile and you get the profile related with user (so you can do user.profile.any_profile_field).
I recommend you to use this kind of solution because it is easy to manage and scalable. If in 1 month you need to add a new property/field/value to an User, with this solution you only need to change this new model.
Here you can add to the Profile model as many fields as you need, and it's easy to manage because if you have the user you have the profile and viceversa
class Profile(models.Model):
USER_TYPE_CHOICES = (
('s', 'Student'),
('t', 'Teacher' ),
)
user = models.OneToOneField(User)
type_user = models.CharField(max_length=20, default='s',choices=USER_TYPE_CHOICES)
# ... ... ...
# Your fields here
EDIT
If you use this, your authenticate method can remain the same as it is right no.
You could do things as this example:
user = User.objects.all()[0] # Get the first user
user.profile # This would return the profile object
user.profile.type_user # This would return the type_user of the profile related with this user
So you can use the profile fields in your login function, or when an user is accessing to some url, and check the type user to allow or not.
Example to control a template where only teachers can enter:
def teacher_view(request):
if not request.user.is_authenticated:
# If user is not logged in, send it to login page
else:
if request.user.profile.type_user == 's': # If the user is student
# Here you can raise an error (not enough permissions), raise an error or redirect

get user profile in django

hello i'm new in python and django
I need a view that get current user profile I know I shoud use get_profile from User but I don't know how to use it . i read the django document and It didn't help me.
this is what I found from doc:
from django.contrib.auth.models import User
profile=request.user.get_profile()
Django's documentation says it all, specifically the part Storing additional information about users. First you need to define a model somewhere in your models.py with fields for the additional information of the user:
models.py
from django.contrib.auth.models import User
class UserProfile(models.Model):
# This field is required.
user = models.OneToOneField(User)
# Other fields here
accepted_eula = models.BooleanField()
favorite_animal = models.CharField(max_length=20, default="Dragons.")
Then, you need to indicate that this model (UserProfile) is the user profile by setting AUTH_PROFILE_MODULE inside your settings.py:
settings.py
...
AUTH_PROFILE_MODULE = 'accounts.UserProfile'
...
You need to replace accounts with the name of your app. Finally, you want to create a profile every time a User instance is created by registering a post_save handler, this way every time you create a user Django will create his profile too:
models.py
from django.contrib.auth.models import User
class UserProfile(models.Model):
# This field is required.
user = models.OneToOneField(User)
# Other fields here
accepted_eula = models.BooleanField()
favorite_animal = models.CharField(max_length=20, default="Dragons.")
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
post_save.connect(create_user_profile, sender=User)
Accessing the Profile
To access the current user's profile in your view, just use the User instance provided by the request, and call get_profile on it:
def your_view(request):
profile = request.user.get_profile()
...
# Your code
Basically django User models will provide access only for the fields ( firstname,lastname,email,password,is_staff,is_active,last_login).
However if we want to add any extra fields to this model, say we need to add a new column named dateofbirth for every user, then we need to add a column named DOB into User model. But this is not possible as we aren't able to edit django User models.
To achieve this either
1.We can have a separate new table with email id & DOB column, such that a column in User model is mapped with a column in the new table. But this will create a new db instance for every db request. Say if u want to find the DOB of a customer,
First we need to fetch the value of mapped id of a customer from the
User table.
WIth the above value, get DOB from the new table.
In the second method,
Instead of using django User model, use your own customize model with all the fields needed. However if any updation related to security or some enhancement made to django User model we can't use it directly. We need to do more code changes at our end( wherever we use our customize models.) This will be a bit pain for a developer to identify the code & make changes.
To overcome the above issues, django introduce django profile which is very simple and more flexible. The advantages are
Updation/enhancement to the User model can be applied without modifying the code much
No need of creating new db instance to fetch the extra values.
Since the field has onetoone mapping deletion of data from one table will delete others also.
More secure, since we use django models ( no sql injection)
How to Use this:
In settings.py create a variable AUTH_PROFILE_MODULE = "appname.profiletable"
In models.py, create a new table with the fields needed and make sure that the id in User model is onetoone mapped with new table.
create a signal which inserts a row into the new table whenever a new entry is added into User model.
The value in the new table can be accessed using User object itself.
Say, we created a new table extrauser which has DOB, emailid. To find the DOB of a customer, use
a=User.objects.get(email='x#x.xom')
a.get_profile().DOB will give the dateofbirth value from extrauser table.
Hope the above details make you clear in understanding django profile. Incase of any help further, let me know. I have used django profile in my project.
Old question but I thought anyone seeing it today may benefit from this:
Django 1.5 adds the ability to - easily - extend the User model. This may be preferable as you now only got one object to deal with rather than two! Seems the more modern way.
https://hurricanelabs.com/blog/django-user-models/
You need to specify which class is your "Profile" by setting AUTH_PROFILE_MODULE = 'accounts.UserProfile' (for example)
https://docs.djangoproject.com/en/1.4/topics/auth/

Set and use flags against a users profile model in Django

I have a simple webapp in Django for an iPhone app.
I want to prompt the user to review our product, but just once. I then don't want to show that prompt again.
So would the best practise way of implementing this to be to add a new entry to the user profile model with a bolean field: "reviewed" - and then set that flag when the user completes the action?
I would then check for that entry in my template and display or not, the prompt.
I've not yet worked with database models, extended the user model, or saved to custom DB fields, so any thoughts or examples on this would be most welcome. I'm a little nervous as my site has live users and I won't want to break the user tables.
If you are using MySQL or PostgreSQL, you can do some ALTER TABLE without loosing any data.
In Django, it is quite easy to add a profile for the user.
Make sure, to create the profile if it doesn't exist :
try:
profile = request.user.get_profile()
except UserProfile.DoesNotExist:
# If DoesNotExists, Create an empty one
profile = UserProfile(user=request.user)
profile.save()
More information here :
http://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users
http://www.djangobook.com/en/1.0/chapter12/#cn222
There are a variety of ways to do this. I suggest the following:
Django has a messaging framework, built by design to show messages to users only once when the software creates them. Whenever X is created/modified/deleted etc, you can add the message to the user via User.message_set.create(message='Whatever you like'). This will be shown to the user once. This relies on django sessions, which I assume you're using since you're relying on the built-in user model. These messages are stored in auth_message.
HTH

Django UserProfile... without a password

I'd like to create a subset of Users that don't have a login... basically as a way to add a photographer field to photos without having a full blown account associated with that person (since in many cases, they'll never actually log in to the site). A caveat is that I'd also like to be able to enable an account for them later.
So, I think the question becomes what's the best way to set up a "People" table that ties to the User table without actually extending the User table with UserProfile.
A user profile (as returned by django.contrib.auth.models.User.get_profile) doesn't extend the User table - the model you specify as the profile model with the AUTH_PROFILE_MODULE setting is just a model which has a ForeignKey to User. get_profile and the setting are really just a convenience API for accessing an instance of a specific model which has a ForeignKey to a specific User instance.
As such, one option is to create a profile model in which the ForeignKey to User can be null and associate your Photo model with this profile model instead of the User model. This would allow you to create a profile for a non-existent user and attach a registered User to the profile at a later date.
Users that can't login? Just given them a totally random password.
import random
user.set_password( str(random.random()) )
They'll never be able to log on.
Supply your own authentication routine, then you can check (or not check) anything you like. We do this so if they fail on normal username, we can also let them in on email/password (although that's not what I'm showing below).
in settings.py:
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
'userprofile.my_authenticate.MyLoginBackend', # if they fail the normal test
)
in userprofile/my_authenticate.py:
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import User
class MyLoginBackend(ModelBackend):
"""Return User record if username + (some test) is valid.
Return None if no match.
"""
def authenticate(self, username=None, password=None, request=None):
try:
user = User.objects.get(username=username)
# plus any other test of User/UserProfile, etc.
return user # indicates success
except User.DoesNotExist:
return None
# authenticate
# class MyLoginBackend
From the documentation on django auth, if you want to use the User model, it's mandatory to have a username and password, there are no "anonymous accounts". I guess you could create accounts with a default password and then give the opportunity for people to enable a "real" account (by setting a password themselves).
To set up a "People" table that ties to the User table you just have to use a ForeignKey field (that's actually the recommended way of adding additional info to the User model, and not inheritance)
Using a model with a ForeignKey field linking to User might not work as you want because you need anonymous access. I'm not sure if that's going to work, but you might try what happens if you let it have a ForeignKey to AnonymousUser (whose id is always None!) instead.
If you try it, post your results here, I'd be curious.
The django.contrib.auth.models.User exists solely for the purpose of using default authentication backend (database-based). If you write your own backend, you can make some accounts passwordless, while keeping normal accounts with passwords. Django documentation has a chapter on this.
Another upvote for insin's answer: handle this through a UserProfile. James Bennett has a great article about extending django.contrib.auth.models.User. He walks through a couple methods, explains their pros/cons and lands on the UserProfile way as ideal.

Categories

Resources