如何将django对象存储为会话变量(对象不是JSON可序列化的)?

hjqgdpho  于 2022-12-05  发布在  Go
关注(0)|答案(7)|浏览(143)

我有一个简单的观点

def foo(request):
   card = Card.objects.latest(datetime)
   request.session['card']=card

对于上面的代码,我得到了错误

"<Card: Card object> is not JSON serializable"

Django版本1.6.2.我做错了什么?

dvtswwa3

dvtswwa31#

在会话中,我只存储对象主键:

request.session['card'] = card.id

以及当从会话加载卡时,通过以下方式再次获得卡:

try:
    card = Card.objects.get(id=request.session['card'])
except (KeyError, Card.DoesNotExist):
    card = None

如果会话中没有card条目或者特定的卡不存在,则将card设置为None
默认情况下,会话数据被序列化为JSON。您也可以提供自己的序列化器,它知道如何存储card.id值或其他表示,并在反序列化时再次生成您的Card示例。

gywdnpxw

gywdnpxw2#

不幸的是,如果对象不是数据库对象,而是其他类型的对象(例如,日期时间或对象类Foo(object)),则建议的答案不起作用:不是数据库模型对象的传递。
当然,如果对象碰巧有一些id字段,你可以将id字段存储在数据库中,并从那里查找值,但通常它可能没有这样一个简单的值,唯一的方法是将数据转换为字符串,这样你就可以读取该字符串,并根据字符串中的信息重建对象。
在datetime对象的情况下,这会变得更加复杂,因为尽管简单的datetime对象可以通过不打印任何内容来打印出格式%Z,但strptime对象无法读取格式%Z(如果没有任何内容),它将阻塞,除非那里有有效时区规范-所以如果你有一个datetime对象,可能包含也可能不包含tzinfo字段,你真的必须做两次strptime,一次用%Z,然后如果它没有%Z就阻塞了。这很愚蠢。更愚蠢的是,datetime对象有一个fromtimestamp函数,但没有一个totimestamp函数,该函数统一产生一个fromtimestamp将读取的时间戳。如果有一个格式代码产生时间戳数字,我还没有找到一个,那么strftime/strptime就有一个问题,即它们不对称。

2admgd59

2admgd593#

有两种简单的方法可以做到这一点。

  • 如果每个对象同时属于单个会话,则将会话ID存储为模型字段,并更新模型。
  • 如果一个对象可以同时属于多个会话,请将www.example.com存储object.id为会话变量。
b1zrtrql

b1zrtrql4#

@Martijn是或可能是在会话变量中保存对象的正确方式。
但是这个问题在回到Django 1.5后就解决了。所以这个问题是专门针对Django 1.6.2的。
希望这对你有帮助。

pgpifvop

pgpifvop5#

Django 1.6或更高版本的对象不能存储在session中。如果你不想改变cookie值的行为,你可以在那里添加一个字典。这可以用于非数据库对象,如类对象等。

from django.core.serializers.json import DjangoJSONEncoder
import json     
card_dict = card.__dict__
card_dict .pop('_state', None) #Pop which are not json serialize
card_dict = json.dumps(card_dict , cls=DjangoJSONEncoder)
request.session['card'] = card_dict

希望对你有帮助!

xpszyzbs

xpszyzbs6#

--〉永远不想做这样的事情!〈--

使用sessionctypes的Django:请阅读下面的Martijn Pieters解释注解。

class MyObject:
  def stuff(self):
    return "stuff..."

my_obj = MyObject()
request.session['id_my_obj'] = id(my_obj)

...

id_my_obj = request.session.get('id_my_obj')

import ctypes
obj = ctypes.cast(id_my_obj, ctypes.py_object).value

print(obj.stuff())    
# returns "stuff..."
cbjzeqam

cbjzeqam7#

在我的例子中,由于对象是不可序列化的(selenium webdriver),我不得不使用全局变量,这非常有效。

相关问题