Django: how to add links to my admin site - django

I have this code in my admin-site,
#admin.register(StudentsEnrollmentRecord)
class StudentsEnrollmentRecord(admin.ModelAdmin):
list_display = ('Student_Users', 'School_Year', 'link',)
ordering = ('Education_Levels',)
list_filter = ('Student_Users',)
Django-adminsite
i just want to add an html_link here and filter what studentenrollmentrecord selected

You can create a function to be used as field:
#admin.register(StudentsEnrollmentRecord)
class StudentsEnrollmentRecord(admin.ModelAdmin):
list_display = ('Student_Users', 'School_Year', 'link_display',)
ordering = ('Education_Levels',)
list_filter = ('Student_Users',)
def link_display(self, obj):
your_url = '' # Define your URL here
return 'link'.format(your_url)
link_display.allow_tags = True
link_display.short_description = 'link'
The function receive the current object as first parameter (obj).
You need to set the allow_tags property to render your link.
You can optionally customize the description (displayed in the header) with short_description.

Related

How to add foreign-key column to dj-stripe admin?

I would like to add plan names to dj-stripe django admin so I can see a readable name for what each subscription is associated with. Adding "cancel_at" worked, but I can't use the name of a Product from a Plan.
In my_app\admin.py I do this:
from djstripe.models import Subscription
from djstripe.admin import StripeModelAdmin, SubscriptionItemInline
...
class SubscriptionAdmin(StripeModelAdmin):
list_display = ("plan__product__name", "customer", "status", "cancel_at")
list_filter = ("status", "cancel_at_period_end")
list_select_related = ("customer", "customer__subscriber")
inlines = (SubscriptionItemInline,)
def _cancel(self, request, queryset):
"""Cancel a subscription."""
for subscription in queryset:
subscription.cancel()
_cancel.short_description = "Cancel selected subscriptions" # type: ignore # noqa
actions = (_cancel,)
admin.site.unregister(Subscription)
admin.site.register(Subscription, SubscriptionAdmin)
...
Which produces this error:
Subscription has no field named 'plan__product__name'
How do I add extra columns in dj-stripe that require foreign key lookups?
One solution is to make a callable then reference it in the modeladmin class.
Per the docs:
ModelAdmin.list_display
Set list_display to control which fields are displayed on the change list page of the admin.
There are four types of values that can be used in list_display. All but the simplest may use the display() decorator is used to
customize how the field is presented:
A callable that accepts one
argument, the model instance. For example:
#admin.display(description='Name')
def upper_case_name(obj):
return ("%s %s" % (obj.first_name, obj.last_name)).upper()
class PersonAdmin(admin.ModelAdmin):
list_display = (upper_case_name,)
Which means in my case I can do this to add a combined tier + interval column:
#admin.display(description='Subscription Tier and Interval')
def subscription_tier_interval(obj):
return ("%s - %s" % (obj.plan.product.name, obj.plan.interval))
class SubscriptionAdmin(StripeModelAdmin):
list_display = ("customer", "status", subscription_tier_interval, "cancel_at")
list_filter = ("status", "cancel_at_period_end")
list_select_related = ("customer", "customer__subscriber")
inlines = (SubscriptionItemInline,)
def _cancel(self, request, queryset):
"""Cancel a subscription."""
for subscription in queryset:
subscription.cancel()
_cancel.short_description = "Cancel selected subscriptions" # type: ignore # noqa
actions = (_cancel,)
admin.site.unregister(Subscription)
admin.site.register(Subscription, SubscriptionAdmin)

Django-filter get all records when a specific value for a filter_field is passed

I am using django-filter to filter my Queryset on the basis of url params.
class WorklistViewSet(ModelViewSet):
serializer_class = MySerializer
queryset = MyModel.objects.all()
filter_backends = [DjangoFilterBackend, ]
filterset_fields = ['class', ]
# possible values of *class* which is allowed to be passed in the url params are ['first', 'second', 'ALL'].
class MyModel(BaseModel):
CLASS_CHOICES = (
(FIRST_CLASS, 'first'),
(SECOND_CLASS, 'second'),
)
class = models.CharField(choices=CLASS_CHOICES, max_length=3, )
URLs http://127.0.0.1:8000?class=first and http://127.0.0.1:8000?class=first are giving the expected results.
I want that when http://127.0.0.1:8000?class=ALL is called, all the records in my table should be listed i.e without filtering.
How can i do this while using django-filter ?
You may want to use Filter.method, as explained in the docs.
In your case, I would do as follows:
class F(django_filters.FilterSet):
klass = CharFilter(method='my_custom_filter')
class Meta:
model = MyModel
fields = ['klass']
def my_custom_filter(self, queryset, name, value):
if value == 'ALL':
return queryset
return queryset.filter(**{
name: value,
})
Be also reminded that class is a reserved word in Python and cannot be used as a variable name. I've used klass instead, although that's used as something else in many Python books and may be confusing.

