Dynamic show and hide fields in Django admin panel - django

I have defined model in which one of the filed has definition:
REPEAT = (
('day', 'Daily'),
('week', 'Weekly'),
)
repeats = models.CharField('Repeat', default='day', max_length=5, choices=REPEAT)
Also I have defined related admin model, which is responsible to show my main model in panel.
Is possible to show and hide some fields in admin panel based on choice in repeats field? For example in scenery when user choose 'Daily', then some fields are not required and I want to hide them.
I will be thankful for any advices or hints.

Yes, you can add custom JS to your admin model:
class MyModelAdmin(admin.ModelAdmin):
class Media:
js = ("my_code.js",)
STATIC_URL is appended to your filename automagically.
And your JS function, assuming jQuery, something like:
$(function(){
$('<my-selector>').change(function(){
//do something on select change
});
});

Related

Django Admin intercept onchange event of a field and make an action

In my django project i would clear a field value every time another select field have an onChange event.
I have an add form like thisone:
every time Template field change (onChange), Test Case field have to become blank.
How can i do this in a django admin add or edit page?
So many thanks in advance
You could customize Admin asset definition and use JavaScript/jQuery to handle your problem. Here is an example:
admin.py
class TestCaseAdmin(admin.ModelAdmin):
class Media:
js = (
'js/admin.js', # inside app static folder
)
admin.site.register(TestCase, TestCaseAdmin)
js/admin.js
if (!$) {
// Need this line because Django also provided jQuery and namespaced as django.jQuery
$ = django.jQuery;
}
$(document).ready(function() {
$("select[name='template']").change(function() {
$("select['test_case']").val('');
});
});
template, test_case are field name on your model
The event can also be set in the modelform meta widgets dict;
class ReceiptsForm(ModelForm):
class Meta:
model = Receipts
fields = []
widgets = {
'partner_id': forms.Select(attrs={'onchange': 'this.form.submit();'})
}

Model "help" text in Django Inline Admin

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).

GenericForeignKey and Admin in Django

Let's say I have a Post object that can contain Images, Videos, and other media types. I can use a GenericForeignKey to link them together. Something like:
class Post(models.Model):
title = models.CharField(...)
text = models.TextField(...)
class AudioMedia(models.Model):
...
class VideoMedia(models.Model):
...
class ImageMedia(models.Model):
...
class MediaObject(models.Model):
post = models.ForeignKey(Post)
order = models.IntegerField()
content_type_media = models.ForeignKey(
ContentType, limit_choices_to={
'model__in': (
'audiomedia',
'imagemedia',
'videomedia')
})
object_id_media = models.PositiveIntegerField()
obj = generic.GenericForeignKey('content_type_media', 'object_id_media')
Now I can easily create an admin interface, like:
class MediaObjectAdminInLine(admin.StackedInline):
model = MediaObject
ct_field = "content_type_media"
ct_fk_field = "object_id_media"
extra = 0
class PostAdmin(admin.ModelAdmin):
inlines = [MediaObjectAdminInLine]
Now the question :) In admin/, I can easily create a new Post. To the post, I can easily add more MediaObject. In the panel, I have a drop down menu to chose the type (audio, video, ...), but I have to manually enter the ID of the object I want to link with Post.
I have tried various extensions, including grappelli. Some provide the ability to lookup the ID of objects to link here. I want the ability to add objects here, eg, add an AudioMedia, a VideoMedia, an ImageMedia, depending on what I pick from the dropdown.
Any suggestions?
You'd need to quite a bit of work to get this going.
You're asking that the admin dynamically display a modelform, based on what model type you chose from a drop down.
Django's admin does not do that (nor do any known extensions to it).
To make this work, you'll have to:
Write a custom JavaScript event handler which captures the onchange of the model select drop down.
Then calls Django's admin and requests the inline modelform for that model.
Updates the current HTML page with that model form.
Then you'll need to intercept the parent model's modelform's save() method to figure out which child modelform it's dealing with, and correctly save it to the database.
Then you'll need to sort out how to get the parent model's modelform to correctly display the appropriate child model's modelform dependent on the model of the child.
Sound daunting? It is.
Here's an easier way:
Just have a single "Media" model. You'll have a few fields on the model that are only valid for one of your types (though there's plenty of crossover).
Name any fields that are specific to a single Media type with a prefix for that mediatype, i.e. image_size', orvideo_title`.
Attach a JavaScript handler to your ModelAdmin which selectively shows and hides fields based on a dropdown for the media type. Something like this:
class MediaAdmin(admin.ModelAdmin):
class Meta:
js = ["js/media-types.js",]
// media-type.js
(function($) {
$(document).ready(function(){
$('.module[id^=module] .row').hide();
$('.module[id^=module] .row.module').show();
$('.module[id^=module] .row.module select').each(function(){
if ($(this).val() != '')
{
var group = $(this).parent().parent().parent().parent();
var field = $(this).parent().parent().parent();
var mtype = $(this).val().toLowerCase();
if (mtype != '')
{
$('.row', group).not(field).slideUp('fast');
$('.row[class*="'+mtype+'"]', group).slideDown('fast');
$('.row[class*="all"]', group).slideDown('fast');
}
else
{
$('.row', group).not(field).slideUp('fast');
}
}
});
$('.module[id^=module] .row.module select').change(function(){
var group = $(this).parent().parent().parent().parent();
var field = $(this).parent().parent().parent();
var mtype = $(this).val().toLowerCase();
if (mtype != '')
{
$('.row', group).not(field).slideUp('fast');
$('.row[class*="'+mtype+'"]', group).slideDown('fast');
$('.row[class*="all"]', group).slideDown('fast');
}
else
{
$('.row', group).not(field).slideUp('fast');
}
});
});
})(django.jQuery);
django-admin-genericfk doesn't work with Django 1.9.
Other than that I only found the following module:
https://github.com/lexich/genericrelationview
which looks well maintained. Unfortunately, its JS code does not work well with how Django CMS sets up jQuery (noConflict jQuery), so it seems that it is not an option for me. But it should be fine if not used in Django CMS pages but the regular Django Admin.
I realize this is pretty old, but this is still the first result when searching for this.
django-admin-genericfk does exactly what you need.

