Reputation: 5366
#In my views.py file
def home(request):
myfunc()
return render(request, "home.html", {})
It takes awhile for home.html to load because it is executing the function myfunc every time that it is clicked. Is there a way to have myfunc loaded on the server before home.html is accessed so that it loads faster. Also is it possible to have myfunc be called every 15 minutes instead of everytime home.html is accessed?
Upvotes: 0
Views: 3014
Reputation: 7835
Is there a way to have myfunc loaded on the server before home.html is accessed so that it loads faster. Also is it possible to have myfunc be called every 15 minutes instead of everytime home.html is accessed?
I think you have three ways you could solve this problem:
1) Caching
With caching, you just stash the results of a heavy computation so it's saved after the first time. The benefits here are that it's pretty easy to use and easy to set up and pretty fast, but the first time it's accessed (and every time it's been invalidated) it'll be slow and you are limited in the size of what you can store in the cache (typically 1MB in the case of memcached).
Once you get your cache server setup, you typically can use Django's decorator:
from django.views.decorators.cache import cache_page
@cache_page(60 * 15)
def my_view(request):
In your case, it doesn't look like you're actually using the results of myfunc
, so you don't have any data to actually cache? Thus, caching won't help much.
2) Cron
Probably a better solution for you is to create a management command that calls myfunc
, and then create an entry in your server's crontab, to run this every fifteen minutes.
Let's say you've got a Django management command called update_myfunc
. Then, you can edit your server's crontab and add a line such as the following:
*/15 * * * * /location/of/python /var/www/yourproject/manage.py update_myfunc
This would run the command every fifteen minutes on whatever server where you have edited the crontab. (To edit a crontab, you enter the command crontab -e
.
3) Celery
You can also run this command asynchronously using Celery or even use celerybeat
which would take the place of the cron entry above.
To do this, you need to install a message queue (Redis is pretty easy one to install), then you need to configure it in your settings file. You will also need the Celery Python library, and then you will need to get Celery running on that server either as a worker or via celerybeat (probably celerybeat is what you want).
4) Combination of the above
There's also a fourth option, which is to combine some of the above. Let's say, for example, that myfunc
does a bunch of computations which are stored in the database and then it assembles the data it has computed somehow to be used in the view.
What you can do in that case is separate its functionality into two parts: the computation part and the view-helping part. You can then run the computation part using celery or cron every fifteen minutes, and then you can cache the view that calls the view-helping part.
Further, you can actually manually put stuff in your cache if you're not storing this computation in the database. In that case, you could stash some stuff in the cache and then retrieve using a specially created cache key when you need it for your view.
Upvotes: 5
Reputation: 18513
The answer depends on:
If myfunc()
is not related to the current request/session in any way, it should be executed once globally, when the Django app starts, with its results cached for later use. For instance, you can put the code in urls.py, which is guaranteed to be executed.
Else if myfunc()
is related to current request, but the response does not need its result, it can be executed asynchronously (HTTP response is returned before it runs). The standard solution is to use a message queue. Read about Celery
, a message queue adapter for Django.
Else if the response does depend on the result of myfunc()
, there is not much you can do, other than optimizing myfunc()
.
For periodical execution, perhaps you want to do it with a cron job. Another way is to use message queue, with a task that put itself back into queue after execution.
Upvotes: 1