Add css class to all admin form field - django

I need to assign a boostrap class to all my user's field in Django admin form, I wrote this code but it does not work.
formfield_overrides = {
models.CharField: {'widget': TextInput(attrs={'class': 'form-control'})},
models.CharField: {'widget': EmailInput(attrs={'class': 'form-control'})},
models.DateField: {'widget': DateTimeInput(attrs={'type': 'date', 'class': 'form-control'})},
models.EmailField: {'widget': EmailInput(attrs={'class': 'form-control'})},
models.BooleanField: {'widget': CheckboxInput(attrs={'class': 'form-control'})},
}
Can you help me?

Your form
#yourapp/forms.py
class YourForm(forms.ModelForm):
class Meta:
model = YourModel
fields = (field1,field2,field3,)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for field in self._meta.fields:
attrs = {'class':'form-control'}
if self.fields[field].widget.__class__.__name__ == "DateTimeInput":
attrs.update({'type':'date'})
self.fields[field].widget.attrs.update(attrs)
Next, admin.py
#yourapp/admin.py
from django.contrib import admin
from .forms import YourForm
from .models import YourModel
class AdminModel(admin.ModelAdmin):
form = YourForm
admin.site.register(YourModel,AdminModel)
You can learn more from the documentation.

If you want to override some of the Field options for use in the admin, please check this for detail: https://docs.djangoproject.com/en/1.11/ref/contrib/admin/#django.contrib.admin.ModelAdmin.formfield_overrides. And the most common use of formfield_overrides is to add a custom widget for a certain type of field.

Related

add my own class in admin field django-cms

Hi everyone Y create my own app in djando CMS, now I want to add my own class and id's to my field.. y try this, but I don't obtain any successful result.
in my model.py I have this
class Entry(models.Model):
TYPES_CHOICES = (
('none', 'not specified'),
('s', 'Series'),
('mb', 'Multiples Bar'),
('b', 'Bar suggestion'),
)
app_config = AppHookConfigField(HealthConfig)
code = models.CharField(blank=True, default='', max_length=250)
url_suggestion = models.CharField(blank=True, default='', max_length=250, verbose_name="URL for Suggestion" )
health_placeholder = PlaceholderField('health_info')
objects = AppHookConfigManager()
def __unicode__(self):
return self.url
class Meta:
verbose_name_plural = 'entries'
and now in my form.py I have this
from django import forms
from .models import Entry
class EntryForm(forms.ModelForm):
class Meta:
model = Entry
fields = '__all__'
def __init__(self, *args, **kwargs):
super(EntryForm, self).__init__(*args, **kwargs)
self.fields['code'].widget.attrs={
'id': 'my_code',
'class': 'code_class',
}
finally my admin.py is like this
from django.contrib import admin
from cms.admin.placeholderadmin import PlaceholderAdminMixin
from .cms_appconfig import HealthConfig
from .models import Entry
from .forms import EntryForm
from aldryn_apphooks_config.admin import ModelAppHookConfig, BaseAppHookConfig
class EntryAdmin(ModelAppHookConfig, PlaceholderAdminMixin, admin.ModelAdmin):
# pass
fieldsets = (
('General data', {
'fields':('app_config','chart', 'url',('count', 'code', 'start'))
}),
('Suggestion',{
'classes':('collapse', 'suggestion',),
'fields':('url_suggestion',('key1_suggestion_name','key1_suggestion'),('key2_suggestion_name','key2_suggestion'), 'primary_suggestions')
}),
)
list_display =('app_config' ,'url', 'chart');
list_filter = (
'app_config',
)
form = EntryForm
class Media:
js = ('health/js/admin/healthAdmin.js',)
css = {
'all': ('health/css/admin/admin_area.css',)
}
admin.site.register(Entry, EntryAdmin)
any idea is I missing something, after that, I do a migrate of the component again.
Thanks in advance!
You can specify a custom form for admin using the form attribute of ModelAdmin.
So using the example from the docs linked below, that would look like;
from django import forms
from django.contrib import admin
from myapp.models import Person
class PersonForm(forms.ModelForm):
class Meta:
model = Person
exclude = ['name']
class PersonAdmin(admin.ModelAdmin):
exclude = ['age']
form = PersonForm
https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.form
So in your admin.py you'd need something like;
from .forms import EntryForm
class EntryAdmin(admin.ModelAdmin):
form = EntryForm

