why Django admin short_description function not working? - python

I am trying to make some changes in my django admin panel such as want to show "title" instead of "blog_tile" but I am not understanding why changes not reflecting.
class BlogAdmin(admin.ModelAdmin):
readonly_fields = ['blog_publish_time', 'blog_update_time']
list_display = ['blog_title', 'blog_status',
'blog_publish_time', 'blog_update_time']
def rename_blog_title(self, obj):
return obj.blog_title[:10]
rename_blog_title.short_description = "title"
admin.site.register(Blog, BlogAdmin)
where I am doing mistake?

You are using blog_title, not rename_blog_title in your list_display. You thus should refer to the method, not to the field of your Blog model:
class BlogAdmin(admin.ModelAdmin):
readonly_fields = ['blog_publish_time', 'blog_update_time']
list_display = ['rename_blog_title', 'blog_status', 'blog_publish_time', 'blog_update_time']
def rename_blog_title(self, obj):
return obj.blog_title[:10]
rename_blog_title.short_description = 'title'
admin.site.register(Blog, BlogAdmin)

Related

Filtering objects in django admin

I want to manage objects in django admin, though I would like to be able only to edit objects with a specific value of some attribute. Precisely I have now in admin.py:
class UnitAdmin(admin.ModelAdmin):
list_display = ('type', 'name', 'result_file')
list_filter = ['type']
admin.site.register(Unit, UnitAdmin)
And I would like to manage only units with type='SomeSpecificType'. I saw something with overriding SimpleListFilter class, though I can't see how this applies here.
You have to override the get_queryset in de modelAdmin and filter objects that have type='SomeSpecificType.
class UnitAdmin(admin.ModelAdmin):
...
def get_queryset(self, request):
qs = super(UnitAdmin, self).get_queryset(request)
return qs.filter(type='SomeSpecificType')
You can do
class UnitAdmin(admin.ModelAdmin):
list_display = ('type', 'name', 'result_file')
list_filter = ['type']
def get_readonly_fields(self, request, obj=None):
if obj and obj.type == 'SomeSpecificType':
return []
return ["type", "name", "result_file"]

Passing URL parameters to a nested serializer

I have two serializers, one of which is nested:
class PaperSerializer(serializers.ModelSerializer):
class Meta:
model = Paper
class AuthorSerializer(serializers.ModelSerializer):
papers = PaperSerializer(
many=True,
read_only=True,
source='paper_set'
)
class Meta:
model = Author
I want to get a list of Authors which shows only their published Papers (Boolean field exists on the model).
I would like to call the API like /api/v1/authors/?show_published_only=true.
After some digging around, I discovered that you can pass the context from the ViewSet to the Serializer:
views.py
class AuthorViewSet(viewsets.ModelViewSet):
queryset = Author.objects.all()
serializer_class = AuthorSerializer
filter_fields = (
'show_published_only',
)
def get_serializer_context(self):
return {'request': self.request}
Now, create a new serializer FilteredPaperSerializer which inherits from serializers.ListSerializer, then override the to_representation() method to filter the queryset:
serializers.py
class FilteredPaperSerializer(serializers.ListSerializer):
def to_representation(self, data):
# Get the parameter from the URL
show_published_only = self.context['request'].query_params['show_published_only']
data = data.filter(is_published=show_published_only)
return super(FilteredPaperSerializer, self).to_representation(data)
class AuthorSerializer(serializers.ModelSerializer):
papers = FilteredPaperSerializer(
many=True,
read_only=True,
source='paper_set'
)
class Meta:
model = Author
NB: Don't forget to convert the fetched URL parameter to a Boolean or relevant data type for your model, I neglected to do it in the write-up above.

add data to admin modelform inline object before saving

In relation to the question below, how would I do this for the django admin?
Add data to ModelForm object before saving
Example:
class FooInlineModel(models.Model):
bar = models.CharField()
secret = models.CharField()
class FooInlineForm(forms.ModelForm):
class Meta:
model = FooInlineModel
exclude = ('secret',)
class FooInline(admin.TabularInline):
pass
class FooAdmin(admin.ModelAdmin):
inlines = (FooInline,)
This logically triggers an IntegrityError because secret is submitted NULL, how do I manually populate the field in one of the admin methods? e.g.
class ???:
def ???:
obj = form.save(commit=False)
obj.secret = 'stackoverflow'
obj.save()
Alright I found the method, for those interested:
class FooAdmin(admin.ModelAdmin):
inlines = (FooInline,)
def save_formset(self, request, form, formset, change):
instances = formset.save(commit=False)
for instance in instances:
if isinstance(instance, FooInlineModel):
instance.secret = 'stackoverflow'
instance.save()

