Django template tag URL is not working in JavaScript - django

I want to add an edit button and delete image dynamically to table, but it is showing error
Page Not Found at
Request URL: http://127.0.0.1:8000/%7B%25%20url%20'expense-edit'%20expense.id%20%25%7D
here is js file
const searchField = document.querySelector("#searchField");
const tableOutput = document.querySelector(".table-output");
const appTable = document.querySelector(".app-table");
const paginationContainer = document.querySelector(".pagination-container");
tableOutput.style.display = 'none';
const noResults = document.querySelector(".no-results");
const tbody = document.querySelector(".table-body");
searchField.addEventListener('keyup', (e) => {
const searchValue = e.target.value;
if (searchValue.trim().length > 0) {
paginationContainer.style.display = "none";
tbody.innerHTML = "";
fetch("http://127.0.0.1:8000/search-expenses", {
body: JSON.stringify({ searchText: searchValue }),
method: "POST",
})
.then((res) => res.json())
.then((data) => {
console.log("data", data);
appTable.style.display = "none";
tableOutput.style.display = "block";
console.log("data.length", data.length);
if (data.length === 0) {
noResults.style.display = "block";
tableOutput.style.display = "none";
}
else {
noResults.style.display = "none";
data.forEach((item) => {
tbody.innerHTML += `
<tr>
<td>${item.amount}</td>
<td>${item.category}</td>
<td>${item.description}</td>
<td>${item.date}</td>
<td>Edit<img src="{% static 'img/delete.png' %}" width="35" height="35"/></td>
</tr>`;
});
}
});
}
else {
noResults.style.display = "none";
tableOutput.style.display = "none";
appTable.style.display = "block";
paginationContainer.style.display = "block";
}
});
urls.py
from django.urls import path
from . import views
from django.views.decorators.csrf import csrf_exempt
urlpatterns = [
path('', views.home, name="home"),
path('expenses', views.index, name='expenses'),
path('add-expenses', views.add_expenses, name='add-expenses'),
path('edit-expense/<int:id>', views.expense_edit, name='expense-edit'),
path('expense-delete/<int:id>', views.delete_expense, name='expense-delete'),
path('search-expenses', csrf_exempt(views.search_expenses), name='search_expenses'),
path('expense_category_summary', views.expense_category_summary, name="expense_category_summary"),
path('stats', views.stats_view, name="stats"),
path('export_csv', views.export_csv, name="export-csv"),
path('export_excel', views.export_excel, name="export-excel"),
path('export_pdf', views.export_pdf, name="export-pdf"),
]
I want to add a button that has a link to the next page through JavaScript using the Django URL template tag. thanks in advance

When you write {% url 'expense-edit' expense.id %}, you're using a Django-specific "language" called Django template language which means that the mentioned syntax can only be "understood" by Django templates.
What you're doing here is loading a separate JavaScript file in which the Django template syntax simply won't work because when browser comes to the point to evaluate that file, {% url 'expense-edit' expense.id %} will look just another string literal, and not what you would expect to.
It should work if you inline your JavaScript example directly into the Django template.
So there is two possible Hacks to do this:
One is putting the written script in your tenplate file as:
<script type="text/javascript">
const searchField = document.querySelector("#searchField");
const tableOutput = document.querySelector(".table-output");
...
</script>
The issue with this approach is the scope of variables as you may not want to declare things globally so it could be considered an easy approach, but not necessarily the best solution.
So the other solution is to change the name of file from script.js to script.js.html and include in your desired template as :
...
{% include "my_app/script.js.html" %}

Instead of this:
Edit<img src="{% static 'img/delete.png' %}" width="35" height="35"/></td>
Try this way:
Edit
<img src="{% static 'img/delete.png' %}" width="35" height="35"/></td>

Related

Pass javascript variable to views.py

