155

I have a web site which shows different content based on a location the visitor chooses. e.g: User enters in 55812 as the zip. I know what city and area lat/long. that is and give them their content pertinent to that area. My question is how can I store this in a cookie so that when they return they are not required to always enter their zip code?

I see it as follows:

  1. Set persistent cookie based on their area.
  2. When they return read cookie, grab zipcode.
  3. Return content based on the zip code in their cookie.

I can't seem to find any solid information on setting a cookie. Any help is greatly appreciated.

Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
Jeffrey
  • 1,621
  • 2
  • 12
  • 7
  • Those who are looking for setting a `cookie` and `rendering a template` together,see [this](https://stackoverflow.com/a/17334840/9217577) answer. – TheGuardener Mar 30 '20 at 05:56
  • https://stackoverflow.com/questions/4581789/how-do-i-get-user-ip-address-in-django/4581997#4581997 IP might solve the problem. – AnonymousUser Dec 03 '21 at 03:35

6 Answers6

306

Using Django's session framework should cover most scenarios, but Django also now provide direct cookie manipulation methods on the request and response objects (so you don't need a helper function).

Setting a cookie:

def view(request):
  response = HttpResponse('blah')
  response.set_cookie('cookie_name', 'cookie_value')

Retrieving a cookie:

def view(request):
  value = request.COOKIES.get('cookie_name')
  if value is None:
    # Cookie is not set

  # OR

  try:
    value = request.COOKIES['cookie_name']
  except KeyError:
    # Cookie is not set
Richard de Wit
  • 7,102
  • 7
  • 44
  • 54
Peter
  • 3,305
  • 2
  • 15
  • 5
  • 11
    Just to update - 'has_key' has been replaced with 'in'. – skaz Dec 06 '14 at 15:58
  • 19
    A more pythonic way would be to call request.COOKIES.get('cookie_name') – Charlesthk Jun 13 '16 at 06:41
  • let me ask you a silly question, this cookies persist between other uses sessions? – Diego Vinícius Oct 20 '17 at 19:06
  • Nothing of value to add here, but when framework solutions exist, it's often better to use them rather than using custom helper functions for the job, especially if there's no good reason not to do it. These solutions may not have been available at first but they sure are, so why not use them? It makes for a simpler code and might handle more cases than what our custom helpers would think of handling, which is in itself a good argument in my opinion. – vincent-lg Feb 16 '19 at 10:29
  • 4
    If you're wondering how to create a Django response object from a Django request object, read this: https://stackoverflow.com/questions/17057536/how-to-set-cookie-in-django-and-then-render-template – Raoul Jun 21 '19 at 17:34
86

UPDATE : check Peter's answer below for a builtin solution :

This is a helper to set a persistent cookie:

import datetime

def set_cookie(response, key, value, days_expire=7):
    if days_expire is None:
        max_age = 365 * 24 * 60 * 60  # one year
    else:
        max_age = days_expire * 24 * 60 * 60
    expires = datetime.datetime.strftime(
        datetime.datetime.utcnow() + datetime.timedelta(seconds=max_age),
        "%a, %d-%b-%Y %H:%M:%S GMT",
    )
    response.set_cookie(
        key,
        value,
        max_age=max_age,
        expires=expires,
        domain=settings.SESSION_COOKIE_DOMAIN,
        secure=settings.SESSION_COOKIE_SECURE or None,
    )

Use the following code before sending a response.

def view(request):
    response = HttpResponse("hello")
    set_cookie(response, 'name', 'jujule')
    return response

UPDATE : check Peter's answer below for a builtin solution :

tony
  • 870
  • 7
  • 16
jujule
  • 11,125
  • 3
  • 42
  • 63
  • any problem if settings.SESSION_COOKIE_DOMAIN is not set? – panchicore Aug 26 '10 at 22:26
  • 1
    anyway django itselfs sets a default SESSION_COOKIE_DOMAIN. think about this setting if you need to share cookie across multiple subdomains. – jujule Aug 31 '10 at 20:46
  • 14
    -1 on that, django comes with an method to set cookies https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpResponse.set_cookie – fetzig Jan 11 '12 at 13:49
  • 2
    @klemens : yes and i finally call the django method in my example; its just a shortcut (from 2009) that simplify date processing. – jujule Jan 13 '12 at 23:08
  • 5
    i don't care but, fyi: useless helper function were already useless in 2009. https://docs.djangoproject.com/en/1.0/ref/request-response/#django.http.HttpResponse.set_cookie (django 1.0 was released sept 2008, as far as i know) – fetzig Jan 24 '12 at 14:31
  • true man ! and the builtin method now accept only expires and autocalculate max_age accordingly. – jujule Mar 29 '12 at 18:40
  • This answer is over ten years old and has been made obsolete multiple times. – Chris Conlan May 24 '20 at 19:39
19

You could manually set the cookie, but depending on your use case (and if you might want to add more types of persistent/session data in future) it might make more sense to use Django's sessions feature. This will let you get and set variables tied internally to the user's session cookie. Cool thing about this is that if you want to store a lot of data tied to a user's session, storing it all in cookies will add a lot of weight to HTTP requests and responses. With sessions the session cookie is all that is sent back and forth (though there is the overhead on Django's end of storing the session data to keep in mind).

