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)
Related
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.
When a field is null in the database, Django inserts "(None)" to hold the place of the null when displaying a changelist. While descriptive, when there are lots of fields on a changelist, it makes everything very busy to look at, where as a blank field would be just as helpful but much less cluttered. So is there some way to change the text Django uses for representing null fields in the changelist? Doesn't matter if the solution is modeladmin-specific or admin wide.
Should also add that I am aware of the solution where you define custom fields and then output a blank string. That works, but in makes the column unsortable, and that is a priority before display, so it's not an option.
Starting with Django 1.9 this behavior has changed and some custom functionality was added to support a solution to the situation you describe.
With Django 1.9, Django now uses a '-' (dash) instead of "(None)" to show NULLs in the Django admin.
In addition you can now customize this default '-' (dash) display for the Django admin with the empty_value_display : globally, for a specific admin class or a specific field:
Globally:
# In settings.py to show '???' instead of '-' for all null django admin values
from django.contrib import admin
admin.site.empty_value_display = '???'
For all fields in a Django admin class:
# admin.py to show "Unknown Item field" instead of '-' for null values in all Item fields
class ItemAdmin(admin.ModelAdmin):
empty_value_display = 'Unknown Item field'
For a single field:
# admin.py to show "No known price" instead of '-' just for null price values in Item
class ItemAdmin(admin.ModelAdmin):
list_display = ('name','price_view')
def price_view(self, obj):
return obj.price
price_view.empty_value_display = 'No known price'
You can override the individual ModelAdmin behavior with this workaround:
from django.contrib.admin.views import main
...
...
...
class MyModelAdmin(admin.ModelAdmin):
def __init__(self,*args,**kwargs):
super(MyModelAdmin, self).__init__(*args, **kwargs)
main.EMPTY_CHANGELIST_VALUE = '-'
Note: Overriding the __init__() is incompatable with the #admin.register() decorator, instead you will need to call admin.site.register(Model, ModelAdmin) after the Model class is defined.
in tabular admin, i want to provide direct link to editing a model which is in a foreignkey of my record.
it works fine when i explicitly defined the admin fields, using reverseurl, like this:
class MediaInline(admin.TabularInline):
fieldsets = [
(None, {'fields': ['media', 'media_id',...
]
readonly_fields = ['media_id']
...
def media_id(self, object):
url = reverse('admin:%s_%s_change' %(object._meta.app_label, 'medialinks'), args=[object.media.id] )
return u'%s' %(url, object.media.id)
media_id.allow_tags = True
But, now i want to define the tabular using a form and i did not find how can do it anymore. i have the HTMl tag as a string but i did not find a way to see it as an HTML tag.
btw, The reason i need a form and not an explicit definition is that i want to be able to order another dropdown field in this tabular list and the only way i found how to do that is in form setting.
A modelform should not prevent you from doing this.
Make sure you don't move this code. You can't put field override code inside a ModelForm.
You use a ModelForm and have the overrides in the ModelAdmin (TabularInline).
I want to add a text next to a field of the django admin interface.
The warning needs to created at runtime inside a python method. I know python and the django ORM well, but I don't know how to get the text next the field.
The text should be a warning. Raising ValidationError in clean() is not a solution, since
the user can't edit the page any more. It should be just a warning message.
You can use custom ModelForm subclass for the admin, adding help_text attribute for the field in question at its initialization, and style it appropriately.
# forms.py
class YourModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(YourModelForm, self).__init__(*args, **kwargs)
self.fields['field_in_question'].help_text = generate_warning()
# admin.py
class YourModelAdmin(admin.ModelAdmin):
form = forms.YourModelForm
# And here you can specify custom CSS / JS which would make
# `help_text` for that particular field look like a warning.
# Or you can make it generic--say, style (and maybe reposition w/js) all tags
# like <span class="warning"> that occur within the help text of any field.
class Media:
css = {"all": ("admin_warning.css", )}
js = ("admin_warning.js", )
If you want to do it in changelist view, you can write in model method, which returns string in format you want, and put name of that method in list_display in admin.
class MyModel(models.Model):
myfield = models.CharField(max_length=100)
def myfield_with_warning(self):
return '%s - %s' % (self.myfield, '<span class="warn">My warning message</p>'
myfield_with_warning.short_description = 'My field verbose name'
myfield_with_warning.allow_tags = True
class MyModelAdmin(models.ModelAdmin):
list_display = ('myfield_with_warning',)
If it's not what you need, write more precisely, where do you want to display warning message.
I think the simplest way would be to override the specific admin page for that model. This is described here in the Django documentation. The template you need to override is probably change_form.html. Within these template displayed object is available in the template variable original.
I would add a method or property to you model, that generates and returns the error message and call this method from the template.
Edit: Have a look at contrib/admin/templates/admin/change_form.html there is a include for includes/fieldset.html that displays the the fields of the admin site. You could put some code there that chckes if the model has some special named attribute and if so it is displayed. You could them simply override that change_form.html for all models with your custom one.
I'm using a Django ModelForm where my model contains a BooleanField and the form widget associated with that BooleanField is a RadioSelect widget. I'd like the the RadioSelect widget that renders to have no options selected so the user has to explicitly make a choice, but the form validation to fail if they make no selection. Is there a way to do this?
models.py
myboolean = models.BooleanField(choices=YES_NO)
forms.py
class myModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(myModelForm, self).__init__(*args, **kwargs)
self.fields['myboolean'].widget = forms.RadioSelect(choices=YES_NO)
Your code actually does what you need. It renders the radio buttons with no options selected and generate the error message if nothing is selected.
A small note about your form code. I would do it like this:
class myModelForm(forms.ModelForm):
myboolean = forms.BooleanField(widget=forms.RadioSelect(choices=YES_NO))
class Meta:
model = MyModel
Unfortunately, this is less of a Django issue than an HTML question. The HTML specification (RFC1866) says:
At all times, exactly one of the radio buttons in a set is checked. If none of the <INPUT> elements of a set of radio buttons specifies `CHECKED', then the user agent must check the first radio button of the set initially.
However, browsers have historically ignored this and implemented radio buttons in different ways.
HTML also makes this difficult because the "checked" attribute of the <INPUT> tag doesn't take a parameter, so you can't use a customized Django widget that sets this attribute to False or No.
A possible workaround is to put in a little Javascript that runs as part of the document's onLoad event that finds all the radio buttons on the page and sets the 'checked' attribute to false (using JQuery, for example).
see this:
http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#a-full-example
I creates custom field with default widget.
Cut of my models.py:
class Order(models.Model):
...
# transport = models.CharField(choices=transport.choices,max_length=25,null=True)
transport = SelectField(choices=transport.choices,max_length=25,null=True)
...
Field definition:
from django.db import models
from django.forms import widgets
class SelectField(models.CharField):
def formfield(self, **kwargs):
if self._choices:
defaults = {'widget': widgets.RadioSelect}
defaults.update(kwargs)
return super(SelectField, self).formfield(**defaults)