I have two TextField in my model. But i want to change the rows and cols attribute of only of the TextField. I know from this page that the look of TextField can be changed using the following code in the admin.py.
class RulesAdmin(admin.ModelAdmin):
formfield_overrides = {
models.TextField: {'widget': Textarea(
attrs={'rows': 1,
'cols': 40})},
}
...
admin.site.register(Rules, RulesAdmin)
As I said, using the above code changed the look of both the TextField, I want only to change one of those here is how my model looks like:
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
pub_date = models.DateTimeField(auto_now_add=True)
update_date = models.DateTimeField(auto_now=True)
meta = models.TextField(blank=True)
def __str__(self):
return self.title
I want only to change the look of meta field.
How should I go about this ?
Add the following code to forms.py
from django.forms import ModelForm, Textarea
from .models import Lesson
class PostModelForm(ModelForm):
class Meta:
model = Lesson
fields = ('__all__')
widgets = {
'meta': Textarea(attrs={'cols': 80, 'rows': 5}),
}
and in admin.py do this
class PostModel(admin.ModelAdmin):
list_display = ('id', 'title', 'pub_date', 'course',)
search_fields = ('title', 'course__alias',)
form = PostModelForm
Related
I am working on a recipe book app, and I currently have my models connected in this way:
class Tool(models.Model):
name = models.CharField(max_length=50)
description = models.CharField(max_length=200)
def __str__(self):
return self.name
class Recipe(models.Model):
name = models.CharField(max_length=50)
description = models.CharField(max_length=200)
servings = models.IntegerField(default=1, blank=False)
tools = models.ManyToManyField(Tool)
def __str__(self):
return self.name
The admin panel input currently looks like this:
Upon saving the data as shown in the screenshot, I get the following error:
OperationalError at /admin/recipeBook/recipe/add/
no such table: recipeBook_recipe_tools
Here is my admin.py, just incase it's useful:
from django.contrib import admin
from .models import Recipe, Ingredient, Instruction, Tool
# Register your models here.
class IngredientInline(admin.TabularInline):
model = Ingredient
extra = 2
class RecipeAdmin(admin.ModelAdmin):
fieldsets = [
('Information', {'fields': ['name', 'description', 'servings']}),
('Tools', {'fields': ['tools']})
]
inlines = [IngredientInline]
list_display = ('name', 'description', 'servings')
search_fields = ['name']
list_filter = ['servings']
admin.site.register(Recipe, RecipeAdmin)
admin.site.register(Ingredient)
admin.site.register(Instruction)
admin.site.register(Tool)
If you have an error like this.
Make sure you migrate your database after adding to your models.
The frontend of my Django site is in Persian language which is RTL and everything is ok except that the CharField model fields are in LTR direction when edited in the Admin site.
Here's my model:
class Post(models.Model):
STATUS_CHOICES = (('draft', 'Draft'), ('published', 'Published'))
title = models.CharField(max_length=100)
slug = models.SlugField(max_length=100, allow_unicode=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='blog_posts')
lead = RichTextField()
body = RichTextUploadingField()
created_on = models.DateTimeField(auto_now_add=True)
published_on = models.DateTimeField(default=timezone.now)
updated_on = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
is_featured = models.BooleanField(default=False, verbose_name='Featured Post')
objects = models.Manager()
published = PublishedManager()
featured = FeaturedManager()
class Meta:
ordering = ('-published_on',)
def __str__(self):
return self.title
I know I can set the site's language to Persian and solve this issue but I don't want to because the Persian translation of Django is dull.
Another solution is to use one of available Rich Text editors (tinymce or ckeditor) but those are overkill for a CharField field.
I also tried custom admin form like this:
class PostAdminForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'slug', 'author', 'lead', 'body', 'status', 'is_featured']
widgets = {'title': forms.TextInput(attrs={'dir': 'rtl'})}
#admin.register(Post, PostAdminForm)
class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'slug', 'created_on', 'published_on', 'status', 'is_featured')
list_filter = ('status', 'created_on', 'published_on', 'is_featured')
search_fields = ('title', 'body')
prepopulated_fields = {'slug': ('title',)}
raw_id_fields = ('author',)
date_hierarchy = 'published_on'
ordering = ('status', 'created_on', 'published_on')
But it gives me this error:
AttributeError: 'ModelFormOptions' object has no attribute 'abstract'
In your admin.py file for your app, you can create a custom form for your model. I don't know your model so I will use general names for this as an example:
from django.contrib import admin
from app_name.models import *
from django import forms
class CustomAdminForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ['mycharfield']
widgets = {'mycharfield':forms.TextInput(attrs={'dir':'rtl'})}
admin.site.register(MyModel,CustomAdminForm)
This should make the mycharfield text input render as being RTL on the admin page for the MyModel form. The line widgets = {'mycharfield':forms.TextInput(attrs={'dir':'rtl'})} will change the text input widget's dir attribute to the rtl value. If you have more than one CharField in your model and want RTL for all of them simply add each field to the fields attribute in the form and do the same thing with the widget attribute for each field.
As the answer provided by Nathan was partially correct, I did my own research and found that the correct way is this:
class CustomPostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'slug', 'lead', 'body']
widgets = {'title': forms.TextInput(attrs={'dir': 'rtl', 'class': 'vTextField'})}
and then:
#admin.register(Post)
class PostAdmin(admin.ModelAdmin):
form = CustomPostForm
What surprises me is that the above code removed vTextField class from the input field so I had to add it again.
I'm trying to build a filter that corresponds to the has_images method on my Django admin, but I can't because it strictly says that has_images is not a field of the model. I tried setting it up as a property, but it also didn't work.
I thought about defining has_images as a field and really calculating it, based on the changes on the model, but I think that would be not optimal.
What would be a good solution here?
models.py
class Product(models.Model):
name = models.CharField("Name", max_length=255)
def has_images(self):
return self.images.all().count() > 0
has_images.boolean = True
class ProductImage(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name="images")
file = models.ImageField("Product Image")
admin.py
class ProductImageInline(admin.TabularInline):
model = ProductImage
fields = ('file',)
extra = 1
class ProductAdmin(VersionAdmin):
list_display = ('id', 'name', 'has_images',)
inlines = (ProductImageInline,)
Expected result:
Can you share the contents of the admin.py file?
Or let me explain it as follows. Add a feature called list_filter = ('images') into the ProductAdmin class you created in admin.py. If this feature doesn't work (I'm not sure as I haven't tried it), if you create an Admin Class for ProductImages directly, you can already view the pictures and the corresponding Product on that page.
----------- EDIT ----------------
This is how I solved the problem.
models.py
from django.db import models
class Product(models.Model):
name = models.CharField("Name", max_length=255)
is_image = models.BooleanField(default=False, editable=False)
def save(self, *args, **kwargs):
if self.images.count():
self.is_image = True
else:
self.is_image = False
super(Product, self).save(*args, **kwargs)
class ProductImage(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name="images")
file = models.ImageField("Product Image")
def save(self, *args, **kwargs):
super(ProductImage, self).save(*args,**kwargs)
self.product.save()
admin.py
from django.contrib import admin
from .models import *
class ProductImageInline(admin.TabularInline):
model = ProductImage
fields = ('file',)
extra = 1
class ProductAdmin(admin.ModelAdmin):
list_display = ('id', 'name',)
list_filter = ('is_image',)
inlines = (ProductImageInline,)
admin.site.register(Product, ProductAdmin)
Here I added an is_image BooleanField field with False by default. Every time the save method of the Product model runs, it checks whether there is an image in the ProductImage to which the Product model is attached. If there is an image in it, is_image is set as True.
I am trying to create a django slideshow app using some existing code and adding some new. I am unsure if what I am doing is correct, I think the problem is in my models.py and as a python beginner I think I need some advice.
models.py
from django.db import models
import datetime
class Slider(models.Model):
title = models.CharField(max_length=100)
description = models.TextField(blank=True)
slideshow = models.ForeignKey('Slideshow')
images = models.ImageField(upload_to='slideshow', max_length=1000, blank=True, null=True)
def __unicode__ (self):
return self.title
class Slideshow(models.model):
name = models.CharField(max_length=50)
touchEnabled = models.BooleanField(blank=True, default=False)
speed = models.IntegerField(blank=True, default=500)
class wrapperClass_options(models.Model):
choices = (('mydiv'))
wrapperClass = models.CharField(blank=True, max_length=20, default=choices)
# div class to wrap the slider in. Change it to prevent using default styles.
pub_date = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.name
I am pretty sure that my BooleanField and IntegerField are ok, but am not so sure about the CharField.
the charfield default is #mydiv but it needs to be able to be changed to whatever a developer needs it to be, am I doing the right thing by creating wrapperclass_options and adding the default to it choices = 'mydiv' or should I be doing something different altogether?
Below is my admin.py
admin.py
from satchmo_slideshow.models import Slider, Slideshow
from django.contrib import admin
class SlideInline(admin.StackedInline):
model = Slider
class SlideshowAdmin(admin.ModelAdmin):
fieldsets = [(title, {'fields': ['name']}),
('speed', {'fields': ['Default: 500ms']}),
('wrapperClass', {'fields': ['Default: mydiv']}),
('touchEnabled', {'fields': ['Default: False']}),
]
inlines = [SlideInline]
list_display = ['name', 'pub_date']
list_filter = ['pub_date']
search_fields = ['name']
admin.site.register(Slideshow, SlideshowAdmin)
using python 2.7 and django 1.4.2
Given the following models in models.py:
class Profile(models.Model):
name = models.CharField(max_length=30)
email_address = models.CharField(max_length=30)
password = models.CharField(max_length=30)
preferences = models.OneToOneField("Preferences")
def __unicode__(self):
return u"%s" % self.name
class Preferences(models.Model):
likes_hugging = models.BooleanField(default=False)
despises_men = models.BooleanField(default=False)
Now the following form in forms.py...
class PreferencesModelForm(forms.ModelForm):
class Meta:
model = Profile
fields = ("preferences",)
... produces the following result:
But how do I get the following result instead?
you need to override the default widget. Like this:
from django.forms import ModelForm, Textarea
from myapp.models import Author
class AuthorForm(ModelForm):
class Meta:
model = Author
fields = ('name', 'title', 'birth_date')
widgets = {
'name': Textarea(attrs={'cols': 80, 'rows': 20}),
}
You can read the full docs here . The problem is that are you using the PreferencesModelForm correctly? The model should be Preferences. If you really trying to made the form for Profile model with preferencesfield, you can use inline formsets. You can read it here.
You need to use a Radio instead of a checkbox in your case, since you have a OneToOne relation.
Just add to your form:
widgets = {
'preferences': forms.RadioSelect(),
}
PS: this question is from last year, I hope you have solved it :) I came here from google and hope to help people in the same situation.