Ben Regenspan
  • 10,058
  • 2
  • 33
  • 44
  • 4
    Good point! One note, you can reduce the HTTP weight by hosting static content on a separate domain (not subdomain), so that the cookies are not sent on those requests. http://stackoverflow.com/questions/72394/what-should-a-developer-know-before-building-a-public-web-site/305381#305381 – John Paulett Oct 28 '09 at 02:32
  • @JohnPaulett's comment is outdated given the existence of the Django Sessions framework. There should no longer be any need to minimize total data storage on cookie-based workflows. – Chris Conlan May 24 '20 at 19:38
6

Anyone interested in doing this should read the documentation of the Django Sessions framework. It stores a session ID in the user's cookies, but maps all the cookies-like data to your database. This is an improvement on the typical cookies-based workflow for HTTP requests.

Here is an example with a Django view ...

def homepage(request):

    request.session.setdefault('how_many_visits', 0)
    request.session['how_many_visits'] += 1

    print(request.session['how_many_visits'])

    return render(request, 'home.html', {})

If you keep visiting the page over and over, you'll see the value start incrementing up from 1 until you clear your cookies, visit on a new browser, go incognito, or do anything else that sidesteps Django's Session ID cookie.

Chris Conlan
  • 2,774
  • 1
  • 19
  • 23
0

In addition to jujule's answer below you can find a solution that shows how to set a cookie to Class Based Views responses. You can apply this solution to your view classes that extends from TemplateView, ListView or View.

Below a modified version of jujule's persistent cookie setter method:

import datetime

from django.http import HttpResponse


def set_cookie(
    response: HttpResponse,
    key: str,
    value: str,
    cookie_host: str,
    days_expire: int = 365,
):
    max_age = days_expire * 24 * 60 * 60
    expires = datetime.datetime.strftime(
        datetime.datetime.utcnow() + datetime.timedelta(days=days_expire), "%a, %d-%b-%Y %H:%M:%S GMT",
    )
    domain = cookie_host.split(":")[0]
    response.set_cookie(
        key,
        value,
        max_age=max_age,
        expires=expires,
        domain=domain,
        secure=False,
    )

And sample class based view example that adds a cookie using persistent cookie setter

class BaseView(TemplateView):
    template_name = "YOUR_TEMPLATE_FILE_PATH"

    def get(self, request, *args, **kwargs):
        response = super().get(request, *args, **kwargs)
        set_cookie(
            response=response,
            key="COOKIE_KEY",
            value="COOKIE_VALUE",  
            cookie_host=request.get_host(),
            days_expire=7,
        )
        return response
abdullahselek
  • 7,893
  • 3
  • 50
  • 40
0

You can set cookies in these ways as shown below. *You must return the object otherwise cookies are not set to a browser different from Django sessions which can set the session id cookies to a browser without returning the object and you can see my question and my answer which explain why to use response.set_cookie() rather than response.cookies[] to set cookies and I asked the question about how to set a dictionary or list to a cookie and get it properly and you can see my answer explaining how to delete cookies.

render() and set_cookie():

from django.shortcuts import render

def my_view(request):
    response = render(request, 'index.html', {})
    response.set_cookie('name', 'John')
    response.cookies['age'] = 27
    return response # Must return the object

render_to_string(), HttpResponse() and set_cookie():

from django.template.loader import render_to_string
from django.http import HttpResponse

def my_view(request):
    rts = render_to_string('index.html', {})
    response = HttpResponse(rts)
    response.set_cookie('name', 'John')
    response.cookies['age'] = 27
    return response # Must return the object

HttpResponse() and set_cookie():

from django.http import HttpResponse

def my_view(request):
    response = HttpResponse('View')
    response.set_cookie('name', 'John')
    response.cookies['age'] = 27
    return response # Must return the object

redirect() and set_cookie():

from django.shortcuts import redirect

def my_view(request):
    response = redirect('https://example.com/')
    response.set_cookie('name', 'John')
    response.cookies['age'] = 27
    return response # Must return the object

HttpResponseRedirect() and set_cookie():

from django.http import HttpResponseRedirect

def my_view(request):
    response = HttpResponseRedirect('https://example.com/')
    response.set_cookie('name', 'John')
    response.cookies['age'] = 27
    return response # Must return the object

And, you can get the cookies with request.COOKIES['key'] and request.COOKIES.get('key') as shown below. *request.COOKIES.get() returns None by default if the key doesn't exist and you can change None to other value like Doesn't exist by setting it to the 2nd argument as shown below:

from django.shortcuts import render

def my_view(request):
    print(request.COOKIES['name']) # John
    print(request.COOKIES.get('age')) # 27
    print(request.COOKIES.get('gender')) # None
    print(request.COOKIES.get('gender', "Doesn't exist")) # Doesn't exist
    return render(request, 'index.html', {})

And, you can get cookies with request.COOKIES.key in Django Templates as shown below:

# "templates/index.html"

{{ request.COOKIES.name }} {# John #}
{{ request.COOKIES.age }} {# 27 #}

And, you can delete the cookies with response.delete_cookie() as shown below. *You must return the object otherwise cookies are not deleted from a browser:

from django.shortcuts import render

def my_view(request):
    response = render(request, 'index.html', {})
    response.delete_cookie('name')
    response.delete_cookie('age')
    return response # Must return the object
Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129