Sunday, February 19, 2017

Templates

So far I have not done much template rendering except listing all the papers in the BibTex file. But before moving on to more complex stuff, I am trying to read as much as possible.

To begin with Django used the concept of loose coupling - URLs, views and data. With the URLconf list in urls.py, Django specifies which URL will call which function in views.py. Therefore, it is possible that the functionality of a URL can be changed by changing the view function without affecting any other part of the code. The view function on the other hand can access the database and render a template while passing the necessary data extracted from the database or from the URL. The template which should be rendered can be changed in the view function without changing any other part of the code. Finally, models.py specifies the structure of the database that can be changed independent of the views or the URLs. Of course, functions in views.py have to be designed flexibly enough the be able to adapt to changes in the database and the URLs.

Within the view functions, I have been reading about templates and contexts. The simplest way to generate a display on a webpage is using the HttpResponse() function. As an example:

return HttpResponse("Hello world")

will display Hello World in a webpage corresponding to the URL that points to the function with the above return statement. But to do more complex stuff, you would need a separate HTML file. This again is in alignment with the concept of loose coupling. The contents of the webpage should be separate from the view function that acts as the buffer between the URL and the database.

Suppose a separate HTML file was to exist in the templates folder in the application folder paperarchive/papercollection. This is the default directory that Django will search for templates when the 'APP_DIRS'=True is set in TEMPLATES variable in settings.py. The other option is to specify a list of directories in DIRS in the same variable. The conventional way to load this HTML file is with the get_template function in django.template.loader. So, suppose:

from django.template.loader import get_template
t = get_template("my_html.html")

is present in a view function, the template object t will be created with the contents of the HTML file. This HTML file could be a simple "Hello world" display as before or could be more complicated with variables called template tags and a bit of programming to deal with these template tags.

Since, variables are present in the template, they need data. The data is in the form of a dictionary with the keys being the variable names in the HTML file. This dictionary of variables is the context. So,

from django.template import Context
c = Context({"name": "Django"})

Will create a context object with the variable "name" being "Django". To pass this data to the HTML file, the template object that was created with the HTML file is rendered with this context by:

t.render(c)

When the view function returns the above template with the context,

return t.render(c)

The webpage is displayed with the data we specified. This concept is fairly convenient as the HTML file can be a regular HTML file with some amount of programming in the form of template tags. The view function can change the variables that are needed by the HTML file by extracting from the database or from user entered data in forms using the HTTP request object "request".

To simplify the above process, there are two functions in Django in django.shortcuts - render and render_to_response. They are similar but render_to_response is being discouraged as it may be discontinued later. The above process of creating a template object and rendering it with a context can be performed in one line as:

render(request, "my_html.html" , {"name": "django"})

or

render_to_response("my_html.html" , {"name": "django"})

Only difference is render needs the request object to be the first argument while render_to_response doesn't.

Additionally, these two functions also provide the possibility of context_processors. Instead of just the template and the context, a RequestContext object can be passed as a context_instance. So,

render(request, "my_html.html" , {"name": "django"} ,
context_instance = RequestContext(request [, context dictionary]
[, processors = <custom_processors>])
)

I took some time reading back and forth about this. RequestContext takes the request object as the first argument and will generate a context object that contains global variables that Django provides by default to save you the trouble from writing code. For example, context data about the user logged in etc. Check out the "context_processors" list in TEMPLATES variables in settings.py. This list contains the default global context processors. A context processor is a function that returns a dictionary which becomes the context and takes the request object as the only single argument. So the default global processors in the settings.py file are functions that are automatically added when a RequestContext function appears anywhere in a view function and these provide as context data that a user can conveniently use for a number of reasons like user authentication etc. Additionally, to the RequestContext function can be added custom processors which the user specifically has designed. The only requirement as before is that these custom processors should take as an argument the request object and return a dictionary as context data. The only catch in using the RequestContext seems to be that a number of context variables will be provided to the template that may not be needed as it calls all the context processors listed in the settings.py file.

So, the Context() function specifies data while RequestContext() function requests data and also allows you to add custom processors which add their data. So choosing to use Context() or RequestContext() seems to depend only on whether the user needs those global data that Django automatically generates or whether the user wishes to call other user-defined context processors that return code specific context data.

No comments:

Post a Comment