I have the situation of permits the access to admin interfaces to three types of users:
- Admin
- Supervisor
- Agent
It's a situation hierarchycal, the admin is one (the superuser) and it's creates the supervisors, and the supervisors create the agents.
All them can login to django admin with distincts authorizations.
The login has managed by 'django.contrib.auth' with the default model auth_user (.
from django.contrib.auth.models import User
class Supervisor(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
e_mail = models.EmailField(max_length=60, db_column='E-Mail',blank=True)
...other fields....
class Admin(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
e_mail = models.EmailField(max_length=60, db_column='E-Mail',blank=True)
...other fields...
But, there is a problem. If I allow the supervisor to create an agent implies that I must add the authorization to ADD and CHANGE the table USER. And this is dangerous, any supervisors could become a superuser, deleting users, etc etc....
How can I resolve this problem?? Is it possible to permit the supervisor to create an Agent without that he can be dangerous??
Thanks
EDIT
I have a doubt... in models.py during a definition of class I written this method:
def save(self):
self.user.is_staff = True
self.user.save()
super(Agent, self).save()
In Java, the method of EJB it was transactional/atomic (the commit is automatic)... In django, I have to call the method save().
It is a question different from the previous.....
Don't know if I got to understand your problem. But, if I did, you could edit the user creation form.
#admin.register(User)
class UserAdmin(BaseUserAdmin):
view_on_site = False
list_display = ('username', 'first_name', 'last_name', 'is_active', 'is_staff', 'date_joined', 'last_login')
list_filter = ('is_staff', )
fieldsets = (
('Data', {'fields': ('username', 'email', 'first_name', 'last_name', 'password')}),
('Activation/Deactivation', {'fields': ('is_active', )}),
('Permissions', {'fields': ('is_staff', 'groups', )})
)
As superuseris not an option anymore, your supervisors can't became superusers.
Let me know if this helps. Maybe we can get closer to the solution.
Related
I am developing a website on django. When I am trying to delete a user via admin panel i get an error. I can change e.g. staff status (while still getting an error, but changes are getting apllied) The code is below:
models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
emailSpam = models.BooleanField(default=True)
email = models.EmailField('email', unique=True)
first_name = None
last_name = None
confirmedEmail = models.BooleanField(default=False)
REQUIRED_FIELDS = ["emailSpam"]
forms.py
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import User
class CustomUserCreationForm(UserCreationForm):
class Meta:
model = User
fields = ('email',)
class CustomUserChangeForm(UserChangeForm):
class Meta:
model = User
fields = ('email',)
admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .forms import CustomUserCreationForm, CustomUserChangeForm
from .models import User
class Admin(UserAdmin):
add_form = CustomUserCreationForm
form = CustomUserChangeForm
model = User
list_display = ('email', 'is_staff', 'is_active',)
list_filter = ('email', 'is_staff', 'is_active',)
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Permissions', {'fields': ('is_staff', 'is_active')}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password1', 'password2', 'is_staff', 'is_active')}
),
)
search_fields = ('email',)
ordering = ('email',)
admin.site.register(User, Admin)
Possible solutions
There are three things that might be causing the issue, at least as far as I can tell. The first you already discounted. I hope it's the second solution, since that will be easier, but I fear it might be the third, which would be hardest to get around.
Cause One
As my comment stated, perhaps there is another model with a field that has User as a ForeignKey with on_delete = models.CASCADE. When you try to delete the User, all instances of this class that has that ForeignKey will need to be deleted as well (because of on_delete=models.CASCADE), and that's what's causing the issue. You have already stated you have no such models, so let's move on to solution 2.
Cause Two
I hope it's this one, since it might be easier to fix. I noticed you have email = models.EmailField('email', unique=True) as one of your fields for your User model, but AbstractUser should already have an email field. Try removing that field, makemigrations and migrate, and see if the issue is resolved.
Cause Three
Did you change from the default User model to the custom user you are now using in mid-project? In other words, did you, in this project, ever run makemigrations before you switched to a custom user model? That can be a big problem. However, there are two solutions for this, not so easy or desirable, but doable.
Solution A: If this is a new project with no valuable data yet, you can simpy delete your database, delete all migrations in all folders, as well as all __pycache__ folders as described here. Then re do python manage.py makemigrations and python manage.py migrate. Of course this will erase all your tables, so you wouldn't want to do this mid-project.
Solution B: There is a way to handle this mid-project without losing data. The steps are out in this django ticket 25313, or these, more readable instructions.
I extended the Django User Model and added a required ForeignKeyField called company. Now I also need to Change the default user creation Form. What I tried so far was:
Creating a new Form that Inherits from the default UserCreationForm form:
class MyUserCreationForm(UserCreationForm):
company = forms.ModelChoiceField(queryset=Company.objects.all())
class Meta:
model = MyUser
fields = ('username', 'company')
Adding it to my extended Django Admin:
class ExtendedUserAdmin(UserAdmin):
add_form = MyUserCreationForm
...
admin.site.register(MyUser, ExtendedUserAdmin)
This does not work. What am I missing?
Turns out you don't need to change add_form. All you need to do is add the following to ExtendedUserAdmin:
def __init__(self, model, admin_site):
super().__init__(model, admin_site)
self.add_fieldsets[0][1]['fields'] = ('username', 'password1', 'password2', 'company')
I've a database of doctors. I want to be able to see in the admin panel under doctors who created a particular doctor entry. I've the following in my admin.py
class CustomUserAdmin(UserAdmin):
filter_horizontal = ('user_permissions', 'groups')
save_on_top = True
list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff', 'last_login', 'date_joined')
admin.site.register(User, CustomUserAdmin)
class DoctorAdmin(admin.ModelAdmin):
list_display = ('name', 'specialization', 'education1', 'clinic', 'submitted_on', 'rating', 'netlikes')
search_fields = ('name', 'id', 'specialization__name', 'clinic__name')
admin.site.register(Doctor, DoctorAdmin)
I want to have another column next to netlikes as 'submitted by' and would like to see the username of the person who created that doctor entry.
Your Doctor model will need to have a field that stores this information, such as
submitted_by = ForeignKey(settings.AUTH_USER_MODEL)
You have to make sure to populate this information whenever you create a new instance of Doctor, probably using request.user. Then, in your ModelAdmin, you can just add this field to list_display.
I am pretty new to django and I am very lost with django-registration. At the moment I have the django-registration set up an going but I need to add another field to it for a phone number. I need the phone number field in the registration field instead so I can use the api from twilio to send a verification link through text instead of email. How would I go about adding this one field to django-registration?
I work with django at work and for that kind of issue we used to attach a model to the user, example:
You create a new model, for example profile with a OneToOneField to user
Add your desired fields to that profile model, such as (tlf, country, language,log...)
Create admin.py to manage this model (profile) at the same time you manage users in django admin
Profile Model Example
class Profile(models.Model):
user = models.OneToOneField(User)
phone = models.CharField(max_length=255, blank=True, null=True, verbose_name='phone')
description = models.TextField(blank=True, verbose_name='descripction')
...
...
class Meta:
ordering = ['user']
verbose_name = 'user'
verbose_name_plural = 'users'
admin.py example
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
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
filter_horizontal = ['filter fields'] # example: ['tlf', 'country',...]
verbose_name_plural = 'profiles'
fk_name = 'user'
class UserAdmin(UserAdmin):
inlines = (ProfileInline, )
list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff')
list_filter = ('is_staff', 'is_superuser', 'is_active')
admin.site.unregister(User) # Unregister user to add new inline ProfileInline
admin.site.register(User, UserAdmin) # Register User with this inline profile
Create an user and attach a profile to him
# Create user
username = 'TestUser'
email = 'test#example.com'
passw = '1234'
new_user = User.objects.create_user(username, email, passw)
# Create profile
phone = '654654654'
desc = 'Test user profile'
new_profile = Profile(user=new_user, phone = phone, description=desc)
new_profile.profile_role = new_u_prole
new_profile.user = new_user
# Save profile and user
new_profile.save()
new_user.save()
Now you'll have this Profile model attached to each user, and you could add the fields you wish to Profile Model, and for example if you make:
user = User.objects.get(id=1)
you can access to his profile doing:
user.profile
and to access phone
user.profile.phone
Not django-registration, but I customized django-userena once to add a custom field to the signup form.
You can view the code here.
I am sure the process works more or less the same in django-registration too: overriding the signup form and adding custom fields.
However, django-registration is no longer maintained, I believe. It is a classic and works so well, but there are other options too.
Using Django 1.1:
The Django admin docs describe using arbitrary methods or attributes on a ModelAdmin object in the list_display class attribute. This is a great mechanism for displaying arbitrary information in the list display for a Model. However, there does not appear to be a similar mechanism for the change form page itself. What is the simplest way to accomplish this useful little feature to display arbitrary, non-field-derived information on the ModelAdmin change form page?
A concrete example of the desired setup:
class CustomUserAdmin(UserAdmin):
def registration_key(self, obj):
"""Special method for looking up and returning the user's registration key
"""
return 'the_key'
list_display = ('email', 'first_name', 'last_name', 'is_active', 'is_staff',
'registration_key') # <- this works
fields = ('email', 'first_name', 'last_name', 'is_active', 'is_staff',
'registration_key') # <- this DOESN'T work?
Add the method to the 'readonly_fields' tuple as well.
Try the following:
class CustomUserAdminForm(forms.ModelForm):
registration_key = forms.IntegerField()
class Meta:
model = User
class CustomUserAdmin(UserAdmin):
def registration_key(self, obj):
"""Special method for looking up and returning the user's registration key
"""
return 'the_key'
list_display = ('email', 'first_name', 'last_name', 'is_active', 'is_staff',
'registration_key') # <- this works
fields = ('email', 'first_name', 'last_name', 'is_active', 'is_staff',
'registration_key')
I've done this before by overriding the template for the change form, and accessing custom methods on the model. Using fields is asking the admin to try to add a form field for your method.