Django. How to change the input class of a Built-in form

I'm trying to change the class of the django Built-in form PassowrdChangeForm. This is what I tried, but it doesn't work:
forms.py
from django.contrib.auth.forms import PasswordChangeForm
class FormChangePassword(PasswordChangeForm):
class Meta:
widgets = {
'old_password': PasswordInput(attrs={'class': 'form-control'}),
'new_password1': PasswordInput(attrs={'class': 'form-control'}),
'new_password2': PasswordInput(attrs={'class': 'form-control'})
}
and just in case it is useful info, I'm using the built-in password_change view like this:
urls.py
from django.contrib.auth.views import password_change
from forms import FormChangePassword
url(r'^change_password/$', password_change,
{'template_name': 'sisacademico/change_password.html',
'post_change_redirect': 'password_changed/',
'password_change_form': FormChangePassword},
name='change_password'),
It doesn't work, the form doesn't get the class 'form-control', any ideas?
PasswordChangeForm is not a ModelForm so Meta.widgets is not working here. You have to set widget's attrs in the __init__() constructor:
class FormChangePassword(PasswordChangeForm):
def __init__(self, *args, **kwargs):
super(FormChangePassword, self).__init__(*args, **kwargs)
for field in ('old_password', 'new_password1', 'new_password2'):
self.fields[field].widget.attrs = {'class': 'form-control'}

Django - Admin: list_display TextField

I'm trying to display the first 10 characters of a TextField on a list_display.
Is it possible in the admin interface ?
You can define a callable that returns the first 10 characters of the field, and add that to list_display.
More information see the Django docs for list_display.
myapp/admin.py
from django.contrib import admin
from django.utils.text import Truncator
from django.db import models
from .models import Product
def truncated_name(obj):
name = "%s" % obj.name
return Truncator(name).chars(70)
class ProductAdmin(admin.ModelAdmin):
list_display = ['id', truncated_name, 'category', 'timestamp',]
list_display_links = [truncated_name]
list_filter = ['category']
class Meta:
model = Product
You can also override the fields like so:
formfield_overrides = {
models.CharField: {'widget': TextInput(attrs={'size': '20'})},
models.TextField: {'widget': Textarea(attrs={'rows': 1, 'cols': 40, 'style': 'height: 1.5em;'})},
}

Django TextField max_length validation for ModelForm

Django does not respect the max_length attribute of TextField model field while validating a ModelForm.
So I define a LimitedTextField inherited from the models.TextField and added validation bits similar to models.CharField:
from django.core import validators
class LimitedTextField(models.TextField):
def __init__(self, *args, **kwargs):
super(LimitedTextField, self).__init__(*args, **kwargs)
self.max_length = kwargs.get('max_length')
if self.max_length:
self.validators.append(validators.MaxLengthValidator(self.max_length))
def formfield(self, **kwargs):
defaults = {'max_length': self.max_length}
defaults.update(kwargs)
return super(LimitedTextField, self).formfield(**defaults)
But this still has no affect on ModelForm validation.
What am I missing?
As of Django 1.2 this can be done by validators at model level, as explained here:
https://docs.djangoproject.com/en/stable/ref/validators/
from django.core.validators import MaxLengthValidator
class Comment(models.Model):
comment = models.TextField(validators=[MaxLengthValidator(200)])
Since Django 1.7, you can use max_length which is only enforced in client side. See here
You can enforce a max length for a TextField by defining a CharField with a Textarea widget like this:
class MyClass(models.Model):
textfield = models.TextField()
class MyForm(forms.ModelForm):
textfield = forms.CharField(
max_length = 50,
widget = forms.Textarea
)
class Meta:
model = MyClass
fields = ('textfield',)
No need to import MaxLengthValidator from validators for Django 2.x
from django.db import models
class Comment(models.Model):
comment = models.TextField(max_length=200)

Django-Admin: CharField as TextArea

