Using arbitrary methods or attributes as fields on Django ModelAdmin objects? - python

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.

Related

Django - Admin Interfaces - to allow create users for non-superuser

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.

Django Rest Framework - Give Serializer of default User model validations that mimic the default validations

I am currently making a REST API that people can register themselves via. And I am just about to write the validations for how long/complex passwords should be etc. when it occurred to me there maybe is a way to mimic the default constraints that the model have set already? Is there?
My code for serializer.py looks like the following:
from rest_framework import serializers
from django.contrib.auth import get_user_model
from rest_framework.reverse import reverse
User = get_user_model()
class UserSerializer(serializers.ModelSerializer):
links = serializers.SerializerMethodField()
class Meta:
model = User
fields = ('id', 'username', 'first_name', 'last_name', 'email', 'password', 'groups', 'user_permissions', 'is_staff', 'is_active', 'is_superuser', 'last_login', 'date_joined', 'links')
def get_links(self, obj):
request = self.context['request']
username = obj.get_username()
return{
'self': reverse('user-detail', kwargs={User.USERNAME_FIELD: username}, request=request)
}
def validate(self, attrs):
#...
Thanks
You can enable Django password validation with AUTH_PASSWORD_VALIDATORS setting.
But
Validators aren’t applied at the model level, for example in User.objects.create_user() and create_superuser().
So you need to add validation to the serializer:
from django.contrib.auth.password_validation import validate_password
def validate_password(self, value):
user = self.context['request'].user
validate_password(password=value, user=user)

How to change djangos default User Creation Form

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')

Django admin show who submitted the entry

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.

How to serialize the return value of a method in a model?

I have a Django app that uses Django REST Framework and Django-allauth. Now, I'm trying to retrieve the avatar URL that's present in the social account. However, I'm having trouble forming the serializer.
For background info, the allauth's SocialAccount is related to the user model via a foreign key:
class SocialAccount(models.Model):
user = models.ForeignKey(allauth.app_settings.USER_MODEL)
# the method I'm interested of
def get_avatar_url(self):
...
Now, here's the serializer I currently have:
class ProfileInfoSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'first_name', 'last_name')
In the end, I'd like to have an extra field avatar_url which takes the result of the method call in the SocialAccount model. How do I do that?
I found a solution using a SerializerMethodField:
class ProfileInfoSerializer(serializers.ModelSerializer):
avatar_url = serializers.SerializerMethodField()
def get_avatar_url(obj, self):
return obj.socialaccount_set.first().get_avatar_id()
class Meta:
model = User
fields = ('id', 'first_name', 'last_name', 'avatar_url')

Categories