Can I display the SerializerMethodField in Django admin - django

I am creating a custom field in my serializers file
new_field= serializers.SerializerMethodField(read_only=True)
def get_new_field(self,obj):
# do something
Is there a way I can display this field in the django admin panel?

You can customise your django admin panel like this:
class MyModelAdmin(models.ModelAdmin):
list_display = ('field1', 'field2', 'new_field')
list_editable = ('field1')
def new_field(self, obj):
return obj.new_field.name
admin.site.register(MyModel,MyModelAdmin)

Related

Avoid 1+n queries in Django admin list view

I have a Django model:
class Book(models.Model):
author = models.ForeignKey(Author, on_delete=models.PROTECT)
#property
def slug(self):
return slugify(self.author.name)
Now if I add slug field to admin list_display, there will be a separated query for each instance.
How to make just one query for all instances?
I tried to use select_related in the ModelAdmin class, but I did not get it working.
You can override get_queryset() of your ModelAdmin to add your select_related.
def get_queryset(self, request):
return super().get_queryset(request).select_related('author')

Doing text lookup for a ModelChoiceField on Admin gets an error

I've a model that has a text field
I added a form with Django-Autocomplete to get the available objects for this field.
In the admin page for this model, i'd like to search for objects, using the my_field field but i get an error "Related Field got invalid lookup: icontains"
I understand that i get it because the form's field is now ModelChoiceField, how can i fix it to search based on the SomeOtherModel's name field?
from dal import autocomplete
import django.forms as forms
from django.db import models
# models.py
class SomeModel(models.Model):
some_other_model = models.ForeignKey('SomeOtherModel', )
class SomeOtherModel(models.Model):
name = models.CharField(max_length=255)
#admin.py
class SomeModelAdmin(admin.ModelAdmin):
form = SomeModelForm
search_fields = ['some_other_model__name', ]
#form.py
class SomeModelForm(ModelForm):
some_other_model = forms.ModelChoiceField(
queryset=SomeOtherModel.objects.all(),
widget=autocomplete.ModelSelect2(url='control:someothermodel-autocomplete', )
)
Needed to change the search_fields using a custom get_search_results and also use the other fields/list results
#admin.py
class SomeModelAdmin(admin.ModelAdmin):
form = SomeModelForm
search_fields = []
def get_search_results(self, request, queryset, search_term):
new_queryset, use_distinct = super(SomeModelAdmin, self).\
get_search_results(request, queryset, search_term)
new_queryset |=
queryset.filter(SomeOtherModel__name__icontains=search_term)
return new_queryset, use_distinct
similar question

How to filter objects for django admin panel?

I am trying to integrate this simple django forum to an existing project.
In admin.py I have
class TopicAdmin(admin.ModelAdmin):
list_display = ["title", "forum", "creator", "created"]
list_filter = ["forum"]
...
The problem is that since there are +100K users, when I try to add a topic from admin panel, browser just hangs or becomes so slow, because it needs to load all the +100K users in creator field.
So I am wondering how to filter users in the form so that admin.py loads only superusers in the form?
You can override the default form for the TopicAdmin and set a required queryset for the creator field:
class TopicForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(TopicForm, self).__init__(*args, **kwargs)
self.fields['creator'].queryset = User.objects.filter(is_superuser=True)
class TopicAdmin(admin.ModelAdmin):
form = TopicForm
...
But may be the raw_id_fields attribute of the ModelAdmin is the better option for you?
class TopicAdmin(admin.ModelAdmin):
...
raw_id_fields = ['creator']

Django: disappearing filter_horizontal after overriding a form field

I have a many2many field in model:
models.py
pages = models.ManyToManyField(Page, verbose_name='Pages', blank=True)
And for admin interface filter_horizontal works just fine:
admin.py
filter_horizontal = ['pages',]
But when i overriding this field, using forms.Modelform (for changing queryset) - in interface it begins to show like a simple <select> field:
forms.py
class BannerAdminForm(forms.ModelForm):
pages = forms.ModelMultipleChoiceField(queryset=Page.objects.filter(publisher_is_draft=0), label='Pages')
class Meta:
model = Banners
admin.py
class BannersAdmin(admin.ModelAdmin):
form = BannerAdminForm
filter_horizontal = ['pages',]
Is there any solution for this problem? I looked for some special widgets for ModelMultipleChoiceField, but don't find anything.
This doesn't address the actual issue but is an alternative approach to setting the queryset:
class BannerAdminForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(BannerAdminForm, self).__init__(*args, **kwargs)
self.fields['pages'].queryset = Page.objects.filter(publisher_is_draft=0)
class Meta:
model = Banners
Take a look at this snippet, you can specify the widget of the field as FilteredSelectMultiple

Django Admin: how to display fields from two different models in same view?

My site makes use of Django's User Authentication User model and a custom UserProfile model to store some additional data (birthday, etc.). Is there a way to create a view in Django admin that weaves together fields from both the User and UserProfile models?
I suspect that this code snippet is not even close, but maybe it will help illustrate what I'm trying to do:
from django.contrib import admin
from django.contrib.auth.models import User
from userprofile.models import UserProfile
class UserProfileAdmin(admin.ModelAdmin):
list_display = ('name', 'gender', 'User.email') #user.email creates the error - tried some variations here, but no luck.
admin.site.register(UserProfile, UserProfileAdmin)
Error message:
ImproperlyConfigured: UserProfileAdmin.list_display[2], 'User.email' is not a callable or an attribute of 'UserProfileAdmin' or found in the model 'UserProfile'.
Ultimately, I'm trying to create an admin view that has first & last name from UserProfile and email from User.
for displaying user email you need to have a method on UserProfile or UserProfileAdmin that returns the email
on UserProfile
def user_email(self):
return self.user.email
or on UserProfileAdmin
def user_email(self, instance):
return instance.user.email
then change your list_display to
list_display = ('name', 'gender', 'user_email')
Related docs: ModelAdmin.list_display
You could try using InlineModelAdmin to display both User and UserPofile forms in a admin view.
To display user profile information in change list you can create a new method that delegates the values from UserProfile to User model.
For example this should work more or less :)
from django.contrib import admin
from django.contrib.auth.models import User
from my_models import UserProfile
class UserProfileInline(admin.StackedInline):
model = UserProfile
fk_name = 'user'
class UserAdmin(admin.ModelAdmin):
list_display = ['get_userprofile_name', 'email']
list_select_related = True
inlines = [
UserProfileInline,
]
def get_userprofile_name(self, instance):
# instance is User instance
return instance.get_profile().name
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
Using Ashoks top answer i made snippet that simplifies this process for large number of fields
class ColumnViewer(object):
pass
column_list = ('name', 'surname', )
for col in column_list:
setattr(ColumnViewer, col, lambda s,i : getattr(i, col))
#admin.register(UserProfile)
class UserProfileAdmin(admin.ModelAdmin, ColumnViewer):
list_display = column_list