I have a TabularInline admin layout, all works fine except I'd like to have it show something other than the Obj.__unicode__ value on the top left of each row.
My TabularInline is a photologue ImageModel model, so I'd like it to show me the thumbnail instead of the regular __unicode__ result.
I tried to change __unicode__ to output the thumbnail, which works, except the HTML is escaped so I get <img src="XXX"...... etc
Is there an easy way to mark my __unicode__ method as a safe string? Or a way to override the property the admin chooses to display?
I've tried this:
__unicode__.is_safe = True
But that doesn't work.
You can customize the template for you TabularInline to make it look the way you want. I think it's a better idea then hacking __unicode__:
class PhotoInline(admin.TabularInline):
model = Photo
template = 'photologue/photoinline.html'
The easiest way to create your is to copy and customize the default django/contrib/admin/templates/admin/edit_inline/tabular.html template.
Related
I have a model method in Django that I am displaying on an admin page just like I would a model field. With a field, I can just add a help_text argument to it to give a description of what the field is and what the user should put into it. However, with a model method, help_text does not work. Adding the attribute short_description changes the way the method name is displayed, which is sort of okay, but I'm looking for a way to add a few sentences of description beneath the method value that is displayed. Is there any way to do this natively, or would I have to resort to overriding admin templates or something? (Which I do not think is worth it for something this minor).
You can do this using JS.
Replace ID-OF-THE-FIELD with the actual id of the desired field.
(function($) {
var myField = $('#ID-OF-THE-FIELD');
// find the id of the desired field by doing
// Right-Click > Inspect element
var help = $('<p class="help">A very long help text</p>');
help.insertAfter(myField);
})(django.jQuery);
Put this code into a JS file and supply this file using class Media of your ModelAdmin class.
In Django (we are currently using 1.9), when we add an UrlField to a model, the Admin site correctly renders the UrlField value as a clickable link on edit views.
If we were to mark this UrlField as readonly (through the ModelAdmin readonly_fields attribute), the value is then displayed as non-clickable plain text.
What is a rationale for this behaviour ?
Is there a way to work around it without changing the widget for the associated form field ?
I think it's just that readonly_fields displays the raw content (using the __str__() method) without any widget.
To work it around you might do something like this:
class MyAdmin (ModelAdmin):
readonly_fields = ['myurl_link']
def myurl_link(self, instance):
return format_html('<a href="{url}" target=_blank>{url}</a>', url=instance.myurl)
myurl_link.short_description = _("Website")
In Django admin, if I have a model field that's a TextField and set it as readonly using readonly_fields, then it's displayed as text in a <p> tag.
I'd like it to still be displayed as a textarea field, but with its disabled attribute set.
What's the simplest way to accomplish this?
use a form field
somefield = forms.CharField(
widget=forms.TextInput(attrs={'readonly':'readonly'})
)
A bit late, but here's an idea (inspired by #cinoch`s answer and this answer) that does the trick for me, with a minimum of code:
do not add the name of your TextField to the readonly_fields in your ModelAdmin subclass (otherwise step 2 has no effect)
instead, do add the following to your ModelAdmin subclass:
formfield_overrides = {
TextField: dict(widget=Textarea(attrs=dict(readonly=True)))
}
Note this requires some imports:
from django.db.models import TextField
from django.forms import Textarea
The TextField will now show up on the admin page as a scrollable Textarea instead of plain text, and its content will now be read-only, as desired.
Downside is that this applies to all TextFields in the model. If that's a problem, you should probably use a custom form as suggested by #cinoch and described in more detail here or here.
Also, this has no effect if ModelAdmin.has_change_permission() returns False.
The readonly_fields can take method names as well as field names. You could write a method that renders the value of the field in a disabled textarea.
Make sure you exclude the field from the model admin, since it will no longer be in readonly_fields.
#alasdair's answer is actually quite clever, but, unfortunately, it does not provide an example.
Here's my attempt to clarify, based on the docs for readonly_fields.
Assuming a model like so:
class MyModel(models.Model):
my_textfield = models.TextField()
The admin could look like this, using format_html to create a readonly textarea:
class MyModelAdmin(admin.ModelAdmin):
exclude = ['my_textfield']
readonly_fields = ['display_my_textfield']
#admin.display(description='my textfield')
def display_my_textfield(self, obj):
return format_html(
'<textarea cols="40" rows="10" readonly>{}</textarea>',
obj.my_textfield)
This also works if ModelAdmin.has_change_permission() returns False.
In the django admin I have a TabularInline for a ManyToMany field with a raw_id_fields set. It displays the unicode() of the object next to the html input field.
I would like it to display the an email link. So in the unicode() function of the model, I put in the html tags to create a link. However, it is displaying the html tags.
Is there a way to tell the admin that the unicode is safe to display tags?
I've tried using the allow_tags property but that seems to only be a ModelAdmin property.
Is it possible to do this without creating a new template?
EDIT:
I've found exactly where this is happening. On line 159 of:django/contrib/admin/widgets.py
return ' <strong>%s</strong>' % escape(truncate_words(obj, 14))
The escape there is manually escaping it. I've tested removing the escape() and it works. I don't like the idea of editing the django source. How could I get around this without change the source?
If your aim is to just display an email link for the list view, i would suggest writing a custom column for the list view like this:
list_display = ('admin_email', ...)
def admin_email(self, object):
return '%s'%(admin.email, admin)
admin_email.allow_tags = True
admin_email.short_description = 'Send Email'
This is better because you might be using the unicode call at a lot of other places, and the html might cause problems there.
Here is an example, with same end result as sebpiq's using SafeUnicode, "A unicode subclass that has been specifically marked as 'safe' for HTML output purposes."
e.g.
from django.utils.safestring import SafeUnicode
class SomeClass(models.Model):
...
def __unicode__(self):
return SafeUnicode("foo: %s<br>bar: %s" % (foo, bar))
You should try mark_safe on the value that you return. Then the string shouldn't be escaped anymore !
Let's say I have a model with a field based on the ImageField class.
class Foo(models.Model):
imagefile = models.ImageField('File', upload_to='foo/%Y/%m%/%d/')
Django adds - after first upload - an input tag of type file to let me change it and a link to the image to view it.
I want this original field specific (HTML) code as is (and by no means create it myself manually) but also add other HTML/JS code, say to include a thumbnail-preview or add some AJAX-stuff. I can image a few other use cases for other fields, too.
What's the correct (say: easy/unobtrusive) way to implement something like that?
You need to write a custom widget. Look at django.forms.widgets for the code of the existing FileInput widget, which you can subclass and override the render method where necessary. You'll then just need to assign that widget for your file field in your admin form.