Django: How to integrate an app inside another app - django

i would like to know how can we "call" an application from inside a different application.
Basically, i have, for example :
a Calendar app that does a certain process to render a calendar in html
a "Main" app that shows the index.html of a website
I would like the Main app to invoke the Calendar app and insert what it renders in the sidebar.
The CodeIgniter framework for example, can handle that. A controller can invoke another controller, saves what it returns (the html output) in a variable, and finally includes this variable in the context that will be used to render the final html file.
Is that possible with Django ?
Thanks

Well, i think i may found a solution. I'm new to Django so i don't know if it's a good way to do it, if it brokes some conventional rules, if it open some security hole, or if simply, there are other better methods, but anyway, it works ...
So, i created my application Calendar, and my application Show.
I want Show to invoke Calendar, render its template, and then insert the result inside a template of Show.
To do that i used TemplateResponse instead of HttpResponse on the Calendar side :
# Calendar view
from django.template.response import TemplateResponse
def render_calendar(request):
return TemplateResponse(request, 'calendar/calendar-template.html', {})
Then on the Show side, get the TemplateResponse instance, invoke its render() method, and finally insert the rendered_content inside the context :
# Show view
from calendar import views
def show(request, show_id):
cal = views.render_calendar(request)
cal.render()
context = {"calendar": cal.rendered_content}
return render_to_response("show/show-template.html", context)
And that does the trick !

Sort of...
There is a template tag {% ssi %} that allows you to include one template inside another, the only thing is you will need to pass the parent template all the context variables needed in the other template.

Related

How to get url params from the HttpRequest object

Suppose, we have a url path:
path('something/<int:some_param>/test/', views.some_view)
When a user hits this url, django makes an instance of HttpRequest, that will be passed to the some_view view. Is there a way to get the some_param url parameter from the request object outside the some_view code? (for instance, to do some processing that depends on some_param in a custom middleware).
One possible solution is to parse the HttpRequest.path attribute, but is there any prebuilt way to do this?
Django calls your view with the request object and some_param, which you have access to inside views.some_view. Your function will have the following signature:
def some_view(request, some_param):
....
Or:
def some_view(request, **kwargs):
some_param=kwargs.get('some_param', None)
You can then use some_param inside your view to do whatever you need to do with it, save it in a database, put it in a cookie, do calculations with it, get some database data with it, etc. Then once you're done, you need to return a response object. Usually by calling render or TemplateResponse with a template or returning HttpResponse without a template. You render templates providing a context dictionary which you are free to put anything you like into (like some_param), which makes it available to be rendered in your HTML template. That rendered HTML template is then returned as response to your user through the magic of the render function or TemplateResponse class, which ends the view process. I.e. like so:
return TemplateResponse(request, 'template.html', context)
To store some_param in between views, you'll need to save it in the database, store it in the user's session, or use a cookie. Or pass it to the next view inside the url or outside the url via /?param=some_param. Without saying what you need some_param for later on, it's hard to solve your issue.
The one possible solution here is to use the resolve function from django.urls module. It is extremely uselful if you want to access the URL parameters from URL path that is related to a HttpRequest object outside a view function. For example, get the URL params and process them in the custom middleware or other parts of your code.
Example:
from django.urls import resolve
...
func, args, kwargs = resolve(some_request.path)

Can I have a CMSPluginBase class method directly return a custom plugin's html?

I would like to create a Django CMS plugin primarily used as a child of a TextPlugin (djangocms-text-ckeditor). It is meant to return a link to an application page.
To this end I subclass CMSPluginBase as described in the doc. It seems that the CMSPluginBase is relying on each plugin to have its own template.
Do I have to have a template.html file or can I write a method for the CMSPluginBase subclass that directly returns the rendered html (essentially something really simple like 'App link') and avoid the invocation of a template to be rendered?
Thanks very much for helping out!
Figured it out!
It seems that the render_template does not have to be a string. It can be a django.template.Template instance, too. So, here we go:
from django.template import Template
class MyLinkPlugin(CMSPluginBase):
render_template = Template('{{anchor}}')
def render(self, context, instance, placeholder):
context['link']='http://google.com'
context['anchor'] = 'Google me'
return(context)

Django include the same variables in all views