I have
class Cab(models.Model):
name = models.CharField( max_length=20 )
descr = models.CharField( max_length=2000 )
class Cab_Admin(admin.ModelAdmin):
ordering = ('name',)
list_display = ('name','descr', )
# what to write here to make descr using TextArea?
admin.site.register( Cab, Cab_Admin )
how to assign TextArea widget to 'descr' field in admin interface?
upd:
In Admin interface only!
Good idea to use ModelForm.
You will have to create a forms.ModelForm that will describe how you want the descr field to be displayed, and then tell admin.ModelAdmin to use that form. For example:
from django import forms
class CabModelForm( forms.ModelForm ):
descr = forms.CharField( widget=forms.Textarea )
class Meta:
model = Cab
class Cab_Admin( admin.ModelAdmin ):
form = CabModelForm
The form attribute of admin.ModelAdmin is documented in the official Django documentation. Here is one place to look at.
For this case, the best option is probably just to use a TextField instead of CharField in your model. You can also override the formfield_for_dbfield method of your ModelAdmin class:
class CabAdmin(admin.ModelAdmin):
def formfield_for_dbfield(self, db_field, **kwargs):
formfield = super(CabAdmin, self).formfield_for_dbfield(db_field, **kwargs)
if db_field.name == 'descr':
formfield.widget = forms.Textarea(attrs=formfield.widget.attrs)
return formfield
Ayaz has pretty much spot on, except for a slight change(?!):
class MessageAdminForm(forms.ModelForm):
class Meta:
model = Message
widgets = {
'text': forms.Textarea(attrs={'cols': 80, 'rows': 20}),
}
class MessageAdmin(admin.ModelAdmin):
form = MessageAdminForm
admin.site.register(Message, MessageAdmin)
So, you don't need to redefine a field in the ModelForm to change it's widget, just set the widgets dict in Meta.
You don't need to create the form class yourself:
from django.contrib import admin
from django import forms
class MyModelAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
kwargs['widgets'] = {'descr': forms.Textarea}
return super().get_form(request, obj, **kwargs)
admin.site.register(MyModel, MyModelAdmin)
See ModelAdmin.get_form.
You can subclass your own field with needed formfield method:
class CharFieldWithTextarea(models.CharField):
def formfield(self, **kwargs):
kwargs.update({"widget": forms.Textarea})
return super(CharFieldWithTextarea, self).formfield(**kwargs)
This will take affect on all generated forms.
If you are trying to change the Textarea on admin.py, this is the solution that worked for me:
from django import forms
from django.contrib import admin
from django.db import models
from django.forms import TextInput, Textarea
from books.models import Book
class BookForm(forms.ModelForm):
description = forms.CharField( widget=forms.Textarea(attrs={'rows': 5, 'cols': 100}))
class Meta:
model = Book
class BookAdmin(admin.ModelAdmin):
form = BookForm
admin.site.register(Book, BookAdmin)
If you are using a MySQL DB, your column length will usually be autoset to 250 characters, so you will want to run an ALTER TABLE to change the length in you MySQL DB, so that you can take advantage of the new larger Textarea that you have in you Admin Django site.
Instead of a models.CharField, use a models.TextField for descr.
You can use models.TextField for this purpose:
class Sample(models.Model):
field1 = models.CharField(max_length=128)
field2 = models.TextField(max_length=1024*2) # Will be rendered as textarea
Wanted to expand on Carl Meyer's answer, which works perfectly till this date.
I always use TextField instead of CharField (with or without choices) and impose character limits on UI/API side rather than at DB level. To make this work dynamically:
from django import forms
from django.contrib import admin
class BaseAdmin(admin.ModelAdmin):
"""
Base admin capable of forcing widget conversion
"""
def formfield_for_dbfield(self, db_field, **kwargs):
formfield = super(BaseAdmin, self).formfield_for_dbfield(
db_field, **kwargs)
display_as_charfield = getattr(self, 'display_as_charfield', [])
display_as_choicefield = getattr(self, 'display_as_choicefield', [])
if db_field.name in display_as_charfield:
formfield.widget = forms.TextInput(attrs=formfield.widget.attrs)
elif db_field.name in display_as_choicefield:
formfield.widget = forms.Select(choices=formfield.choices,
attrs=formfield.widget.attrs)
return formfield
I have a model name Post where title, slug & state are TextFields and state has choices. The admin definition looks like:
#admin.register(Post)
class PostAdmin(BaseAdmin):
list_display = ('pk', 'title', 'author', 'org', 'state', 'created',)
search_fields = [
'title',
'author__username',
]
display_as_charfield = ['title', 'slug']
display_as_choicefield = ['state']
Thought others looking for answers might find this useful.