I really need some help on this subject, which seems easy, but i cant get myself to figure out the problem.
I understand that using ajax is the best way to pass a variable from a template to a view.
Is what i have done good, or would you recommend i try something different ?
function updateArea(e) {
var data = draw.getAll();
var answer = document.getElementById('calculated-area');
if (data.features.length > 0) {
var area = turf.area(data);
// restrict to area to 2 decimal points
var rounded_area = Math.round(area*100)/100;
answer.innerHTML = '<p><strong>' + rounded_area + '</strong></p><p>square meters</p>';
var convertedData = 'text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(data));
document.getElementById('export').setAttribute('href', 'data:' + convertedData);
document.getElementById('export').setAttribute('download','data.geojson');
} else {
answer.innerHTML = '';
if (e.type !== 'draw.delete') alert("Use the draw tools to draw a polygon!");
}
}
I want to take the area variable and convertedData variable and pass them to a view.
So after some searching and trial and error, here is what I tried to do using Ajax.
When I run this i get no errors, but i get nothing in my database.
template.html
<form id="areaform" method="POST">
{% csrf_token %}
<input type="submit" name="area" value=""/>
</form>
$(document).on('submit', '#areaform',function(e) {
e.preventDefault();
$.ajax({
type: 'POST',
url:'fertisatmap/area',
data:{
name: $('#area').val(),
},
sucess:function(){}
});
});
urls.py
path('fertisatmap/area', fertisat_views.fertisatareaview, name='fertisat-area'),
views.py
def fertisatareaview(request):
if request.method == "POST":
area = request.POST['area']
Fertidb.objects.create(
area = area)
return HttpResponse('')

Django How to route to a js file from urlpattern

I want to route to a js file (may be static or dynamic).
The js file has format same thing:
(function() {
var img = new Image,
url = encodeURIComponent(document.location.href),
title = encodeURIComponent(document.title),
ref = encodeURIComponent(document.referrer);
img.src = '%s/a.gif?url=' + url + '&t=' + title + '&ref=' + ref;
})();
And from client I will run this script from header by:
<script async="" src="https://example.com/a.js"> </script>
without use staticfile, I think we can use it by urlpattern. But I don't know use for javascript file.
I found a solution.
in views.py:
def generatejs(request):
js_str="""
(function() {
var img = new Image,
url = encodeURIComponent(document.location.href),
title = encodeURIComponent(document.title),
ref = encodeURIComponent(document.referrer);
img.src = 'http://127.0.0.1:8000/a.gif?url=' + url + '&t=' + title + '&ref=' + ref;
})();
"""
return HttpResponse(js_str)
And In urlpatterns, insert:
url(r'^gtag/js', collector.generatejs),

Holoview chart won't appear in Django site