I want to include the same variables in all the views , to avoid repeating , i've been looking at django docs and found the generic display views and i tried it but it doesnt seems to work.
Any idea how to do this ?
Write a template context processor:
def add_foo(request):
return {'var': 'foo'}
Save this to a file, lets say custom_context.py, put it inside the same directory as your views.py.
Then, add it to your TEMPLATE_CONTEXT_PROCESSORS setting - make sure you keep the default ones, otherwise other functions may not work. You need to add the Python path, so add yourapp.custom_context.add_foo,
Now, whenever you return a RequestContext instance (you can do this by using the render shortcut, and all class based views automatically return a RequestContext instance); the variable var will be available in your templates, as {{ var }}.

Passing request to custom Django template loader

I want to write custom template loader for my Django app which looks for a specific folder based on a key that is part of the request.
Let me get into more details to be clear. Assume that I will be getting a key on every request(which I populate using a middleware).
Example: request.key could be 'india' or 'usa' or 'uk'.
I want my template loader to look for the template "templates/<key>/<template.html>". So when I say {% include "home.html" %}, I want the template loader to load "templates/india/home.html" or "templates/usa/home.html" or "templates/uk/home.html" based on the request.
Is there a way to pass the request object to a custom template loader?
I've been searching for the same solution and, after a couple days of searching, decided to use threading.local(). Simply make the request object global for the duration of the HTTP request processing! Commence rotten tomato throwing from the gallery.
Let me explain:
As of Django 1.8 (according to the development version docs) the "dirs" argument for all template finding functions will be deprecated. (ref)
This means that there are no arguments passed into a custom template loader other than the template name being requested and the list of template directories. If you want to access paramters in the request URL (or even the session information) you'll have to "reach out" into some other storage mechanism.
import threading
_local = threading.local()
class CustomMiddleware:
def process_request(self, request):
_local.request = request
def load_template_source(template_name, template_dirs=None):
if _local.request:
# Get the request URL and work your magic here!
pass
In my case it wasn't the request object (directly) I was after but rather what site (I'm developing a SaaS solution) the template should be rendered for.
To find the template to render Django uses the get_template method which only gets the template_name and optional dirs argument. So you cannot really pass the request there.
However, if you customize your render_to_response function to pass along a dirs argument you should be able to do it.
For example (assuming you are using a RequestContext as most people would):
from django import shortcuts
from django.conf import settings
def render_to_response(template_name, dictionary=None, context_instance=None, content_type=None, dirs):
assert context_instance, 'This method requires a `RequestContext` instance to function'
if not dirs:
dirs = []
dirs.append(os.path.join(settings.BASE_TEMPLATE_DIR, context_instance['request'].key)
return shortcuts.render_to_response(template_name, dictionary, context_instance, content_type, dirs)

Passing template variables from URL to FormPreview in Django

I'm a Django noob and fear the answer to my question is fairly obvious, but hoping someone can help.
I'm building an app that includes the same form on every page, with the content surrounding the form and the model instance to which the form data is tied dependent on a value passed in the URL. Works fine using the standard Form class and (URL, 'template.html', myapp.view) in URLconf, like so:
url(r'^listings/(?P<listing_id>\d+)/submit$', 'myapp.views.lister'),
With FormPreview, however, instead of calling the view in the URLconf, you're calling the subclass with the view functionality baked in.
url(r'^listings/(?P<listing_id>\d+)/submit$', PickFormPreview(PickForm)),
From what I can gather from the docs, FormPreview uses parse_params to pass values captured in the URL to state.self, which I believe is a dictionary. Unfortunately given my level of experience, I can't figure out from this barebones understanding how to customize my FormPreview subclass how to pass the listing_id captured in the URL to a template variable in my form.html template called by FormPreview. Do I somehow need to override parse_params? Or somehow pass state.listing_id? Or am I missing it entirely?
Any help much appreciated!
You're on the right track. The parse_params method in FormPreview does not do anything, but it is the correct method to override in your subclass.
The following example saves listing_id to self.state.listing_id, which is available in the template context.
class PickFormPreview(FormPreview):
def parse_params(self, *args, **kwargs)
"""
Saves listing_id from the url to state
"""
self.state['listing_id'] = kwargs['listing_id']
Then in your template, you access it as:
Listing {{ state.listing_id }}