Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to generate temporary URLs in Django

Tags:

url

django

Wondering if there is a good way to generate temporary URLs that expire in X days. Would like to email out a URL that the recipient can click to access a part of the site that then is inaccessible via that URL after some time period. No idea how to do this, with Django, or Python, or otherwise.

like image 679
chacmool Avatar asked Sep 01 '09 00:09

chacmool


People also ask

What is URLconf in Django?

A URLconf is like a table of contents for your Django-powered Web site. Basically, it's a mapping between URLs and the view functions that should be called for those URLs.

What is URL routing in Django?

A route can be defined as a URL that displays a particular web page on the browser. For example, if we want to visit the Educative website, we would head over to https://www.educative.io. Django lets us route URLs however we want and with no framework limitations.

How do I create a one time link in Django?

generate_link creates the one time link. You can do whatever you want with the link once you have it, whether it be email it or just present it to the user. one_time_link is the url for the single use link itself.

Is URL deprecated in Django?

Yes, if they upgrade to django-4.0, url will no longer be available.


5 Answers

If you don't expect to get a large response rate, then you should try to store all of the data in the URL itself. This way, you don't need to store anything in the database, and will have data storage proportional to the responses rather than the emails sent.

Updated: Let's say you had two strings that were unique for each user. You can pack them and unpack them with a protecting hash like this:

import hashlib, zlib
import cPickle as pickle
import urllib

my_secret = "michnorts"

def encode_data(data):
    """Turn `data` into a hash and an encoded string, suitable for use with `decode_data`."""
    text = zlib.compress(pickle.dumps(data, 0)).encode('base64').replace('\n', '')
    m = hashlib.md5(my_secret + text).hexdigest()[:12]
    return m, text

def decode_data(hash, enc):
    """The inverse of `encode_data`."""
    text = urllib.unquote(enc)
    m = hashlib.md5(my_secret + text).hexdigest()[:12]
    if m != hash:
        raise Exception("Bad hash!")
    data = pickle.loads(zlib.decompress(text.decode('base64')))
    return data

hash, enc = encode_data(['Hello', 'Goodbye'])
print hash, enc
print decode_data(hash, enc)

This produces:

849e77ae1b3c eJzTyCkw5ApW90jNyclX5yow4koMVnfPz09JqkwFco25EvUAqXwJnA==
['Hello', 'Goodbye']

In your email, include a URL that has both the hash and enc values (properly url-quoted). In your view function, use those two values with decode_data to retrieve the original data.

The zlib.compress may not be that helpful, depending on your data, you can experiment to see what works best for you.

like image 125
Ned Batchelder Avatar answered Sep 23 '22 15:09

Ned Batchelder


models

class TempUrl(models.Model):
    url_hash = models.CharField("Url", blank=False, max_length=32, unique=True)
    expires = models.DateTimeField("Expires")

views

def generate_url(request):
    # do actions that result creating the object and mailing it

def load_url(request, hash):
    url = get_object_or_404(TempUrl, url_hash=hash, expires__gte=datetime.now())
    data = get_some_data_or_whatever()
    return render_to_response('some_template.html', {'data':data}, 
                              context_instance=RequestContext(request))

urls

urlpatterns = patterns('', url(r'^temp/(?P<hash>\w+)/$', 'your.views.load_url', name="url"),)

//of course you need some imports and templates

like image 31
zalew Avatar answered Sep 24 '22 15:09

zalew


You could set this up with URLs like:

http://yoursite.com/temp/1a5h21j32

Your URLconf would look something like this:

from django.conf.urls.defaults import *

urlpatterns = patterns('',
    (r'^temp/(?P<hash>\w+)/$', 'yoursite.views.tempurl'),
)

...where tempurl is a view handler that fetches the appropriate page based on the hash. Or, sends a 404 if the page is expired.

like image 27
Matt Howell Avatar answered Sep 22 '22 15:09

Matt Howell


It depends on what you want to do - one-shot things like account activation or allowing a file to be downloaded could be done with a view which looks up a hash, checks a timestamp and performs an action or provides a file.

More complex stuff such as providing arbitrary data would also require the model containing some reference to that data so that you can decide what to send back. Finally, allowing access to multiple pages would probably involve setting something in the user's session and then using that to determine what they can see, followed by a redirect.

If you could provide more detail about what you're trying to do and how well you know Django, I can make a more specific reply.

like image 37
Dial Z Avatar answered Sep 25 '22 15:09

Dial Z


I think the solution lies within a combination of all the suggested solutions. I'd suggest using an expiring session so the link will expire within the time period you specify in the model. Combined with a redirect and middleware to check if a session attribute exists and the requested url requires it you can create somewhat secure parts of your site that can have nicer URLs that reference permanent parts of the site. I use this for demonstrating design/features for a limited time. This works to prevent forwarding... I don't do it but you could remove the temp url after first click so only the session attribute will provide access thus more effectively limiting to one user. I personally don't mind if the temp url gets forwarded knowing it will only last for a certain amount of time. Works well in a modified form for tracking invited visits as well.

like image 22
mogga Avatar answered Sep 21 '22 15:09

mogga