i know there is probably something simple i am doing wrong, but i don't know where else to get an answer. I created a django site and the following function returns holoview html:
from django.shortcuts import render
from django.http import HttpResponseRedirect
from charts.models import Ord
from IPython.display import display_html
import pandas as pd
import holoviews as hv
hv.extension('bokeh')
renderer = hv.renderer('bokeh')
# Create your views here.
def displayChart(request):
df = pd.DataFrame(list(Ord.objects.using('DB').all().values('ordtyp')[:500]))
df = df.groupby([df.ordtyp]).size().reset_index(name='counts')
bars = hv.Bars(df, kdims=[('ordtyp', 'Order Type')], vdims=[('counts', 'Count of Orders')])
hv.Store.registry['bokeh'][hv.Bars]
html = renderer.html(bars)
return render(request, 'charts/charts.html', {'html': html})
i put a block in the charts.html file as:
{{ html |safe }}
and all i get is a blank page. i then took the raw html that the renderer is returning and tried to copy and paste it directly into my html file, and got the same thing. the html is below. Also, the chart does work in Jupyter Notebook... can you tell me what i am doing wrong?
charts.html:
> <!DOCTYPE html>
> <html>
> <head>
> <title>Charts</title>
> </head>
> <body>
> {{html|safe}}
> </body>
> </html>
raw html that the renderer returned:
<div style='display: table; margin: 0 auto;'>
<div class="bk-root">
<div class="bk-plotdiv" id="0dd69ef6-4d30-48f5-a95a-1201437920de"></div>
</div>
<script type="text/javascript">
(function(root) {
function now() {
return new Date();
}
var force = false;
if (typeof (root._bokeh_onload_callbacks) === "undefined" || force === true) {
root._bokeh_onload_callbacks = [];
root._bokeh_is_loading = undefined;
}
if (typeof (root._bokeh_timeout) === "undefined" || force === true) {
root._bokeh_timeout = Date.now() + 0;
root._bokeh_failed_load = false;
}
var NB_LOAD_WARNING = {'data': {'text/html':
"<div style='background-color: #fdd'>\n"+
"<p>\n"+
"BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \n"+
"may be due to a slow or bad network connection. Possible fixes:\n"+
"</p>\n"+
"<ul>\n"+
"<li>re-rerun `output_notebook()` to attempt to load from CDN again, or</li>\n"+
"<li>use INLINE resources instead, as so:</li>\n"+
"</ul>\n"+
"<code>\n"+
"from bokeh.resources import INLINE\n"+
"output_notebook(resources=INLINE)\n"+
"</code>\n"+
"</div>"}};
function display_loaded() {
if (root.Bokeh !== undefined) {
var el = document.getElementById("0dd69ef6-4d30-48f5-a95a-1201437920de");
if (el != null) {
el.textContent = "BokehJS " + Bokeh.version + " successfully loaded.";
}
} else if (Date.now() < root._bokeh_timeout) {
setTimeout(display_loaded, 100)
}
}
function run_callbacks() {
try {
root._bokeh_onload_callbacks.forEach(function(callback) { callback() });
}
finally {
delete root._bokeh_onload_callbacks
}
console.info("Bokeh: all callbacks have finished");
}
function load_libs(js_urls, callback) {
root._bokeh_onload_callbacks.push(callback);
if (root._bokeh_is_loading > 0) {
console.log("Bokeh: BokehJS is being loaded, scheduling callback at", now());
return null;
}
if (js_urls == null || js_urls.length === 0) {
run_callbacks();
return null;
}
console.log("Bokeh: BokehJS not loaded, scheduling load and callback at", now());
root._bokeh_is_loading = js_urls.length;
for (var i = 0; i < js_urls.length; i++) {
var url = js_urls[i];
var s = document.createElement('script');
s.src = url;
s.async = false;
s.onreadystatechange = s.onload = function() {
root._bokeh_is_loading--;
if (root._bokeh_is_loading === 0) {
console.log("Bokeh: all BokehJS libraries loaded");
run_callbacks()
}
};
s.onerror = function() {
console.warn("failed to load library " + url);
};
console.log("Bokeh: injecting script tag for BokehJS library: ", url);
document.getElementsByTagName("head")[0].appendChild(s);
}
};var element = document.getElementById("0dd69ef6-4d30-48f5-a95a-1201437920de");
if (element == null) {
console.log("Bokeh: ERROR: autoload.js configured with elementid '0dd69ef6-4d30-48f5-a95a-1201437920de' but no matching script tag was found. ")
return false;
}
var js_urls = [];
var inline_js = [
function(Bokeh) {
(function() {
var fn = function() {
var docs_json = {"c7d02456-4a61-46d2-8431-34face1e6c67":{"roots":{"references":[{"attributes":{"callback":null,"column_names":["ORDTYP","counts"],"data":{"ORDTYP":["CC","CD","CZ","DB","DR","ED","EI","IC","ID","IP","MC","MF","MI","MK","MP","MS","MX","PC","PM","PT","SD","TI","TX","ZLR"],"counts":[60,3,2,17,1,13,2,28,21,1,3,6,1,2,2,35,10,20,12,2,525,7,225,1]}},"id":"46c2f30a-31d4-4c3f-ade2-4de96e13a4db","type":"ColumnDataSource"},{"attributes":{"active_drag":"auto","active_inspect":"auto","active_scroll":"auto","active_tap":"auto","tools":[{"id":"16eb22e8-c448-49d7-ab20-a02f2ebb3e5c","type":"SaveTool"},{"id":"218dbf74-8190-491c-b2dc-d13097c1f9e4","type":"PanTool"},{"id":"03f67199-1622-4784-b9a2-b36b4a47477b","type":"WheelZoomTool"},{"id":"d48948b1-297b-4915-bf84-916a417b01ee","type":"BoxZoomTool"},{"id":"722ae387-76c5-48cb-a387-7090de91b014","type":"ResetTool"}]},"id":"8ce67c3d-e8dc-41a2-86a8-76685fb90fe9","type":"Toolbar"},{"attributes":{"callback":null,"end":525,"start":0},"id":"16f5dfe6-08a6-4ad8-a190-bdf67979b26c","type":"DataRange1d"},{"attributes":{},"id":"bfe7ff64-0995-43a7-8944-6d491bf93b14","type":"CategoricalTicker"},{"attributes":{"callback":null,"factors":["CC","CD","CZ","DB","DR","ED","EI","IC","ID","IP","MC","MF","MI","MK","MP","MS","MX","PC","PM","PT","SD","TI","TX","ZLR"]},"id":"36f2f454-71a9-4511-a446-2c56a015ecd0","type":"FactorRange"},{"attributes":{"axis_label":"Count of Orders","formatter":{"id":"7303c9ca-b3e1-40be-bd44-1ef7f06d8a2d","type":"BasicTickFormatter"},"plot":{"id":"c84e964a-0b0b-4d95-aa2c-3657b7811bd0","subtype":"Figure","type":"Plot"},"ticker":{"id":"95b801e5-1f32-4ff1-be0c-e64ddcb14fa3","type":"BasicTicker"}},"id":"bd1e5045-1d72-4e92-8914-13be1ee0d04f","type":"LinearAxis"},{"attributes":{},"id":"95b801e5-1f32-4ff1-be0c-e64ddcb14fa3","type":"BasicTicker"},{"attributes":{"grid_line_color":{"value":null},"plot":{"id":"c84e964a-0b0b-4d95-aa2c-3657b7811bd0","subtype":"Figure","type":"Plot"},"ticker":{"id":"bfe7ff64-0995-43a7-8944-6d491bf93b14","type":"CategoricalTicker"}},"id":"0dee56d3-b965-4d15-bf6d-93cd1ea2a20d","type":"Grid"},{"attributes":{"bottom_units":"screen","fill_alpha":{"value":0.5},"fill_color":{"value":"lightgrey"},"left_units":"screen","level":"overlay","line_alpha":{"value":1.0},"line_color":{"value":"black"},"line_dash":[4,4],"line_width":{"value":2},"plot":null,"render_mode":"css","right_units":"screen","top_units":"screen"},"id":"2a376fc3-0bcc-47df-a0e8-2389040d3254","type":"BoxAnnotation"},{"attributes":{"plot":null,"text":"","text_color":{"value":"black"},"text_font_size":{"value":"12pt"}},"id":"04310042-3ae0-4955-bd48-3d9c8e2d9be2","type":"Title"},{"attributes":{},"id":"722ae387-76c5-48cb-a387-7090de91b014","type":"ResetTool"},{"attributes":{"dimension":1,"grid_line_color":{"value":null},"plot":{"id":"c84e964a-0b0b-4d95-aa2c-3657b7811bd0","subtype":"Figure","type":"Plot"},"ticker":{"id":"95b801e5-1f32-4ff1-be0c-e64ddcb14fa3","type":"BasicTicker"}},"id":"a281b265-486f-42a3-829a-c71bfd6830d0","type":"Grid"},{"attributes":{"axis_label":"Order Type","formatter":{"id":"259e4d35-20fb-4eb4-9fbd-6068fef93c0d","type":"CategoricalTickFormatter"},"plot":{"id":"c84e964a-0b0b-4d95-aa2c-3657b7811bd0","subtype":"Figure","type":"Plot"},"ticker":{"id":"bfe7ff64-0995-43a7-8944-6d491bf93b14","type":"CategoricalTicker"}},"id":"9f673b5b-85bf-40d1-96f3-b27737ecc242","type":"CategoricalAxis"},{"attributes":{},"id":"218dbf74-8190-491c-b2dc-d13097c1f9e4","type":"PanTool"},{"attributes":{},"id":"259e4d35-20fb-4eb4-9fbd-6068fef93c0d","type":"CategoricalTickFormatter"},{"attributes":{},"id":"16eb22e8-c448-49d7-ab20-a02f2ebb3e5c","type":"SaveTool"},{"attributes":{},"id":"721998c2-dee0-4e47-9a6d-ecef76d53889","type":"LinearScale"},{"attributes":{},"id":"03f67199-1622-4784-b9a2-b36b4a47477b","type":"WheelZoomTool"},{"attributes":{"overlay":{"id":"2a376fc3-0bcc-47df-a0e8-2389040d3254","type":"BoxAnnotation"}},"id":"d48948b1-297b-4915-bf84-916a417b01ee","type":"BoxZoomTool"},{"attributes":{"data_source":{"id":"46c2f30a-31d4-4c3f-ade2-4de96e13a4db","type":"ColumnDataSource"},"glyph":{"id":"3ab94627-160a-4913-95e6-c25fa17a1d51","type":"VBar"},"hover_glyph":null,"muted_glyph":null,"nonselection_glyph":{"id":"f72f6dc1-7c71-4f5e-80f9-fbd1351268b3","type":"VBar"},"selection_glyph":null,"view":{"id":"9df174a0-4967-47fd-82f3-3d054eee1a12","type":"CDSView"}},"id":"897248ec-4fbd-404c-b3b3-09900b6e3560","type":"GlyphRenderer"},{"attributes":{"fill_alpha":{"value":0.1},"fill_color":{"value":"#30a2da"},"line_alpha":{"value":0.1},"line_color":{"value":"#000000"},"top":{"field":"counts"},"width":{"value":0.8},"x":{"field":"ORDTYP"}},"id":"f72f6dc1-7c71-4f5e-80f9-fbd1351268b3","type":"VBar"},{"attributes":{"fill_color":{"value":"#30a2da"},"line_color":{"value":"#000000"},"top":{"field":"counts"},"width":{"value":0.8},"x":{"field":"ORDTYP"}},"id":"3ab94627-160a-4913-95e6-c25fa17a1d51","type":"VBar"},{"attributes":{"source":{"id":"46c2f30a-31d4-4c3f-ade2-4de96e13a4db","type":"ColumnDataSource"}},"id":"9df174a0-4967-47fd-82f3-3d054eee1a12","type":"CDSView"},{"attributes":{},"id":"eb1872c1-4fa5-47b0-b5c7-43dfe9b890e3","type":"CategoricalScale"},{"attributes":{},"id":"7303c9ca-b3e1-40be-bd44-1ef7f06d8a2d","type":"BasicTickFormatter"},{"attributes":{"background_fill_color":{"value":"white"},"below":[{"id":"9f673b5b-85bf-40d1-96f3-b27737ecc242","type":"CategoricalAxis"}],"left":[{"id":"bd1e5045-1d72-4e92-8914-13be1ee0d04f","type":"LinearAxis"}],"min_border_bottom":10,"min_border_left":10,"min_border_right":10,"min_border_top":10,"plot_height":300,"plot_width":300,"renderers":[{"id":"9f673b5b-85bf-40d1-96f3-b27737ecc242","type":"CategoricalAxis"},{"id":"0dee56d3-b965-4d15-bf6d-93cd1ea2a20d","type":"Grid"},{"id":"bd1e5045-1d72-4e92-8914-13be1ee0d04f","type":"LinearAxis"},{"id":"a281b265-486f-42a3-829a-c71bfd6830d0","type":"Grid"},{"id":"2a376fc3-0bcc-47df-a0e8-2389040d3254","type":"BoxAnnotation"},{"id":"897248ec-4fbd-404c-b3b3-09900b6e3560","type":"GlyphRenderer"}],"title":{"id":"04310042-3ae0-4955-bd48-3d9c8e2d9be2","type":"Title"},"toolbar":{"id":"8ce67c3d-e8dc-41a2-86a8-76685fb90fe9","type":"Toolbar"},"x_range":{"id":"36f2f454-71a9-4511-a446-2c56a015ecd0","type":"FactorRange"},"x_scale":{"id":"eb1872c1-4fa5-47b0-b5c7-43dfe9b890e3","type":"CategoricalScale"},"y_range":{"id":"16f5dfe6-08a6-4ad8-a190-bdf67979b26c","type":"DataRange1d"},"y_scale":{"id":"721998c2-dee0-4e47-9a6d-ecef76d53889","type":"LinearScale"}},"id":"c84e964a-0b0b-4d95-aa2c-3657b7811bd0","subtype":"Figure","type":"Plot"}],"root_ids":["c84e964a-0b0b-4d95-aa2c-3657b7811bd0"]},"title":"Bokeh Application","version":"0.12.7"}};
var render_items = [{"docid":"c7d02456-4a61-46d2-8431-34face1e6c67","elementid":"0dd69ef6-4d30-48f5-a95a-1201437920de","modelid":"c84e964a-0b0b-4d95-aa2c-3657b7811bd0"}];
Bokeh.embed.embed_items(docs_json, render_items);
};
if (document.readyState != "loading") fn();
else document.addEventListener("DOMContentLoaded", fn);
})();
},
function(Bokeh) {
}
];
function run_inline_js() {
if ((root.Bokeh !== undefined) || (force === true)) {
for (var i = 0; i < inline_js.length; i++) {
inline_js[i].call(root, root.Bokeh);
}if (force === true) {
display_loaded();
}} else if (Date.now() < root._bokeh_timeout) {
setTimeout(run_inline_js, 100);
} else if (!root._bokeh_failed_load) {
console.log("Bokeh: BokehJS failed to load within specified timeout.");
root._bokeh_failed_load = true;
} else if (force !== true) {
var cell = $(document.getElementById("0dd69ef6-4d30-48f5-a95a-1201437920de")).parents('.cell').data().cell;
cell.output_area.append_execute_result(NB_LOAD_WARNING)
}
}
if (root._bokeh_is_loading === 0) {
console.log("Bokeh: BokehJS loaded, going straight to plotting");
run_inline_js();
} else {
load_libs(js_urls, function() {
console.log("Bokeh: BokehJS plotting callback run at", now());
run_inline_js();
});
}
}(window));
</script></div>
THANKS!
You are missing the JS and CSS that's required to render this output. You can either manually include BokehJS as a script tag, e.g. for bokeh 0.12.9 you'd add this:
<link
href="http://cdn.bokeh.org/bokeh/release/bokeh-0.12.9.min.css"
rel="stylesheet" type="text/css">
<link
href="http://cdn.bokeh.org/bokeh/release/bokeh-widgets-0.12.9.min.css"
rel="stylesheet" type="text/css">
<script src="http://cdn.bokeh.org/bokeh/release/bokeh-0.12.9.min.js"></script>
<script src="http://cdn.bokeh.org/bokeh/release/bokeh-widgets-0.12.6.min.js"></script>
Alternatively you can also use the renderer.static_html method to export a div which includes all the required JS and CSS, e.g.:
hmap = hv.HoloMap({i: hv.Curve(np.random.rand(10)*i) for i in range(1,5)})
html = hv.renderer('bokeh').static_html(hmap)
with open('test.html', 'w') as f:
f.write(html)
The static_html method also accepts a template to embed the JS, CSS and HTML separately:
<html>
<head>
{css}
{js}
</head>
<body>
{html}
</body>
</html>
In future releases we will also have a components method letting you get the JS, CSS and HTML components separately.

