如何在Django中设置和获取cookies?

158

我有一个网站,根据访问者选择的位置显示不同的内容。例如:用户输入55812作为邮编。我知道对应的城市和地区的经纬度,并提供与该地区相关的内容。我的问题是,我如何将这些信息存储在cookie中,以便当他们返回时不需要始终输入他们的邮编?

我将其分解如下:

  1. 基于他们的地区设置持久性cookie。
  2. 当他们返回时读取cookie,获取邮编。
  3. 根据他们cookie中的邮编返回相应的内容。

我似乎找不到关于设置cookie的确切信息。非常感谢任何帮助。


如果您正在寻找同时设置“cookie”和“渲染模板”的方法,请参阅此答案 - TheGuardener
https://dev59.com/uG455IYBdhLWcg3wAvbQ#4581997 IP可能会解决问题。 - AnonymousUser
6个回答

308
使用Django的会话框架应该可以满足大多数情况,但Django现在还提供了直接操作请求和响应对象的cookie方法(因此您不需要帮助函数)。

设置cookie:

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

检索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

11
更新一下 - 'has_key' 已被替换为 'in'。 - skaz
19
更符合 Python 风格的方法是调用 request.COOKIES.get('cookie_name')。 - Charlesthk
让我问一个愚蠢的问题,这些Cookies会在其他用户的会话之间保留吗? - Diego Vinícius
没有什么有价值的东西可以在这里添加,但是当框架解决方案存在时,最好使用它们而不是为工作使用自定义帮助函数,特别是如果没有充分的理由不这样做。这些解决方案可能一开始并不可用,但现在肯定是可用的,那为什么不使用它们呢?这会使代码更简单,并且可能处理比我们自定义的帮助程序想要处理的更多的情况,这本身就是一个很好的论据。 - vincent-lg
4
如果您想知道如何从Django请求对象创建一个Django响应对象,请阅读此内容:https://dev59.com/8GQn5IYBdhLWcg3wJ0UO - Raoul

87

更新:请查看下面Peter的答案,其中提供了一个内置解决方案:

这是一个设置持久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,
    )

在发送响应之前,请使用以下代码。

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

更新:请查看下面Peter的答案,其中包含一个内置的解决方案:


1
无论如何,Django本身设置了默认的SESSION_COOKIE_DOMAIN。如果您需要在多个子域之间共享cookie,请考虑此设置。 - jujule
14
明白,django自带一个方法可以设置cookies。具体可参考https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpResponse.set_cookie - fetzig
2
@klemens:是的,我最终在我的示例中调用了Django方法;这只是一个快捷方式(来自2009年),可以简化日期处理。 - jujule
5
我不在乎,但是提醒你一下:无用的辅助函数在2009年已经无用了。https://docs.djangoproject.com/en/1.0/ref/request-response/#django.http.HttpResponse.set_cookie(据我所知,django 1.0于2008年9月发布)。 - fetzig
真的!现在内置方法只接受过期时间参数,并自动计算最大年龄。 - jujule
显示剩余2条评论

19
你可以手动设置cookie,但根据你的用例(以及如果你将来可能想添加更多类型的持久/会话数据),使用Django的会话功能可能更有意义。这将允许你获取和设置与用户会话cookie内部绑定的变量。很酷的一件事是,如果你想存储与用户会话相关的大量数据,在cookie中存储所有数据将增加HTTP请求和响应的负担。使用会话,只有会话cookie来回发送(尽管需要考虑Django端存储会话数据的开销)。

4
好的观点!但需要注意的是,您可以通过在单独的域上(而不是子域)托管静态内容来减少HTTP负载,这样在这些请求中就不会发送cookie。http://stackoverflow.com/questions/72394/what-should-a-developer-know-before-building-a-public-web-site/305381#305381 - John Paulett
@JohnPaulett的评论已经过时,因为Django Sessions框架已经存在。在基于cookie的工作流中,不再需要最小化总数据存储。 - Chris Conlan

6

对于任何有兴趣做这个的人,应该阅读Django Sessions框架的文档。它将会话ID存储在用户的cookie中,但将所有类似于cookie的数据映射到数据库中。这是HTTP请求的典型基于cookie的工作流的改进。

以下是一个带有Django视图的示例...

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', {})

如果您一遍又一遍地访问此页面,您会看到该值从1开始递增,直到您清除cookie、在新的浏览器上访问或使用隐身模式等绕过 Django 的 Session ID cookie 的任何操作。


0
除了下面jujule的答案之外,您还可以找到一种解决方案,显示如何将cookie设置为基于类的视图响应。 您可以将此解决方案应用于扩展自TemplateViewListViewView的视图类。
下面是jujule的持久cookie设置器方法的修改版本:
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,
    )

一个基于类的视图示例,使用持久化cookie设置器添加一个cookie。

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

0
你可以按照下面的方式设置cookie。*如果你不返回对象,那么除了Django sessions可以在浏览器中设置会话ID cookie之外,其他情况下都无法设置cookie。你可以查看我的问题我的答案,解释了为什么要使用response.set_cookie()来设置cookie,而不是使用response.cookies[]。我曾经问过这个问题,关于如何正确地将字典或列表设置为cookie并获取它,你可以看到我的答案解释了如何删除cookie。

render()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()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()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()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

而且,您可以像下面显示的那样通过request.COOKIES['key']request.COOKIES.get('key')获取到cookie。request.COOKIES.get()默认情况下返回None,如果键不存在,您可以将None更改为其他值,例如将其设置为第二个参数中的Doesn't exist,如下所示:

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', {})

而且,在Django模板中,您可以使用request.COOKIES.key获取cookie,如下所示:

# "templates/index.html"

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

而且,你可以像下面展示的那样使用response.delete_cookie()来删除cookies。*你必须返回对象,否则浏览器中的cookies不会被删除。
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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接