I have a Django website as follows:
site has several views
each view has its own template to show its data
each template extends a base template
base template is the base of the site, has all the JS/CSS and the basic layout
So up until now it's all good. So now we have the master head of the site (which exists in the base template), and it is common to all the views.
But now I want to make it dynamic, and add some dynamic data to it. On which view do I do this? All my views are basically render_to_response('viewtemplate.html', someContext). So how do add a common view to a base template?
Obviously I will not duplicate the common code to each separate view...
I think I'm missing something fundamental in the MVT basis of Django.
You want to use context_instance and RequestContexts.
First, add at the top of your views.py:
from django.template import RequestContext
Then, update all of your views to look like:
def someview(request, ...)
...
return render_to_response('viewtemplate.html', someContext, context_instance=RequestContext(request))
In your settings.py, add:
TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.auth',
...
'myproj.app.context_processors.dynamic',
'myproj.app.context_processors.sidebar',
'myproj.app.context_processors.etc',
)
Each of these context_processors is a function takes the request object and returns a context in the form of a dictionary. Just put all the functions in context_processors.py inside the appropriate app. For example, a blog might have a sidebar with a list of recent entries and comments. context_processors.py would just define:
def sidebar(request):
recent_entry_list = Entry.objects...
recent_comment_list = Comment.objects...
return {'recent_entry_list': recent_entry_list, 'recent_comment_list': recent_comment_list}
You can add as many or as few as you like.
For more, check out the Django Template Docs.
Context processors and RequestContext (see Tyler's answer) are the way to go for data that is used on every page load. For data that you may need on various views, but not all (especially data that isn't really related to the primary purpose of the view, but appears in something like a navigation sidebar), it often makes most sense to define a custom template tag for retrieving the data.
or use a generic view, because they are automatically passed the request context.
a simple direct to template generic view can be used to avoid having to import/pass in the request context.
Related
I have a view inheriting from LoginRequiredMixin, TemplateView, which renders some data using the admin/base_site.html template as the base. I treat it as a part of the admin interface, so it requires an administrator login. I'd like to make this view a little bit more a part of the Django admin interface by enabling the standard sidebar navigation on the left-hand side.
Note that I don't have a custom ModelAdmin definition anywhere, I simply render the template at some predefined URL. There are no models used in the interface either, it parses and displays data from database-unrelated sources.
Currently, I just build the required context data manually, e.g.:
data = super().get_context_data(**kwargs)
data.update(**{
"is_popup": False,
"site_header": None,
"is_nav_sidebar_enabled": True,
"has_permission": True,
"title": "My title",
"subtitle": None,
"site_url": None,
"available_apps": []
})
The sidebar is visible, but displays an error message:
Adding an app to available_apps ("available_apps": ["my_app"]) doesn't help either:
So my question is - how do I do that? Is there a class I can inherit from to achieve this behaviour? Or a method I can call to get all required context data for base_site.html? Or perhaps I should insert some information in my template? Perhaps I need an AdminSite object, or can somehow call methods of the default one?
By accident I noticed there is a DefaultAdminSite object in django.contrib.admin.sites, and it's instantiated as site. Therefore, in my case, simply using site is sufficient.
from django.contrib.admin import AdminSite
from django.contrib.admin.sites import site
admin_site: AdminSite = site
data.update(**admin_site.each_context(self.request))
Furthermore, turns out I can just use the apps in case importing site would be an issue, just like DefaultAdminSite does it:
AdminSiteClass = import_string(apps.get_app_config("admin").default_site)
self._wrapped = AdminSiteClass()
The app_list.html template which is included in your base template requires a context variable available_apps with a structure as described here.
As you probably won't be able to make this include work properly with your app you could also override the {% block nav-sidebar %} in your base template and provide some HTML that fits your use-case.
But after all it's probably not such a good idea to reuse templates which are made for a different app (admin) with your app because it's difficult to predict how they will behave, what their requirements are and beyond this maintainance in the long term will also be a problem as they might change with future Django versions.
You have to include django admin's default context variables used in the template. This can be done by calling each_context function:
data.update(self.admin_site.each_context(request))
I also have custom admin views and templates in my projects and this works well for me.
I am learning Django and I programming a CRUD for various objects. Currently I need to generate three templates per object: one for creation, one for update and one for a list. Look at how many templates I got in the picture.
The process is becoming painful.
What I am doing wrong and how to correct it?
Thanks.
From your comment:
The problem is that If I need to make a change, for example, add a new button, I have to make it in all the templates.
That sounds wrong. Either a button belong to one type of thing and then it should only exist in that template, or it should be on every page and then it should be in the base template.
You can make one template with your basic page layout (including such buttons), and have "blocks" in them that are then filled out by each template that extends the base template.
See the Django documentation about template inheritance.
Also, I think that in most cases the "create" and "update" pages are going to be extremely similar; usually they use the same template, one with data already filled in, the other without.
You could have a base template, then a generic list template and a generic edit/create template, with templates for each type of thing extending the list and the edit templates to fill in only the relevant fields.
Also, maybe you use HTML that is close enough to what the Django forms can render themselves. Then as long as you call the edit/create form the same in each of your views (like "form"), the template can just render the form and they can all use the same template.
If you're building a big web-app then this is normal for templates to be more.
Heavy (big) web-app means = more templates + more code + more time + more features
I am working on my first django project which is also my first backend project. In the tutorials/reading I have completed, I haven't come across passing information back to django without a modelform.
My intention is to calculate a value on a page using javascript and pass it to django when a user hits a submit button on that page. The submit button will also be a link to another page. I know I could process the information in a view via the url if I knew how to pass the information back to django.
I'm aware that django uses MVC and as I have my models and views in place, I am lead to believe that this has something to do with controllers.
Basically, I would like to know how to pass information from a page to django as a user follows a link to another page. I understand that this isn't the place for long step by step tutorials on specific topics but I would appreciate any links to resources on this subject. I don't know what this process is even called so I can't search documentation for it.
EDIT:
From further reading, I think that I want to be using the submit button to GET or POST the value. In this particular case, POST is probably better. Could someone confirm that this is true?
Yes, generally POST is a better way of submitting data than GET. There is a bit of a confusion about terminology in Django. While Django is, indeed MVC, models are models, but views are in fact controllers and views are templates. Since you are going to use AJAX to submit and retrieve the data, you don't care about templates. So what you most likely want is something like this
in your urls.py as part of your urlpatterns variable
url(r'mything/$', MyView.as_view())
in your views.py
from django.views import View
from django.http import HttpResponse
class MyView(View):
def post(self, request):
data = request.POST
... do your thing ...
return HttpResponse(results)
and in your javascript
jQuery.post('/mything/', data, function() { whatever you do here })
There're many ways, you can achieve this in django. Following are the two ways, that I generally prefer :-
1) As a query string parameter in the URL
eg. http://localhost/getPatientInfo?patientId=23&name=Sachin
2) Making URL dynamic, to include the information in the view itself.
eg. http://localhost/patientInfo/23/Sachin
In case 1:-
You will have to do,
patientId = request.GET["patientId"]
name = request.GET["patientName"]
In case 2:
Your URL conf will be something like :
urls = [
url("^patientInfo/(\d+)/([^/]+)$", yourViewFunc)
]
And in your view func :-
def yourViewFunc(request, patientId, patientName):
# your logic goes here
pass
For info. related to URLConf, refer to https://docs.djangoproject.com/en/1.10/topics/http/urls/#example
I'm looking for ways of adding custom actions to a Django admin change page. I am not looking for actions that can be added to the dropdown box in the overview.
One model in my Django application contains information about documents, and those are automatically compiled to PDF files at the frontend. I'd like to give the administrator the possibility to quickly render the PDF directly from the change page to be able to quickly check the results.
I've already played around with overriding change_form.html/submit_line.html, and it's absolutely no problem to add a button. But I wonder how to extend the admin module in a clean way so that it includes my custom action.
Since custom admin views are basically just normal views there aren't many specialities. A few things you should consider for a cleaner integration:
Add the url pattern through get_urls() of the AdminSite.
Provide the current_app argument to RequestContext or Context when rendering a template which subclasses admin templates.
EDIT:
Found a an example here:
http://shrenikp.webs.com/apps/blog/show/5211522-add-custom-view-method-for-django-admin-model-
Note, that the example doesn't utilize the current_app argument i've mentioned. I suppose your view to generate the PDF just returns a HttpResponse with the appropriate content type rather than rendering a response with a Context, so it's not needed. All in all the current_app only makes sense when you subclass an admin template used by your custom view which actually makes use of current_app somewhere.
The example encapsulates the urls and view in a ModelAdmin. It is also possible to do this through a AdminSite subclass, but at least in your use case this is probably overkill.
By the way, overriding the change_form.html template for your app to add a button to the standard change view is just fine. There is no special api for this in the admin (unfortunately).
I have a parent template that I'm using in many parts of the site, called base.html. This template holds a lot of functional components, such as buttons that trigger different forms (inside modal windows) allowing users to upload different kinds of content, etc. I want users to be able to click these buttons from almost any part of the site (from all the templates that inherit from base.html).
I've written a view that handles the main page of the site, HomeView (it renders homepage.html, which inherits from base.html). I've written a bunch of functionality into this view, which handles all the uploads.
Since many templates are going to inherit from base.html, and therefore have all that same functionality, do I have to copy-and-paste the hundreds of lines of code from the HomeView into the views that render all the other pages??
There's got to be a better way, right?
How do I make sure that the functionality in a parent base template holds true for all views which call child templates that inherit from this base template?
you can put all the lines of code from HomeView in a separate function let be func
and have func return a dictionary containing all context variables needed
and call it whenever needed so your HomeView would look like this:
def HomeView(request):
dict = func(request)
... # rest of code that is not common with other views
and your func would look like:
def func(request):
#all repeated code
#put all needed variables in a dictionary and return it
dict = {'var1': 4, 'var2': "a String" ...}
return dict
I believe separating out your upload related functionality into separate views will be better way to go about it. That way all your templates (inheriting from base.html) will refer to appropriate view for uploads.
You can use HTTP_REFERER header to redirect to appropriate page from the upload views.
You can render many templates in just one view by requiring unique value in each or use request session.
Use TemplateResponse instead of HttpResponse in home_view. This way you will be able to update context and switch template on the response.
Call home_view inside other views like this:
from django.template.response import TemplateResponse
def other_view( request ):
#produce other_context
t = home_view( request )
t.context.update( other_context )
t.template = 'other_template.html'
return t
Load the functionality part with ajax on your base.html.
That way you have a view_method that deals exclusively with those funcionalities.