Django admin list display optimize queryset

In User model i have a method:
#cached_property
def income(self):
return PartnerIncome.objects.all().aggregate(Sum('income'))['income__sum']*self.share_of_profit
PartnerIncome model:
class PartnerIncome(models.Model):
title = models.CharField(max_length=255)
income = models.FloatField(default=0)
Now i want to show 'inccome' in list_display=('income', ) at admin panel, but each object make extra query to database. How i can make PartnerIncome.objects.all().aggregate(Sum('income')) as a global variable for admin change list...
How about just overriding the get_queryset method in your ModelAdmin?
class UserAdmin(admin.ModelAdmin):
list_display = ('income', ...)
def income(self, obj):
return obj.income
def get_queryset(self, request):
queryset = super(UserAdmin, self).get_queryset(request)
# you logic here to `annotate`the queryset with income
return queryset
Documentation on aggregation:
https://docs.djangoproject.com/en/dev/topics/db/aggregation/
Without me really understanding your models and business logic.. here's a snippet from my own code as an example:
class AuthorAdmin(admin.ModelAdmin):
list_display = ('__str__', 'books_count',)
def books_count(self, obj):
return obj.books_count
def get_queryset(self, request):
return super(AuthorAdmin, self).get_queryset(
request).annotate(books_count=Count('books'))

Django Admin: add inlines dynamically

class MyTemplateAdmin(admin.ModelAdmin):
list_display = ('name')
search_fields = ['name']
inlines = [
Template1Inline,
Template2Inline,
Template3Inline,
]
This works fine. But what I need is to make it dynamic. Whenever the admin adds a new Template to the MyTemplate Model, that needs to be added to the inlines.
Is there a way to do this? Please comment if I am not clear enough on my question.
Thanks in advance!
Just Override the admin's get_inline_instances.
def get_inline_instances(self, request, obj=None):
_inlines = super().get_inline_instances(request, obj=None)
custom_inline = YourDynamicInline(self.model, self.admin_site)
_inlines.append(custom_inline)
return _inlines
I haven't tested this, but in theory you could do:
class MyTemplateAdmin(admin.ModelAdmin):
def __init__(self, *args, **kwargs):
super(MyTemplateAdmin, self).__init__(*args, **kwargs)
#see if there are new templates
#and set the inlines list property
list_display = ('name')
search_fields = ['name']
Hope that helps you out.
In admin.py for the Templates:
class Template1Inline(admin.TabularInline)
pass
class Template2Inline(admin.TabularInline)
pass
Then in the admin.py for MyTemplateAdmin:
import sys, inspect, Templates.admin
class MyTemplateAdmin(admin.ModelAdmin):
list_display = ('name')
search_fields = ['name']
def __init__(self, *args, **kwargs):
inlines = [class_type[1] for class_type in inspect.getmembers(Templates.admin, inspect.isclass)]
super(MyTemplateAdmin, self).__init__(*args, **kwargs)
Templates.admin may not be correct depending on how you have your project setup, but the point is you just import the module that has the Template1Inline classes.
Just a quick idea.
from django.contrib import admin
from mymodule import signals
class MyModuleAdmin(admin.ModelAdmin):
def add_view(self, *args, **kwargs):
signals.my_dynamic_inline_hook_signal.send(
sender = self,
inlines = self.inlines,
args = args,
kwargs = kwargs
)
I'm not completely sure this is what you are looking for. You want inlines that are different instances of the same model?
One way of creating the inlines dynamically is with type() and adding them in get_inline_instances()
class MyTemplateAdmin(admin.ModelAdmin):
list_display = ('name')
search_fields = ['name']
inlines = [some_other_inline]
def get_inline_instances(self, request, obj=None):
new_inlines = []
for inline in (Template, Template2,Template3, ...): # I don't know how you want to get these.
attrs = {
'model': MyTemplate,
# 'extra': 1, Add extra attributes
}
# Create a new uninstanciated inline class
new_inlines.append(type('{}Inline'.format(inline),
(admin.TabularInline, ), attrs))
# Add the dynamically created inlines along with the ordinary.
self.inlines = self.inlines + new_inlines
return super(CommunityAdmin, self).get_inline_instances(request, obj)

Categories