Django admin site add html link - django

admin.py
#admin.register(StudentsEnrollmentRecord)
class StudentsEnrollmentRecord(admin.ModelAdmin):
list_display = ('Student_Users', 'School_Year', 'Report')
ordering = ('Education_Levels',)
list_filter = ('Student_Users',)
I just want that to add the html link in the adminsite then if the admin click the "report" it will filter what studentenrollmentrecord selected to html file

You need to create a method to calculate this field for each entry in the list, as follows:
from django.utils.html import format_html
#admin.register(StudentsEnrollmentRecord)
class StudentsEnrollmentRecord(admin.ModelAdmin):
list_display = ('Student_Users', 'School_Year', 'report')
...
def report(self, obj):
return format_html(f'<a href={pass_link_here}>Report</a>')
Those kinds of methods take actual objects as a parameter, you can use it to create different links for different objects. obj.field_name

Related

Django admin: Change the displayed value of a key

i have a model that includes a key "service_id" and the values stored in database are like "10001", i want to add a method to admin page that instead of displaying the id it displays a custom value like "Car Wash".
I think you need to create a custom field to be added in your list_display
from django.contrib import admin
#admin.register(MyModelClass)
class MyModelClassAdmin(admin.ModelAdmin):
list_display = ('my_field')
def my_field(self, obj):
return obj.description().title()
my_field.short_description = "My field"
You can change the value returned by the my_field method as you prefer (take into consideration that you can use the obj instance).
Create an Admin Class following
class ModelclassNameAdmin(admin.ModelAdmin):
list_display = ('service__name', [other fields])
in it for list display use double underscore __ for accessing field inside foreign key like service__name
and while registering the model add admin as second argument.
admin.site.register(ModelclassName, ModelclassNameAdmin)

Django admin: don't send all options for a field?

One of my Django admin "edit object" pages started loading very slowly because of a ForeignKey on another object there that has a lot of instances. Is there a way I could tell Django to render the field, but not send any options, because I'm going to pull them via AJAX based on a choice in another SelectBox?
You can set the queryset of that ModelChoiceField to empty in your ModelForm.
class MyAdminForm(forms.ModelForm):
def __init__(self):
self.fields['MY_MODEL_CHOIE_FIELD'].queryset = RelatedModel.objects.empty()
class Meta:
model = MyModel
fields = [...]
I think you can try raw_id_fields
By default, Django’s admin uses a select-box interface () for fields that are ForeignKey. Sometimes you don’t want to incur the overhead of having to select all the related instances to display in the drop-down.
raw_id_fields is a list of fields you would like to change into an Input widget for either a ForeignKey or ManyToManyField
Or you need to create a custom admin form
MY_CHOICES = (
('', '---------'),
)
class MyAdminForm(forms.ModelForm):
my_field = forms.ChoiceField(choices=MY_CHOICES)
class Meta:
model = MyModel
fields = [...]
class MyAdmin(admin.ModelAdmin):
form = MyAdminForm
Neither of the other answers worked for me, so I read Django's internals and tried on my own:
class EmptySelectWidget(Select):
"""
A class that behaves like Select from django.forms.widgets, but doesn't
display any options other than the empty and selected ones. The remaining
ones can be pulled via AJAX in order to perform chaining and save
bandwidth and time on page generation.
To use it, specify the widget as described here in "Overriding the
default fields":
https://docs.djangoproject.com/en/1.9/topics/forms/modelforms/
This class is related to the following StackOverflow problem:
> One of my Django admin "edit object" pages started loading very slowly
> because of a ForeignKey on another object there that has a lot of
> instances. Is there a way I could tell Django to render the field, but
> not send any options, because I'm going to pull them via AJAX based on
> a choice in another SelectBox?
Source: http://stackoverflow.com/q/37327422/1091116
"""
def render_options(self, *args, **kwargs):
# copy the choices so that we don't risk affecting validation by
# references (I hadn't checked if this works without this trick)
choices_copy = self.choices
self.choices = [('', '---------'), ]
ret = super(EmptySelectWidget, self).render_options(*args, **kwargs)
self.choices = choices_copy
return ret

django admin list_display textfield

I've a Textfield defined in model.py
In the changelist data are shown as single line instead
in the change view of the object, the data are rendered in a:
vLargeTextField
the break lines are mantained as in the user input.
es.
hi,
nice to meet you,
I need a break
Is there something special to allow the list_display to show the data as in the change view?
You can render breaks as html (the linebreaks templatetag make it easy, or surround with the html pre tag i.e. <pre>... (your_text) ...</pre>) and set the allow_tags property to True for this field within your admin class definition.
admin.py
class CustomAdmin(admin.ModelAdmin):
model = YourModel
list_display = ['your_large_text_field__custom_rendering']
def your_large_text_field__custom_rendering(self, obj):
return "<pre>%s</pre>" % (obj.your_large_text_field,)
your_large_text_field__custom_rendering.allow_tags = True
admin.site.register(YourModel, CustomAdmin)

Django admin: Default model display problem