Django labels for custom admin fields on inline

I'm new both here and to Django, and I have a doubt about custom fields:
I'm using custom models in my admin, but I would like to change the label that shows on the tabular inline.
My model is like this:
ModelA(Model):
name = Model.charField(80)
(...)
ModelB(Model):
modelA = ModelA
(...)
then in my admin I use:
def name_modelA(self):
return ("%s" % self.modelA.name)
class ModelBInlne(TabularInline):
(...)
fields=('field1','field2',...,name_modelA)
(...)
thing is, on the admin page the label for the name comes out "name_modelA", I'd like to change it to "name". Is it possible?
Hope I was clear enough.
I guess you will get what you want with verbose field names? That controls the label for editable fields in the admin interface.
For the tabular interface, I'd say something along the following lines should do:
class ModelAInline(TabularInline):
model = ModelA
class ModelAAdmin(ModelAdmin):
inlines = [ ModelAInline, ]
This makes your ModelA editable inline. I'm not exactly sure how you would like to have it displayed in your ModelB, but perhaps you could look through the ModelAdmin docs and use something from there?

Django admin raw_id_fields table display

Django raw_id_fields don't display tables the way I expect, am I doing something wrong? I'm trying to use a raw_id_fields widget to edit a ForeignKey field as follows:
#models.py
class OrderLine(models.Model):
product = ForeignKey('SternProduct')
class SternProduct(models.Model):
def __unicode__(self): return self.product_num
product_num = models.CharField(max_length=255)
#admin.py
#import and register stuff
class OrderLineAdmin(admin.ModelAdmin):
raw_id_fields=('product')
I get the little textbox and magnifier widget as expected, but clicking the magnifier gives me this:
flickr.com/photos/28928816#N00/5244376512/sizes/o/in/photostream/
(sorry, can't post more than one hyperlink apparently)
I thought I would get something closer to the changelist page c/w columns, filters and search fields. In fact, that's apparently what others get.
Any thoughts about how to enable the more featureful widget?
Ah, OK, this should have been obvious, but it isn't explained in the Django docs. The list that appears in the raw_id_fields popup uses the same options as the admin object for the referenced model. So in my example, to get a nice looking popup I needed to create a SternProductAdmin object as follows:
class SternProductAdmin(admin.ModelAdmin):
list_display = ('__unicode__', 'drawing_number', 'drawing_revision',)
list_filter = ('drawing_number',)
search_fields = ('drawing_number',)
actions = None
Hopefully this will help others in the future.