How to modify the admin template in django - python

i use the django's default admin for the admin site, and i create a app named "project"
Then in the project change form, i want to show and dynamic image, i plan to draw some charts using the google API, so i must put change the html form to add a in the html file as below:
So my question is that how can i modify the django's default templates for this page, i can not find the form in templates/ folder, is this page named "change_form"? "change_list"? or some other names. If so ,how do i only change the form for app "Project" since maybe i will create some other apps in the same level with "project"

You need a place for static files which is valid.
Then place an admin directory inside that static files directory.
Then add your addname as a directory like this:
Root
yourapp
static
admin
yourapp
file_to_overwrite
Find your Django files. Then go to:
contrib/admin/templates/admin
On OSX this would be:
/Library/Python/2.7/site-packages/django/contrib/admin/templates/admin
Copy the file you want to overwrite to yourapp directory like above.
EDIT:
If you want to change a single form for a single app:
For example:
Root
yourapp
static
admin
yourapp
modelname
change_form.html
Only the model "modelname" will be affected by this html-file.

A good way to do this as the docs suggests is go with #Rickard Zachrisson answer but instead of copying it use the "extends" block and import super.
this should be a better approach since you are not directly overriding the admin templates but instead inheriting them.
This is how the docs suggests to do it when inserting JS for example:
{% extends 'admin/change_form.html' %}
{% load static %}
{% block admin_change_form_document_ready %}
{{ block.super }}
<script type="text/javascript" src="{% static 'app/formset_handlers.js' %}"></script>
{% endblock %}

Related

Simplest way to assign version numbers to static files in django to avoid caching?

I want to introduce versioning on static files so that the browser doesn't cache them since I will be putting out changes quite often. So currently in my index.html, I call my two files index.css and index.js like so
{% extends "base.html" %} {% load staticfiles %}
<link rel="stylesheet" href="{% static 'css/index.css' %}">
<script type="text/javascript" src="{% static 'js/index.js' %}"></script>
Now I want to introduce versioning such that the browser is forced to fetch the latest files when I update the files with some changes. Offcourse this doesn't mean it should always fetch new files but when I ask it to.
So to do that I need to register a template tag. So I make a folder called templatetags and keep it in the same level where my models.py and urls.py are. (Keeping it elsewhere Django throws error). I name the file as assign_version.py. This is the content inside the file
import time
from django import template
register = template.Library()
#register.simple_tag
def static_version():
print("version changed!!")
version = int(round(time.time() * 1000))
return version
The templatetags folder looks like
assign_version.py assign_version.pyc __init__.py __init__.pyc
Now I change my index.html to refer to these two tags like so
{% extends "base.html" %} {% load staticfiles %} {% load assign_version %}
<link rel="stylesheet" href="{% static 'css/index.css' %}?v={{ static_version }}">
<script type="text/javascript" src="{% static 'js/index.js' %}?v={{ static_version }}"></script>
Then I restart my server. But nothing happens. I do not see the print that I have put to confirm whether this template is being called on restart. Also changing js or css and restarting doesn't seem to force the browser to fetch new files. What am I doing wrong?
First of all please be aware that templatetags are used with {% your_tag %} and not with {{ your_tag }}. So replace {{ static_version }} with {% static_version %} in your template.
However, as the tag is used every time django generates the html page from your template a new "version" is put into your page every time the page is loaded. So you will probably not achieve waht you are intending.
If you want to save the time every time the server is restarted an approach I can think of is using the AppConfig in your apps.py. It is called whan the app is reloaded. So maybe something like this:
In your assing_version.py add the variable "version" as a "global" variable and use this as your version:
#assign_version.py
import time
from django import template
register = template.Library()
version = 0
#register.simple_tag
def static_version():
print("version changed!!")
return version
Set the version in your apps.py
from django.apps import AppConfig
import time
from . templatetags import assign_version
class YourappConfig(AppConfig):
name = 'yourapp'
def ready(self):
assign_version.version = int(round(time.time() * 1000))
For this to work you need to load your app in settings.py with "yourapp.apps.YourappConfig" and not just with "yourapp".
You can use ManifestStaticFilesStorage to achieve this.
From the docs:.
A subclass of the StaticFilesStorage storage backend which stores the file names it handles by appending the MD5 hash of the file’s content to the filename. For example, the file css/styles.css would also be saved as css/styles.55e7cbb9ba48.css.
Reference:
https://docs.djangoproject.com/en/1.10/ref/contrib/staticfiles/#manifeststaticfilesstorage

How to add script type="module" in django admin

