Как хранить объекты django в качестве переменных сеанса (объект не является сериализуемым JSON)?

У меня простой вид

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

Для приведенного выше кода я получаю сообщение об ошибке

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

версия Django 1.6.2. Что я делаю не так?

Ответ 1

@Martijn является или может быть правильным способом сохранения объекта в переменных сеанса.

Но проблема была решена, возвращаясь к Django 1.5. Поэтому этот вопрос специально предназначен для django 1.6.2.

Надеюсь, это поможет.

Ответ 2

В cookie я просто сохранил первичный ключ объекта:

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

и при загрузке карты из сеанса снова получите карту:

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

который установит card в None, если в сеансе нет записи card или не существует конкретной карты.

Ответ 3

Есть два простых способа сделать это.

  • Если каждый объект принадлежит к одному сеансу одновременно, сохраните идентификатор сеанса в качестве поля модели и обновите модели.
  • Если объект может принадлежать нескольким сеансам одновременно, храните object.id в качестве переменной сеанса.

Ответ 4

К сожалению, предложенный ответ не работает, если объект не является объектом базы данных, а некоторым другим видом объекта - например, datetime или объектным классом Foo (object): pass, который не является объектом модели базы данных.

Конечно, если объект имеет некоторое поле id, вы можете сохранить поле id в базе данных и посмотреть там значение, но, как правило, оно может не иметь такого простого значения, и единственный способ - преобразовать данные чтобы вы могли прочитать эту строку и восстановить объект на основе информации в строке.

В случае объекта datetime это усложняется тем фактом, что, хотя наивный объект datetime может распечатать формат% Z, просто ничего не распечатывая, объект strptime не может читать формат% Z, если ничего нет, это будет задыхаться, если там не существует допустимой спецификации часового пояса, поэтому, если у вас есть объект datetime, который может содержать или не содержать поле tzinfo, вам действительно нужно сделать strptime дважды один раз с% Z, а затем, если он захлопнется без% Z. Это глупо. Это делается еще глубже из-за того, что объекты datetime имеют функцию fromtimestamp, но не функцию totimestamp, которая равномерно создает временную метку, которую будет читать fromtimestamp. Если есть код формата, который производит номер метки времени, я не нашел один и снова, strftime/strptime страдают от того, что они не являются симметричными, как описано выше.

Ответ 5

В Django вы можете сделать следующее, используя session и ctypes:

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..."

Ответ 6

Объекты не могут быть сохранены в сеансе от Django 1.6 или выше. Если вы не хотите изменять поведение значения 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 

Надеюсь, это поможет вам!