How can I change titles in action section in Django admin panel? - django

I want to change titles in action section in Django admin. How can I do that?

The description [GitHub] is defined in the django.contrib.admin.actions module with:
#action(
permissions=["delete"],
description=gettext_lazy("Delete selected %(verbose_name_plural)s"),
)
def delete_selected(modeladmin, request, queryset):
# …
It takes the verbose_name_plural of the model. You thus can change the verbose_name_plural with:
class Article(models.Model):
# …
class Meta:
verbose_name_plural = 'publications'
# …
or you can make a translation file that translates it to something else, but you are limited to what the Django modeladmin passes to the formatter.

Related

Django Admin foreign key, more detailed

Im trying to customise my admin. I have a model with a foreign key to an another model. I currently have a dropdown that display a list of possible keys to chose from, but the list only shows the title.
model.py
class Equipment(models.Model):
noequipment = models.IntegerField('Equipment #' ,db_column='Noequipment', primary_key=True) # Field name made lowercase.
nom = models.CharField('Name',db_column='Nom', max_length=50, blank=True) # Field name made lowercase.
...
nooffice = models.ForeignKey('Office', db_column='NoOffice', blank=True, null=True, verbose_name='Office') # Field name made lowercase.
...
class Meta:
db_table = 'equipment'
ordering = ('nom',)
def __str__(self):
return self.nom
class Office(models.Model):
nooffice = models.IntegerField(db_column='NoOffice', primary_key=True) # Field name made lowercase.
officename = models.CharField(db_column='OfficeName', max_length=50, blank=True) # Field name made lowercase.
adresse = models.CharField(db_column='Adresse', max_length=50, blank=True) # Field name made lowercase.
ville = models.CharField(db_column='Ville', max_length=50, blank=True) # Field name made lowercase.
codepostal = models.CharField(db_column='CodePostal', max_length=50, blank=True) # Field name made lowercase.
class Meta:
db_table = 'office'
def __str__(self):
return self.officename
All I need is that the admin would show a table with the attribute values on top of the drop down.
also here admin.py (Need special ModelAdmin because im using multiple DB as per https://docs.djangoproject.com/en/1.8/topics/db/multi-db/ )
from django.contrib import admin
from .models import Equipment, Manufacturier, Office, Devicetype, Backdoor, Passage, Systadmin, Applicationadmin, Application, Os
from django import forms
from forms import EquipmentAdminForm, ManufacturierAdminForm, OfficeAdminForm, DevicetypeAdminForm, BackdoorAdminForm, PassageAdminForm, SystadminAdminForm, ApplicationadminAdminForm, ApplicationAdminForm, OsAdminForm
class VCOEModelAdmin(admin.ModelAdmin):
# A handy constant for the name of the alternate database.
using = 'vcoe'
def save_model(self, request, obj, form, change):
# Tell Django to save objects to the 'other' database.
obj.save(using=self.using)
def delete_model(self, request, obj):
# Tell Django to delete objects from the 'other' database
obj.delete(using=self.using)
def get_queryset(self, request):
# Tell Django to look for objects on the 'other' database.
return super(VCOEModelAdmin, self).get_queryset(request).using(self.using)
def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
# Tell Django to populate ForeignKey widgets using a query
# on the 'other' database.
return super(VCOEModelAdmin, self).formfield_for_foreignkey(db_field, request=request, using=self.using, **kwargs)
def formfield_for_manytomany(self, db_field, request=None, **kwargs):
# Tell Django to populate ManyToMany widgets using a query
# on the 'other' database.
return super(VCOEModelAdmin, self).formfield_for_manytomany(db_field, request=request, using=self.using, **kwargs)
class VCOETabularInline(admin.TabularInline):
using = 'vcoe'
def get_queryset(self, request):
# Tell Django to look for inline objects on the 'other' database.
return super(VCOEMTabularInline, self).get_queryset(request).using(self.using)
def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
# Tell Django to populate ForeignKey widgets using a query
# on the 'other' database.
return super(VCOEMTabularInline, self).formfield_for_foreignkey(db_field, request=request, using=self.using, **kwargs)
def formfield_for_manytomany(self, db_field, request=None, **kwargs):
# Tell Django to populate ManyToMany widgets using a query
# on the 'other' database.
return super(VCOEMTabularInline, self).formfield_for_manytomany(db_field, request=request, using=self.using, **kwargs)
class OfficeAdmin(VCOEModelAdmin):
form = OfficeAdminForm
class EquipmentAdmin(VCOEModelAdmin):
form = EquipmentAdminForm
...
admin.site.register(Equipment, EquipmentAdmin)
...
admin.site.register(Office, OfficeAdmin)
...
and forms.py
from django import forms
from .models import Equipment, Manufacturier, Office, Devicetype, Backdoor, Passage, Systadmin, Applicationadmin, Application, Os
class EquipmentAdminForm(forms.ModelForm):
class Meta:
model = Equipment
exclude = ['noequipment']
...
class OfficeAdminForm(forms.ModelForm):
class Meta:
model = Office
exclude = ['nooffice']
I see two possible approaches:
The simplest approach is to make __str__ (or __unicode__, depending on Python version) on your model to include extra information you want to see. E.g.:
class Office(models.Model):
...
def __unicode__(self):
return u"{0.officename} ({0.ville}, {0.addresse})".format(self)
The most flexible but most complicated is to create a custom widget. There are some readily available libraries that may or may not suit your needs and tastes. For example, you may consider taking a look at django-autocomplete-light's ModelChoiceField and it`s autocomplete styling options.
The process isn't trivial, but the overall outline is:
Create your own widget class or take something that's readily available.
Create a ModelForm that uses this widget. Some libraries provide a custom fields that are pre-configured to use the widget, if you have a self-implemented one, you can consider writing a field or using Django's built-in ModelChoiceField with widget argument. Some libraries have their own conventions, if you have own implementation, then you can go with something like:
class EquipmentForm(forms.ModelForm):
class Meta:
model = Equipment
widgets = {
"office": OfficeSelectWidget(...)
}
In your ModelAdmin class refer to your form, so Django would use it instead of automatically-generated one.
If you're just experimenting or learning - and have enough time to spare, I suggest go the complicated route and write everything on your own, so you'd know how things work under the hood. Then never do this again, but use batteries from PyPI. If you just want things quick, take a look at abovementioned django-autocomplete-light library, which should be quite simple to get started. Just follow their tutorials and examples, starting from the basic autocomplete field then extending it with custom styling.

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

Get value of field from referenced model displayed in Django Admin site

I have two models - Contract and Supplier. Each supplier supplies a type of commodity. These are defined as follows:
class CommodityType(models.Model):
name = models.CharField(max_length=64)
def __unicode__(self):
return self.name
class Supplier(models.Model):
name = models.CharField(max_length=64)
type = models.ForeignKey(CommodityType)
def __unicode__(self):
return self.name
class Meta:
ordering = ['type', 'name']
class Contract(models.Model):
supplier = models.ForeignKey(Supplier)
clientNumber = models.CharField(max_length=32)
def __unicode__(self):
return u'%s, %s' % (self.supplier, self.clientNumber)
I want to have a listing of the Contracts in the Django Admin site. For each of the Contracts, I want to have the type from the referenced Supplier displayed. So, for example, if the associated supplier supplies Electricity, then I want to have that displayed in the listing of Contracts.
However, I cannot seem to find how this is done. I found this answer, but trying that gives me an ImproperlyConfigured error.
How can this be done?
What you probably need is the list_display
class ContractAdmin(admin.ModelAdmin):
list_display('clientNumber', 'supplier')
admin.register(Contract, ContractAdmin)
To allow __ in Admin for foreign key, You can use this snippet
From the snippet:
from django.contrib import admin
from django.db import models
def getter_for_related_field(name, admin_order_field=None, short_description=None):
"""
Create a function that can be attached to a ModelAdmin to use as a list_display field, e.g:
client__name = getter_for_related_field('client__name', short_description='Client')
"""
related_names = name.split('__')
def getter(self, obj):
for related_name in related_names:
obj = getattr(obj, related_name)
return obj
getter.admin_order_field = admin_order_field or name
getter.short_description = short_description or related_names[-1].title().replace('_',' ')
return getter
class RelatedFieldAdminMetaclass(admin.ModelAdmin.__metaclass__):
"""
Metaclass used by RelatedFieldAdmin to handle fetching of related field values.
We have to do this as a metaclass because Django checks that list_display fields are supported by the class.
"""
def __getattr__(self, name):
if '__' in name:
getter = getter_for_related_field(name)
setattr(self, name, getter) # cache so we don't have to do this again
return getter
raise AttributeError # let missing attribute be handled normally
class RelatedFieldAdmin(admin.ModelAdmin):
"""
Version of ModelAdmin that can use related fields in list_display, e.g.:
list_display = ('address__city', 'address__country__country_code')
"""
__metaclass__ = RelatedFieldAdminMetaclass
def queryset(self, request):
qs = super(RelatedFieldAdmin, self).queryset(request)
# include all related fields in queryset
select_related = [field.rsplit('__',1)[0] for field in self.list_display if '__' in field]
# Include all foreign key fields in queryset.
# This is based on ChangeList.get_query_set().
# We have to duplicate it here because select_related() only works once.
# Can't just use list_select_related because we might have multiple__depth__fields it won't follow.
model = qs.model
for field_name in self.list_display:
try:
field = model._meta.get_field(field_name)
except models.FieldDoesNotExist:
continue
if isinstance(field.rel, models.ManyToOneRel):
select_related.append(field_name)
return qs.select_related(*select_related)
#### USAGE ####
class FooAdmin(RelatedFieldAdmin):
# these fields will work automatically:
list_display = ('address__phone','address__country__country_code','address__foo')
# ... but you can also define them manually if you need to override short_description:
address__foo = getter_for_related_field('address__foo', short_description='Custom Name')
Recently, a library called django-related-admin released, which allows you to use foreign key attributes in Django admin change list list_display with '__' so easily, Specifically for this question, how to use this library in admin.py module is as follows:
admin.py
from related_admin import RelatedFieldAdmin
from related_admin import getter_for_related_field
class ContractAdmin(RelatedFieldAdmin):
# these fields will work automatically (and boolean fields will display an icon):
list_display = ('clientNumber','supplier__type__name')
# or you can also define them manually if you need to override short_description or boolean parameter:
supplierType = getter_for_related_field('supplier__type__name', short_description='supplier type', boolean=False)

Can I use Django model function as a field in admin?

I have a model function that returns a numerical value. I would like to be able to filter and sort by that value. When I tried adding it to list_filter Django complained that the model had no such field. Can I tell Django to treat it like a field? If so, how?
Did you tried to use it as a class property, though I didn't try it?
class SomeModel(models.Model):
#property
def list_filter(self):
""" Do your stuffs here """
You can write a custom filter and pass it in list_filter:
from django.contrib.admin import SimpleListFilter
class CustomFilter(SimpleListFilter):
# Human-readable title which will be displayed in the
# right admin sidebar just above the filter options.
title = _('active status')
# Parameter for the filter that will be used in the URL query.
parameter_name = 'status'
def lookups(self, request, model_admin):
if request.user.is_superuser:
return (
('active', _('Active')),
('not_active', _('Not Active')),
)
def queryset(self, request, queryset):
# do something here with queryset
class MyAdmin(admin.ModelAdmin):
list_filter = (CustomFilter, 'other_model_field')
Please see here for more information about ModelAdmin.list_filter

Add multiple records at once in django admin panel

I have following setup.
from django.db import models
from django.contrib.auth.models import User
class Event(models.Model):
name = models.CharField(max_length=64)
date = models.DateField()
ATTENDANCE_CHOICES = (
('A','Attending'),
('N','Absent'),
('L','Taken ill'),
)
class Attendance(models.Model):
student = models.ForeignKey(User)
event = models.ForeignKey(Event)
status = models.CharField(max_length=1, choices=ATTENDANCE_CHOICES)
In a nutshell: Students(User) attend or doesn't attend classes(Event), this is registered by Attendance.
Problem is adding those attendance records one at a time.
What I am looking for is a way to provide form for each class(each Event object) with list of all students and attendance status radio buttons or drop downs next to them.
Something like this:
http://i.imgur.com/jANIZ.png
I have looked at many discussions about multiple/bulk record insertion via django admin and am beginning to wonder is this even possible with django admin or do I have to create such form from scratch? Either way, what would be the best (most django-ish) approach?
"Is this even possible?" It's possible right out of the box.
Look into the django Admin app, Inlines, ModelForms, and the RadioSelect widget.
class MyForm(forms.ModelForm):
class Meta:
model = Attendance
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs
self.fields['status'].widget = forms.RadioSelect(choices=self.fields['status'].choices)
class AttendanceInline(admin.TabularInline):
model = Attendance
form = MyForm
class EventAdmin(admin.ModelAdmin):
inlines = [AttendanceInline]
def save_model(self, request, obj, form, change):
obj.save()
for user in User.objects.all():
obj.attendance_set.create(user=user, status='')
# you should consider a null field or a possible choice for "Undecided"
admin.site.register(Event, EventAdmin)