django admin list sum fields

I'd like to combine the same table data from the inventory admin page list.
My admin.py is as follows
admin.py
class CounselAdmin(admin.ModelAdmin):
list_display = ('counsel_idx', 'show_firm_url', 'answer_count', 'counsel_status', 'deleted', 'register_date',)
search_fields = ('counsel_status',)
list_filter = ('counsel_status',)
def show_firm_url(self, obj):
return format_html("<a href='/admin/counsel/view/{0}'>{1}</a>", obj.counsel_idx, obj.counsel_title)
show_firm_url.short_description = 'title'
For example, I would like to put it together in this way
show_firm_url
The data in show_firm_url is = TITLE TEST
answer_count is = 7
in case of
TITLE TEST (answercount 7)
I want it to come out together like a stomach.
Please help me.
You can try like this:
class CounselAdmin(admin.ModelAdmin):
list_display = ('show_firm_url', 'counsel_idx', 'show_firm_url', 'answer_count', 'counsel_status', 'deleted', 'register_date',)
search_fields = ('counsel_status',)
list_filter = ('counsel_status',)
def show_firm_url(self, obj):
return format_html("<a href='/admin/counsel/view/{0}'>{1}(answercount {2})</a>", obj.counsel_idx, obj.counsel_title, obj.answer_count)
show_firm_url.short_description = 'title'

Django- filtering of the filter object

I want to make a complex filtering on the page using the FilterSets. This is my Filterset, nicely showing me tuples from chosen time and with chosen parameters.
# filters.py
class workFilter(filters.FilterSet):
start__gt = filters.DateTimeFilter(name='time_start', lookup_expr='gte')
start__lt = filters.DateTimeFilter(name='time_end', lookup_expr='lte')
class Meta:
model = Work
fields = ('machine', 'program')
But I want to add charts explaining the queried data. For that I need informations, like overall count of time. I am querying them like that:
#views.py
def search(request):
work_list = Work.objects.all()
work_filter = workFilter(request.GET, queryset=work_list)
filter_backends = (filters.DjangoFilterBackend,)
#some queries to add to context, such as
sum_work = Work.objects.aggregate(Sum('time'))['time__sum']
return render_to_response(
TEMPLATE_DIRS + 'index.html',
{
'filter': praca_filter,
'sum_work': sum_work,
}
)
But sadly, those queries are according to whole database, not to my filtered set of object.
How can I make queries on filtered set work_filter?
Define sum_work as a property of your FilterSet.
class WorkFilter(filters.FilterSet):
start__gt = filters.DateTimeFilter(name='time_start', lookup_expr='gte')
start__lt = filters.DateTimeFilter(name='time_end', lookup_expr='lte')
class Meta:
model = Work
fields = ('machine', 'program')
#property
def work_sum(self):
qs = super(WorkFilter, self).qs
return qs.aggregate(Sum('time'))['time__sum']
Then when you pass your filter through to your view you just need {{ filter.work_sum }} in your template.

django admin - custom fields radio - admin.HORIZONTAL not working

I have this custom field image_choice in django admin as a radio select.
IMG_CHOICES = (
('embed', _('Embed code')),
('file', _('Upload image')),
('link', _('Image Link'))
)
class BlogArticleForm(forms.ModelForm):
class Media:
js = ('js/myjs.js')
image_choice = forms.ChoiceField(choices=IMG_CHOICES, widget=forms.RadioSelect)
class BlogArticleAdmin(admin.ModelAdmin):
form = BlogArticleForm
fields = ['title', 'description', 'image_choice', 'image_embed', 'image_file', 'image_link']
admin.site.register(models.BlogArticle, BlogArticleAdmin)
I cannot get these radio buttons line up horizontally.
I tried:
radio_fields = {'image_choice': admin.HORIZONTAL}
and
radio_fields = {form.image_choice: admin.HORIZONTAL}
but I keep getting this error:
type object "BlogArticleForm" has no attribute 'image_choice'
how can I achieve this?
this is how it looks like right now:
Take a look at this line.
So I guess it should look something like this:
from django.contrib.admin.options import get_ul_class
class BlogArticleForm(forms.ModelForm):
image_choice = forms.ChoiceField(
choices=IMG_CHOICES,
widget=widgets.AdminRadioSelect(
attrs={'class': get_ul_class(admin.HORIZONTAL)}
))
UPD: I'm stupid :(
It says: if 'widget' not in kwargs: bla-bla-bla adds widget. So this should work with no widget:
image_choice = forms.ChoiceField(choices=IMG_CHOICES)
# And set
radio_fields = {'image_choice': admin.HORIZONTAL}