In django models, if we have
def __unicode__(self): then it will be used as how you want to display the model by default
Now in django admin, I want to have a custmized display field(showing this object as an url so can navigate to this object), but I can't change unicode method for it used for other purpose. What do I supposed to do?
You can create a custom method for admin class
class SomeModelAdmin(admin.ModelAdmin):
list_display = ('__unicode__', 'active_status')
def active_status(self, obj):
if obj.profile.is_active:
return """One"""
return """Two"""
active_status.allow_tags = True
active_status.description = ""
This is just very simple example, so you can put your logic into this function
You can also return some html code
Don't use __unicode__ for a purpose like setting a convenience URL.
That will obscure your printed object name for any other purpose.
From which view are you trying to create a link? From the changelist view? From the change view? From a foreign key?
In general, you can simply define any method on your model (or ModelAdmin), that returns a full HTML link <a href=, set allow_tags = True, and refer to it in your admin fields.
# models method
def admin_url(self):
return 'Edit Model' % the_url
admin_url.allow_tags = True
# ModelAdmin method, through ForeignKey
def admin_url(self, obj):
return 'Edit Model' % obj.foreignkey.url
admin_url.allow_tags = True
I agree with those answers, but on my machine just not working.
I was using Python3 and Django1.8, and try to use this.
class MyModel(models.Model):
name = models.CharField(max_length=60)
def __str__(self):
return 'MyModel: {}'.format(self.name)

Foreign keys in django admin list display

If a django model contains a foreign key field, and if that field is shown in list mode, then it shows up as text, instead of displaying a link to the foreign object.
Is it possible to automatically display all foreign keys as links instead of flat text?
(of course it is possible to do that on a field by field basis, but is there a general method?)
Example:
class Author(models.Model):
...
class Post(models.Model):
author = models.ForeignKey(Author)
Now I choose a ModelAdmin such that the author shows up in list mode:
class PostAdmin(admin.ModelAdmin):
list_display = [..., 'author',...]
Now in list mode, the author field will just use the __unicode__ method of the Author class to display the author. On the top of that I would like a link pointing to the url of the corresponding author in the admin site. Is that possible?
Manual method:
For the sake of completeness, I add the manual method. It would be to add a method author_link in the PostAdmin class:
def author_link(self, item):
return '%s' % (item.id, unicode(item))
author_link.allow_tags = True
That will work for that particular field but that is not what I want. I want a general method to achieve the same effect. (One of the problems is how to figure out automatically the path to an object in the django admin site.)
I was looking for a solution to the same problem and ran across this question... ended up solving it myself. The OP might not be interested anymore but this could still be useful to someone.
from functools import partial
from django.forms import MediaDefiningClass
class ModelAdminWithForeignKeyLinksMetaclass(MediaDefiningClass):
def __getattr__(cls, name):
def foreign_key_link(instance, field):
target = getattr(instance, field)
return u'%s' % (
target._meta.app_label, target._meta.module_name, target.id, unicode(target))
if name[:8] == 'link_to_':
method = partial(foreign_key_link, field=name[8:])
method.__name__ = name[8:]
method.allow_tags = True
setattr(cls, name, method)
return getattr(cls, name)
raise AttributeError
class Book(models.Model):
title = models.CharField()
author = models.ForeignKey(Author)
class BookAdmin(admin.ModelAdmin):
__metaclass__ = ModelAdminWithForeignKeyLinksMetaclass
list_display = ('title', 'link_to_author')
Replace 'partial' with Django's 'curry' if not using python >= 2.5.
I don't think there is a mechanism to do what you want automatically out of the box.
But as far as determining the path to an admin edit page based on the id of an object, all you need are two pieces of information:
a) self.model._meta.app_label
b) self.model._meta.module_name
Then, for instance, to go to the edit page for that model you would do:
'../%s_%s_change/%d' % (self.model._meta.app_label, self.model._meta.module_name, item.id)
Take a look at django.contrib.admin.options.ModelAdmin.get_urls to see how they do it.
I suppose you could have a callable that takes a model name and an id, creates a model of the specified type just to get the label and name (no need to hit the database) and generates the URL a above.
But are you sure you can't get by using inlines? It would make for a better user interface to have all the related components in one page...
Edit:
Inlines (linked to docs) allow an admin interface to display a parent-child relationship in one page instead of breaking it into two.
In the Post/Author example you provided, using inlines would mean that the page for editing Posts would also display an inline form for adding/editing/removing Authors. Much more natural to the end user.
What you can do in your admin list view is create a callable in the Post model that will render a comma separated list of Authors. So you will have your Post list view showing the proper Authors, and you edit the Authors associated to a Post directly in the Post admin interface.
See https://docs.djangoproject.com/en/stable/ref/contrib/admin/#admin-reverse-urls
Example:
from django.utils.html import format_html
def get_admin_change_link(app_label, model_name, obj_id, name):
url = reverse('admin:%s_%s_change' % (app_label, model_name),
args=(obj_id,))
return format_html('%s' % (
url, unicode(name)
))