getting a user-inputed variable in django template wihtout using forms

I have a django template which also has a div element that takes in a user_inputed value.
When the value is entered, I call a javascript function say onSubmit(user_input)
<input type="text" class= "inputtext" onKeyPress="return onSubmit(this.value)">
Now in this onSubmit() function which now has the user-inputted value user_input, I want to be able to use url patterns to a direct to a view, like
function onSubmit(user_input) {window.location = "{% url myview user_input %}";}
The problem here is that since user_input is empty when the template is loaded, the url-view reverse lookup gives an error. Is there a way to trigger this lookup only when the onSubmit function is called.
I know form is an alternative, but it just feels like it'll be an overkill for this situation.
You can get the URL via AJAX:
views.py:
def get_url(request):
name = request.GET.get('name')
args = reguest.GET.get('args', [])
kwargs = request.GET.get('kwargs', {})
try:
url = django.core.urlresolvers.reverse(name, args=args, kwargs=kwargs)
except NoReverseMatch:
url = None
return django.http.HttpResponse(url)
urls.py
#...
('^url$', get_url)
#...
js:
function onSubmit(user_input) {
var args = [user_input];
jQuery.get('/url', {'args': args}, function(data) {
var url = data;
if (url) {
window.location = url;
} else {
alert('fail');
}
});
}
Alternatively, if your URL rule is simple enough, you can use some placeholder when resolving and URL, and before submitting the form you should replace it with real input:
var fakeUrl = '{% url myview "%s%" %}';
function onSubmit(user_input) {
window.location = fakeUrl.replace('%s%', user_input);
}