If I want some javascript functionality in my Django admin, I usually go about it using the Media class like this:
#admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
class Media:
js = ('js/my_script.js',)
But I now have a script that is a ES6 module so I would like Django to render it like:
<script src="path/to/static/js/my_script" type="module"></script>
and using the Media class doesn't render the type="module" attribute.
Any help or tips to achieve this? Thanks
You won't be able to use Media class for this, if you check at the code, the method will always render the same type="text/javascript".
If you really want to go with the Media way, you could create your own Mediaclass and inherit from forms.Media, then you could try using Media as a dynamic property that would be able to generate a script with type="module".
Another option is to use a custom template as suggested before, or even considering adding a templatetag to your app in order to add ES6 modules in your template.
In your custom change_form.html template, extend the admin_change_form_document_ready block and add the event listener code
{% extends 'admin/change_form.html' %}
{% load static %}
{% block admin_change_form_document_ready %}
{{ block.super }}
<script type="text/javascript" src="{% static 'app/your_file.js' %}"></script>
{% endblock %}
#admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
class Media:
module = ('js/my_script.js',)
You can just change js to replace module its define is type of src
It‘s working for me.

Adding css/js files to the home site in the admin's panel django

I am trying to add a simple script to my admin's panel in django. I am following this example from the doc, which works when I do this:
class ArticleAdmin(admin.ModelAdmin):
class Media:
js = ("my_code.js",)
admin.site.register(Article, ArticleAdmin)
my_code.js (which lives in STATICFILES_DIRS) gets executed when I open the "Article" link in the admin's panel (so this would be the example url: localhost:8000/admin/news/article/)
However, I want it to be executed in the home site, as in right after I login to the admin's panel (this would be the url:localhost:8000/admin/) . Where do I have to insert the class Media then?
Are you trying to make your custom javascript appear on all admin pages? Then the best thing to do is to override the default admin templatte.
Look in your django installation and find django/contrib/admin/templates/admin/base.html make a copy of it in templates/admin in your project folder. Then simply add the following to the html.
<script scr="my_code.js" type="text/javascript"></script>
Then the js will be available on all admin pages.
I found another way which is overriding instead of replacing as explained in here.
If you place the file base.html into templates/admin:
{% extends "admin/base.html" %}
{% load static %}
{% block footer %}
{{ block.super }}
<script type="text/javascript" src="{% static 'my_code.js' %}"></script>
{% endblock %}
This will insert the script after the footer in the at localhost:8000/admin/.
Here I am "overriding" the base.html. But since I am using .super (explained here) it adds the script after the footer tag.

Django include tag

We are using django with python. I am facing a problem with include tag. I want to include a header in all modules of application.
In application templates directory contains all the html files with subfolders of modules. In any sub-module if I am creating header html and including this tag in base.html then it is working.
But if I place the header html in parent directory, its not working for any sub-modules.
I even tried {% include "../header.html" %} in html with django template, but no luck.
The project structure fo my application, in which root directory I have templates, static, handlers folder. Inside templates I have sub1 and sub2 folders. In sub1 I have base.html and in templates parent directory base.html, header.html, index.html. See below:
Root
----templates
----------Sub1
-----------------base.html
----------Sub2
----------base.html
----------header.html
----------index.html
----static
----handlers
Django templates include tag does not recognize relative paths. You need to give it the path under your templates directory, so try using the following instead:
{% include "Sub2/header.html" %}
Update:
Seems like your "header.html" are on the "Sub2" level and not inside it i.e. it's directly under templates directory So you should try:
{% include "header.html" %}
I am not sure if I have understood you. Just try {% include "header.html" %}, the search of django template should start from template folder.
The template folder is configured in Django config file "setting.py".
TEMPLATE_PATH = os.path.join(BASE_DIR, 'templates')
In addition, I have a project which can seprate Django template develop from the back-end using webpack and support jade, es6 and scss. The readme is in chinese :(, but you can run the project and check the source code.
https://github.com/njleonzhang/webpack-django-starter

Google map Autocompletion in Django Admin Add form

I have a model which uses source and destination fields and these are usually populated from a frontend template. Template has two form fields which are associated with Google map autocomplete APIs. But if I want to create a new object through admin panel, how can I integrate autocomplete API with add form's source and destination fields?
You can easily use something like https://github.com/ubilabs/geocomplete/ in django admin —
Override the change form template to include the required js:
{% load staticfiles %}
{% block extrahead %}{{ block.super }}
<script src="http://maps.googleapis.com/maps/api/js?sensor=false&libraries=places"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/geocomplete/1.4/jquery.geocomplete.min.js"></script>
<script src="{% static 'path/to/your/js/geocomplete.js' %}"></script>
{% endblock %}
In your own js file:
$("#address_input").geocomplete();
Docs here on how to populate form using the library:
https://github.com/ubilabs/geocomplete/#populate-form-data
There is Django admin widget called django-location-field that does exactly what you ask. I use it in my projects.
https://github.com/caioariede/django-location-field

Categories

Resources