Let's say I have these two models:
class Egg(models.Model):
# some fields
class Spam(models.Model):
egg = models.ForeignKey(Egg)
img = models.ImageField()
I planned to have the spams inlined to egg in admin site. The problem is I also want a very customized method on uploading the spam images (like this), like having my own view and template. So far, I just got :
class CustomInline(admin.StackedInline):
model = Spam
template = 'admin/app/inline.html' # empty
class EggAdmin(admin.ModelAdmin):
inlines = [CustomInline, ]
The idea is having some kind of gallery of spams and custom image upload in egg admin. (Is this achievable?)
So the questions are:
I want to injects variables to be available on the template (spam objects on inline.html for gallery) . Is there a way to do this?
Is it okay to POST something to a view (upload process)? Or that particular view must be registered first on admin site or something?
I've looked on InlineAdmin source but still have no idea what to do/override
Thanks
using the form property you can subclass your ModelForm and completely change the way your inline form works.
Related
Django admin site shows the attributes of a class in a form so you can add a new object, I want to know if there is an easy way to separate the attributes in sections to make the form more organized, like having a "Physical features" section title over fields about physical features, similar to how inline attibutes work having the name of the inline class as a section name.
Default form:
Sketch showing how I imagine a section:
I believe fieldsets is what you are after, see the Django documentation here:
https://docs.djangoproject.com/en/4.0/ref/contrib/admin/#django.contrib.admin.ModelAdmin.fieldsets
You will need to put this code within your admin.py file and the registration of your model.
I'm using an inline admin in my Django application. I want to have some help text displayed in the admin form for Page to go with the inline admin (not just the individual help text for each field within that model). I've been trying to figure out how to do this, but cannot seem to find anything on the issue. Am I missing some trivial out-of-the box option for doing this?
If there's no super simple way to do this, is there a way to do this by extending some template?
Below are parts of my models and their admins:
class Page(models.Model):
....
class File(models.Model):
page = models.ForeignKey(Page)
....
class FileAdminInline(admin.TabularInline):
model = File
extra = 0
class PageAdmin(admin.ModelAdmin):
inlines = (FileAdminInline,)
If you're not talking about specific help_text attribute then then look at this post it shows an underdocumented way of accomplishing this.
If you don't want to mess around with getting the help_text information into the formset's context and modify the edit_inline template, there is a way of capturing the verbose_name_plural Meta attribute of your model for that purpose.
Basic idea: If you mark that string as safe you can insert any html element that comes to your mind. For example an image element with it's title set to global your model help text. This could look somethink like this:
class Meta:
verbose_name = "Ygritte"
verbose_name_plural = mark_safe('Ygrittes <img src="' + settings.STATIC_URL + \
'admin/img/icon-unknown.svg" class="help help-tooltip" '
'width="15" height="15" '
'title="You know nothing, Jon Snow"/>')
Of course - this is kind of hacky - but this works quite simple, if your model is only accessed as an inline model and you don't need the plural verbose name for other things (e.g. like in the list of models in your application's admin overview).
I need to create a form to admin-side with two fields
Number of code: integer
Value of code: float
How can I do that. This form is not related to any model.
You can implement your modelless form as explained in #levi's answer.
Then, you can place it in the admin site in a number of different ways, depending your needs:
Make instances of the form available to all templates via a context processor, and override the admin templates to have it rendered wherever you want. You can create a view for only processing the form.
Create a view for both rendering and processing the form in a unique place, and hook it up to the admin as explained in the old Django Book, you'll need to make sure the template for that view extends one of the admin's templates (admin/change_form.html may be a good choice).
from django import forms
class Your_Form(forms.Form):
number_code = forms.IntegerField()
value_code = forms.FloatField()
Given an admin media class that sets up a rich text editor, like:
class TutorialAdmin(admin.ModelAdmin):
fields...
class Media:
js = ['/paths/to/tinymce.js',]
I would like the ability to selectively override js depending on a field value in the model it references. I've added a "use_editor" boolean to the Tutorial model. The question is, how can I detect whether the current instance has that bool set? I'd like to end up with something like:
class Media:
if self.use_editor:
js = ['/path/to/tinymce.js',]
else:
js = ''
Ideas? Thanks.
Many thanks to Sam Lai on django-users, I finally have a working solution for this. Turns out to be trickier than expected because you can't directly access field values on the instance from within the Admin class - you need to do it by redefining the form used by the Admin class. In addition, you'll need to use _media rather than "class Media:" to set the media property.
The goal is to detect the current instance value of the use_visual_editor field and turn javascript paths on or off depending on its value (so authors can turn off the visual editor on a per-record basis). Here's the final working solution:
models.py
class Tutorial(models.Model):
use_visual_editor = models.BooleanField()
forms.py
from django import forms
from tutorials.models import Tutorial
class TutorialAdminForm(forms.ModelForm):
class Meta:
model = Tutorial
def _media(self):
if self.instance.use_visual_editor == True:
js = ['/paths/to/javascript',]
else:
js = ['']
return forms.Media(js=js)
media = property(_media)
admin.py
from django import forms
....
class TutorialAdmin(admin.ModelAdmin):
form = TutorialAdminForm
Works perfectly!
An alternative approach, given you're using TinyMCE, is to use an additional JS file that adds a 'mceNoEditor' class to textareas you don't want to convert to rich text.
eg
class fooAdmin(admin.Modeladmin)
class Media:
js = ['/path/to/admin-styling.js',
'/paths/to/tinymce.js',]
In your tinymce.js init, you need to ensure there's a class defined for disabling the editor, such as:
editor_deselector : "mceNoEditor",
and in the admin-styling.js file have some kind of jQuery call in the document ready handler that finds certain elements and adds that class before TinyMCE is invoked.
Usually you can do this with the 'id_foo' identifier. eg, if you have a model field called additional_notes:
$('textarea#id_additional_notes').addClass('mceNoEditor');
It's possible to use more sophisticated jQuery selectors too, of course.
HTH
Steve
I'm writing a simple real-estate listing app in Django. Each property needs to have a variable number of images. Images need to have an editable order. And I need to make the admin user-proof.
So that said, what are my options?
Is there a ImageList field that I don't know about?
Is there an app like django.contrib.comments that does the job for me?
If I have to write it myself, how would I go about making the admin-side decent? I'm imagining something a lot slicker than what ImageField provides, with some drag'n'drop for re-ordering. But I'm a complete clutz at writing admin pages =(
Variable lists, also known as a many-to-one relationship, are usually handled by making a separate model for the many and, in that model, using a ForeignKey to the "one".
There isn't an app like this in django.contrib, but there are several external projects you can use, e.g. django-photologue which even has some support for viewing the images in the admin.
The admin site can't be made "user proof", it should only be used by trusted users. Given this, the way to make your admin site decent would be to define a ModelAdmin for your property and then inline the photos (inline documentation).
So, to give you some quick drafts, everything would look something like this:
# models.py
class Property(models.Model):
address = models.TextField()
...
class PropertyImage(models.Model):
property = models.ForeignKey(Property, related_name='images')
image = models.ImageField()
and:
# admin.py
class PropertyImageInline(admin.TabularInline):
model = PropertyImage
extra = 3
class PropertyAdmin(admin.ModelAdmin):
inlines = [ PropertyImageInline, ]
admin.site.register(Property, PropertyAdmin)
The reason for using the related_name argument on the ForeignKey is so your queries will be more readable, e.g. in this case you can do something like this in your view:
property = Property.objects.get(pk=1)
image_list = property.images.all()
EDIT: forgot to mention, you can then implement drag-and-drop ordering in the admin using Simon Willison's snippet Orderable inlines using drag and drop with jQuery UI
Write an Image model that has a ForeignKey to your Property model. Quite probably, you'll have some other fields that belong to the image and not to the Property.
I'm currently making the same thing and I faced the same issue.
After I researched for a while, I decided to use django-imaging. It has a nice Ajax feature, images can be uploaded on the same page as the model Insert page, and can be editable. However, it is lacking support for non-JPEG extension.
There is a package named django-galleryfield. I think it will meet your demand.