Django Admin - add collapse to a fieldset, but have it start expanded

Is there a way to make a fieldset collapsible, but start expanded? When you add collapse to the fieldset classes, it gets the functionality but starts collapsed. I've taken a look at the JS that shows/hides the fieldset content, but it doesn't look like there's anything in there to do what I'd like it to, so I'm assuming I'll have to roll my own. Just wanted to check before I went through that effort.
admin.py:
class PageAdmin(admin.ModelAdmin):
fieldsets = (
(None, {
'fields': ('title', 'content', )
}),
('Other Informations', {
'classes': ('collapse', 'open'),
'fields': ('slug', 'create-date',)
}),
)
templates/app_label/model_name/change_form.html:
{% extends "admin/model_name/change_form.html" %}
{% block extrahead %}
{{ block.super }}
<script src="{{ STATIC_URL }}admin/js/collapse-open.js" type="text/javascript"></script>
{% endblock %}
static/admin/js/collapse-open.js:
(function($) {
$(document).ready(function() {
$('fieldset.collapse.open').removeClass('collapsed');
});
})(django.jQuery);
I know this is real old but I also just came across this issue. After thinking about it way too hard I found an easy solution which seems to get the job done involving 0 plugins or additional js.
Within fieldsets construct Add 'collapse in' rather than 'collapse' to class:
fieldsets = [
('Start Expanded', {
'fields': ['field1', 'field2', 'field3'],
'classes': ['collapse in',]
})
]
django-grappelli provides this as one of the features. Here's the wiki page about that feature (with screenshots).
Accoding with the grappelli docs only need to add "classes" : ('grp-collapse grp-closed')
for example
class EntryOptions(admin.ModelAdmin):
...
fieldsets = (
('', {
'fields': ('title', 'subtitle', 'slug', 'pub_date', 'status',),
}),
('Flags', {
'classes': ('grp-collapse grp-closed',),
'fields' : ('flag_front', 'flag_sticky', 'flag_allow_comments',),
}),
note: if you use grappelli version < 2.4 use 'grp-closed' instead 'collapse-closed'*
actually 'collapse-close' still is working but is recommended to use the new classes
Starting from Setomidor answer, I'd like to suggest a simpler alternative that does exactly what you want (if Grappelli is not an option, obviously).
Create the template override as explained (admin/(app)/(model)/change_form.html) and instead of removing the collapsible effect for the "add" model case, simply call the click method of the field-set collapser (i.e. the small link with the show/hide text) to have the whole field-set expanded as soon as the page loads.
The quickest hack I could find was to add a new class start-open to the fieldset
classes = ['collapse', 'start-open']
and then modify static/admin/js/collapse.js.
from:
// Add toggle to anchor tag
var toggles = document.querySelectorAll('fieldset.collapse a.collapse-toggle');
var toggleFunc = function(ev) {
ev.preventDefault();
var fieldset = closestElem(this, 'fieldset');
if (fieldset.classList.contains('collapsed')) {
// Show
this.textContent = gettext('Hide');
fieldset.classList.remove('collapsed');
} else {
// Hide
this.textContent = gettext('Show');
fieldset.classList.add('collapsed');
}
};
for (i = 0; i < toggles.length; i++) {
toggles[i].addEventListener('click', toggleFunc);
}
to:
// Add toggle to anchor tag
var toggles = document.querySelectorAll('fieldset.collapse a.collapse-toggle');
// NEW: select toggles to open
var open_toggles = document.querySelectorAll('fieldset.collapse.start-open a.collapse-toggle');
var toggleFunc = function(ev) {
ev.preventDefault();
var fieldset = closestElem(this, 'fieldset');
if (fieldset.classList.contains('collapsed')) {
// Show
this.textContent = gettext('Hide');
fieldset.classList.remove('collapsed');
} else {
// Hide
this.textContent = gettext('Show');
fieldset.classList.add('collapsed');
}
};
for (i = 0; i < toggles.length; i++) {
toggles[i].addEventListener('click', toggleFunc);
}
// NEW: open toggles
for (i = 0; i < open_toggles.length; i++) {
toggles[i].click();
}
Old question, but I ran into the same one and came up with an answer which can be implemented using standard django:
create file: admin/(app)/(model)/change_form.html in your templates directory to make your (model) of your (app) use that form file.
Add this code to the file:
{% extends "admin/change_form.html" %}
{% block extrahead %}
<!-- Load superblock (where django.jquery resides) -->
{{ block.super }}
<!-- only do this on 'add' actions (and not 'change' actions) -->
{% if add and adminform %}
<script type="text/javascript">
(function($) {
$(document).ready(function($) {
//Remove the 'collapsed' class to make the fieldset open
$('.collapse').removeClass('collapsed');
//Remove the show/hide links
$('.collapse h2 a').remove();
//Tidy up by removing the parenthesis from all headings
var $headings = $(".collapse h2");
$headings.each(function(i, current){
var str = $(current).text();
parenthesisStart = str.indexOf('(');
$(current).text(str.substring(0, parenthesisStart));
});
});
})(django.jQuery);
</script>
{% endif %}
{% endblock %}
For more information about using django.jQuery instead of "regular" jQuery, see: http://blog.picante.co.nz/post/Customizing-Django-Admin-with-jQuery--Getting--is-not-a-function/
So this one worked for me:
class PageAdmin(admin.ModelAdmin):
fieldsets = (
(None, {
'fields': ('title', 'content', )
}),
('Other Informations', {
'classes': ('wide'),
'fields': ('slug', 'create-date',)
}),
)
With django 4.x, here is my admin/js/collapse.js
add start-open in class
'use strict';
{
window.addEventListener('load', function() {
// Add anchor tag for Show/Hide link
const fieldsets = document.querySelectorAll('fieldset.collapse');
// NEW: select toggles to open
var open_toggles = document.querySelectorAll('fieldset.collapse.start-open');
for (const [i, elem] of fieldsets.entries()) {
// Don't hide if fields in this fieldset have errors
if (elem.querySelectorAll('div.errors, ul.errorlist').length === 0) {
if (elem.classList[3] != 'start-open') {
elem.classList.add('collapsed');
}
const h2 = elem.querySelector('h2');
const link = document.createElement('a');
link.id = 'fieldsetcollapser' + i;
link.className = 'collapse-toggle';
link.href = '#';
if (elem.classList[3] != 'start-open') {
link.textContent = gettext('Show');
} else {
link.textContent = gettext('Hide');
}
h2.appendChild(document.createTextNode(' ('));
h2.appendChild(link);
h2.appendChild(document.createTextNode(')'));
}
}
// Add toggle to hide/show anchor tag
const toggleFunc = function(ev) {
if (ev.target.matches('.collapse-toggle')) {
ev.preventDefault();
ev.stopPropagation();
const fieldset = ev.target.closest('fieldset');
if (fieldset.classList.contains('collapsed')) {
// Show
ev.target.textContent = gettext('Hide');
fieldset.classList.remove('collapsed');
} else {
// Hide
ev.target.textContent = gettext('Show');
fieldset.classList.add('collapsed');
}
}
};
document.querySelectorAll('fieldset.module').forEach(function(el) {
el.addEventListener('click', toggleFunc);
});
});
}