Django Sessions, handling of datetime types - django

I'm using sessions in a current django project and recently got a 'Object of type 'date' is not JSON serializable' error - due to the move_in_date field below.
When saving a modelform of the below model to the session via:
if form.is_valid():
request.session.update(form.cleaned_data)
my model:
class Address(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
house_name_number = models.CharField(max_length=255, verbose_name="house name or number")
street_name = models.CharField(max_length=255)
town_city = models.CharField(max_length=255)
county = models.CharField(max_length=255)
postcode = models.CharField(max_length=8)
same_address = models.BooleanField()
move_in_date = models.DateField(null=True, blank=True)
I've tried to solve the issue by using DjangoJSONEncoder as suggested by the docs, which can handle datetimes via the settings with SESSION_SERIALIZER=DjangoJSONEncoder (should this be a serializer rather than an encoder?), but trying that or SESSION_SERIALIZER=PickleSerializer both give an Attribute error - ... has no attribute 'rsplit'
Additionally I was using django wizard before which stores intermediate data (such as the field causing the date issue above) in the session. I've now switched that part of the app to use seperate views for flexibility (as signup wasn't just a linear path), django wizard doesn't have this issue, how does it get round this?
Updated with stacktrace
Traceback (most recent call last):
File "/Users/Barclay/.virtualenvs/switcher5/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner
response = get_response(request)
File "/Users/Barclay/.virtualenvs/switcher5/lib/python3.6/site-packages/django/utils/deprecation.py", line 142, in __call__
response = self.process_response(request, response)
File "/Users/Barclay/.virtualenvs/switcher5/lib/python3.6/site-packages/django/contrib/sessions/middleware.py", line 58, in process_response
request.session.save()
File "/Users/Barclay/.virtualenvs/switcher5/lib/python3.6/site-packages/django/contrib/sessions/backends/db.py", line 83, in save
obj = self.create_model_instance(data)
File "/Users/Barclay/.virtualenvs/switcher5/lib/python3.6/site-packages/django/contrib/sessions/backends/db.py", line 69, in create_model_instance
session_data=self.encode(data),
File "/Users/Barclay/.virtualenvs/switcher5/lib/python3.6/site-packages/django/contrib/sessions/backends/base.py", line 98, in encode
serialized = self.serializer().dumps(session_dict)
File "/Users/Barclay/.virtualenvs/switcher5/lib/python3.6/site-packages/django/core/signing.py", line 93, in dumps
return json.dumps(obj, separators=(',', ':')).encode('latin-1')
File "/usr/local/Cellar/python3/3.6.0/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/__init__.py", line 238, in dumps
**kw).encode(obj)
File "/usr/local/Cellar/python3/3.6.0/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/local/Cellar/python3/3.6.0/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 257, in iterencode
return _iterencode(o, 0)
File "/usr/local/Cellar/python3/3.6.0/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 180, in default
o.__class__.__name__)
TypeError: Object of type 'date' is not JSON serializable
Stack trace for trying DjangoJSONEncoder:
Traceback (most recent call last):
File "/Users/Barclay/.virtualenvs/switcher5/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner
response = get_response(request)
File "/Users/Barclay/.virtualenvs/switcher5/lib/python3.6/site-packages/django/utils/deprecation.py", line 138, in __call__
response = self.process_request(request)
File "/Users/Barclay/.virtualenvs/switcher5/lib/python3.6/site-packages/django/contrib/sessions/middleware.py", line 20, in process_request
request.session = self.SessionStore(session_key)
File "/Users/Barclay/.virtualenvs/switcher5/lib/python3.6/site-packages/django/contrib/sessions/backends/db.py", line 18, in __init__
super(SessionStore, self).__init__(session_key)
File "/Users/Barclay/.virtualenvs/switcher5/lib/python3.6/site-packages/django/contrib/sessions/backends/base.py", line 51, in __init__
self.serializer = import_string(settings.SESSION_SERIALIZER)
File "/Users/Barclay/.virtualenvs/switcher5/lib/python3.6/site-packages/django/utils/module_loading.py", line 15, in import_string
module_path, class_name = dotted_path.rsplit('.', 1)
AttributeError: type object 'DjangoJSONEncoder' has no attribute 'rsplit'

A few things of confusion are hitting you:
When setting the serializer, do not provide a class reference, but a dotted part. This is seen in the error:
module_path, class_name = dotted_path.rsplit('.', 1)
DjangoJSONEncoder isn't the right fix for a serializer. It is referenced in the documentation as a way to serialize models before putting them into the session.
If you want to make a smart serializer then you still need to create a Serializer, which should support a dumps and loads interface, that leverage a JsonEncoder and JsonDecoder respectively.
The Pickle serializer will work just fine, but as said you need to provide the dotted path.
If you want to use JSON as serializer, then this might be a good start:
from django.core.serializers.json import DjangoJSONEncoder
from django.core.signing import JSONSerializer as BaseJSONSerializer
class SmartJSONSerializer(BaseJSONSerializer):
def dumps(self, obj):
return json.dumps(obj, separators=(',', ':'), cls=DjangoJSONEncoder).encode('latin-1')

Related

TypeError and AssertionError after upgrade to Django 2

I'm tasked with upgrading a Django REST framework project from Django 1.8 to Django 2.x. I already ported the whole code from python 2.7 to python 3.7 and from Django 1.8 to 2.0.13. I'm using virtual envs.
I got it running on python 3.7 and Django 2.0.13, and RESTframework 3.11, although I ran into problems while trying to create new objects.
Here's the Traceback to my problem:
Traceback (most recent call last):
File "C:\Users\user1\Envs\projpy3\lib\site-packages\django\core\handlers\exception.py", line 35, in inner
response = get_response(request)
File "C:\Users\user1\Envs\projpy3\lib\site-packages\django\core\handlers\base.py", line 128, in _get_response
response = self.process_exception_by_middleware(e, request)
File "C:\Users\user1\Envs\projpy3\lib\site-packages\django\core\handlers\base.py", line 126, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\user1\Envs\projpy3\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "C:\Users\user1\projects\proj_py3\rest_framework\viewsets.py", line 114, in view
return self.dispatch(request, *args, **kwargs)
File "C:\Users\user1\projects\proj_py3\rest_framework\views.py", line 505, in dispatch
response = self.handle_exception(exc)
File "C:\Users\user1\projects\proj_py3\rest_framework\views.py", line 465, in handle_exception
self.raise_uncaught_exception(exc)
File "C:\Users\user1\projects\proj_py3\rest_framework\views.py", line 476, in raise_uncaught_exception
raise exc
File "C:\Users\user1\projects\proj_py3\rest_framework\views.py", line 502, in dispatch
response = handler(request, *args, **kwargs)
File "C:\Users\user1\projects\proj_py3\rest_framework\mixins.py", line 18, in create
serializer.is_valid(raise_exception=True)
File "C:\Users\user1\projects\proj_py3\rest_framework\serializers.py", line 219, in is_valid
self._validated_data = self.run_validation(self.initial_data)
File "C:\Users\user1\projects\proj_py3\rest_framework\serializers.py", line 418, in run_validation
value = self.to_internal_value(data)
File "C:\Users\user1\projects\proj_py3\rest_framework\serializers.py", line 471, in to_internal_value
for field in fields:
File "C:\Users\user1\projects\proj_py3\rest_framework\serializers.py", line 354, in _writable_fields
for field in self.fields.values():
File "C:\Users\user1\Envs\projpy3\lib\site-packages\django\utils\functional.py", line 36, in __get__
res = instance.__dict__[self.name] = self.func(instance)
File "C:\Users\user1\projects\proj_py3\rest_framework\serializers.py", line 348, in fields
for key, value in self.get_fields().items():
File "C:\Users\user1\projects\proj_py3\rest_framework\serializers.py", line 1027, in get_fields
field_names = self.get_field_names(declared_fields, info)
File "C:\Users\user1\projects\proj_py3\rest_framework\serializers.py", line 1128, in get_field_names
serializer_class=self.__class__.__name__
AssertionError: The field 'participantIDs' was declared on serializer OrderSerializer, but has not been included in the 'fields' option.
I don't understand why that exception only occurs in the new version of the code, since I didn't change the models, serializers, or views, aside from the version updates.
this is what the problematic serializer looks like:
class OrderSerializer(serializers.ModelSerializer):
created_by = ShortPersonSerializer(read_only=True, required=False)
modified_by = ShortPersonSerializer(read_only=True, required=False)
customer = OrderPersonSerializer(required=False, allow_null=True, partial=True)
...
...
participantIDs = serializers.SlugRelatedField(many=True, required=False, allow_null=True, slug_field='id', source='participants', queryset=Person.objects.all())
...
...
class Meta:
model = Order
fields = ('id', 'title','customer',
'customer_copy_id', 'customer_copy_salutation', 'customer_copy_first_name', 'customer_copy_last_name', 'created_at', 'created_by', 'modified_at', 'modified_by')
def create(self, validated_data):
customer_data = validated_data.pop('customer', None)
participants_data = validated_data.pop('participants', None)
if customer_data and customer_data is not None:
validated_data['customer'] = Person(pk=customer_data['id'])
order = Order.objects.create(**validated_data)
if participants_data and participants_data is not None:
setattr(order, 'participants', participants_data) # line 1
order.save() # line 2
...
Additional info:
Before this error was detected, I got a different error, with the following traceback:
Traceback (most recent call last):
...
...
File "C:\Users\user1\projects\proj_py3\rest_framework\serializers.py", line 204, in save
self.instance = self.create(validated_data)
File "C:\Users\user1\projects\proj_py3\orders\serializers.py", line 90, in create
setattr(order, 'participants', participants_data)
File "C:\Users\user1\Envs\projpy3\lib\site-packages\django\db\models\fields\related_descriptors.py", line 509, in __set__
% self._get_set_deprecation_msg_params(),
TypeError: Direct assignment to the forward side of a many-to-many set is prohibited. Use participants.set() instead.
so I had changed the serializer like this:
...
...
if participants_data and participants_data is not None:
#setattr(order, 'participants', participants_data) # line 1
order.save() # line 2
order.participants.set(participants_data)
...
ever since I've done that, I get the AssertionError instead of the TypeError, and I don't know how to revert that problem. Ofcourse I changed the code back, but I've also deleted all the compiled files in the project directory, I deleted the virtual env and created a new one, I ran a disk cleanup on Windows, I even uninstalled Python37 in order to install it again. Always rebooting inbetween. All to no avail.
UPDATE:
I compared the update and create methods in my project's serializers.py files with the ones in rest_framework version I'm using: rest_framework/serializers.py on GitHub
I changed them according to the newer version of the Django REST framework (the code was developed for an older version).
I also checked all the serializers of the other Apps in the project, and I found out, that all but the concerned App orders had the attribute participantsID in their Serializer's Meta class, in case it's supposed to access the other App through the other's Serializer.
In that case, it's like suggested in the comments: the AssertionError was there all along.
There is nothing else to do but to add the attribute to fields.
Add participantIDs to your fields attribute of OrderSerializer's Meta class
class OrderSerializer(serializers.ModelSerializer):
# other code snippets
class Meta:
model = Order
fields = (other-fields, 'participantIDs')
# other code snippets

Using GenericForeignKeys Correctly

I'm trying to use generic foreign keys, but I can't seem to get them to work properly.
First, some context: I've got a messaging app and a groups app. Now, I want to be able to have players/groups write pms (private messages) to other users/groups. Here's my Pm model:
class Pm(models.Model):
"""Represents a private message (a la email) from one user to another."""
title = models.CharField(max_length=settings.max_title_length, default="(Blank)")
slug = models.SlugField(max_length=settings.max_title_length, editable=False)
#This was my code from when I only allowed pms to go from user to another
#user
#author = models.ForeignKey(Player, related_name="written_messages")
#recipient = models.ForeignKey(Player, related_name="recieved_messages")
text = models.TextField(max_length=settings.max_post_length)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
#Both will be either a group or a player
author = generic.GenericForeignKey('content_type', 'object_id')
recipient = generic.GenericForeignKey('content_type', 'object_id')
#[snip]
and here's the relevant bits of my Group and Player models:
class Group(models.Model):
#[snip]
written_messages = generic.GenericRelation("messaging.Pm")
sent_messages = generic.GenericRelation("messaging.Pm")
class Player(My_Model):
user = models.OneToOneField(User)
#[snip]
written_messages = generic.GenericRelation("messaging.Pm")
sent_messages = generic.GenericRelation("messaging.Pm")
Does this look correct?
When I run it, I get this traceback (so obviously something's wrong):
Traceback (most recent call last):
File "/usr/local/lib/python3.2/dist-packages/django/core/urlresolvers.py", line 339, in urlconf_module
return self._urlconf_module
AttributeError: 'RegexURLResolver' object has no attribute '_urlconf_module'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3.2/wsgiref/handlers.py", line 137, in run
self.result = application(self.environ, self.start_response)
File "/usr/local/lib/python3.2/dist-packages/django/contrib/staticfiles/handlers.py", line 72, in __call__
return self.application(environ, start_response)
File "/usr/local/lib/python3.2/dist-packages/django/core/handlers/wsgi.py", line 180, in __call__
self.load_middleware()
File "/usr/local/lib/python3.2/dist-packages/django/core/handlers/base.py", line 49, in load_middleware
mw_instance = mw_class()
File "/usr/local/lib/python3.2/dist-packages/django/middleware/locale.py", line 24, in __init__
for url_pattern in get_resolver(None).url_patterns:
File "/usr/local/lib/python3.2/dist-packages/django/core/urlresolvers.py", line 346, in url_patterns
patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
File "/usr/local/lib/python3.2/dist-packages/django/core/urlresolvers.py", line 341, in urlconf_module
self._urlconf_module = import_module(self.urlconf_name)
File "/usr/local/lib/python3.2/dist-packages/django/utils/importlib.py", line 35, in import_module
__import__(name)
File "/home/mark/Dropbox/Public/Galcon/galcon/galcon/urls.py", line 40, in <module>
("^messages/", include("messaging.urls")),
File "/usr/local/lib/python3.2/dist-packages/django/conf/urls/__init__.py", line 26, in include
urlconf_module = import_module(urlconf_module)
File "/usr/local/lib/python3.2/dist-packages/django/utils/importlib.py", line 35, in import_module
__import__(name)
File "/home/mark/Dropbox/Public/Galcon/galcon/messaging/urls.py", line 3, in <module>
from . import views
File "/home/mark/Dropbox/Public/Galcon/galcon/messaging/views.py", line 10, in <module>
from . import my_forms
File "/home/mark/Dropbox/Public/Galcon/galcon/messaging/my_forms.py", line 5, in <module>
class Modify_Message_Form(forms.ModelForm):
File "/usr/local/lib/python3.2/dist-packages/django/forms/models.py", line 283, in __new__
raise FieldError(message)
django.core.exceptions.FieldError: Unknown field(s) (recipient) specified for Pm
The mentioned form is pretty simple:
class Modify_Message_Form(forms.ModelForm):
class Meta:
model = Pm
fields = ["title", "recipient", "text"]
What have I done wrong? Thanks!
Using the name of the GenericForeignKey in the form doesn't work as it's not actually a real field but more of a convenience. There's no widget to display the relationship; you usually display the content_type and object_id. If you want to see the relationship in the admin interface then I'd recommend looking at Grappelli.
You also need content_type and object_id fields for each GenericForeignKey.
author_content_type = models.ForeignKey(ContentType)
author_object_id = models.PositiveIntegerField()
recipient_content_type = models.ForeignKey(ContentType)
recipient_object_id = models.PositiveIntegerField()
author = generic.GenericForeignKey('author_content_type', 'author_object_id')
recipient = generic.GenericForeignKey('recipient_content_type', 'recipient_object_id')
I've not much experience with GenericRelations but from what I know you'd also need to specify the content_type and object_id fields in your Player and Group models.
written_messages = generic.GenericRelation(messaging.Pm
content_type_field='author_content_type',
object_id_field='author_object_id')
It seems, by looking at the traceback, that you cannot use GenericForeignKeys as form fields. But I think you can use recipient_content_type and recipient_content_id instead, which is what Django admin usually shows to users.

Django Tastypie: "error_message": "'bool' object has no attribute 'read'"

I am using Backbone.js + Tastypie + Django and am trying to save a model using patch = true to update the points on a model, like
this.save({
points: newPoints
}, {
patch: true
});
This issues a PUT request as it should with the request payload
points: 105
However, I get a 500 error message
{"error_message": "'bool' object has no attribute 'read'", "traceback": "Traceback (most recent call last):
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/tastypie/resources.py\", line 217, in wrapper
response = callback(request, *args, **kwargs)
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/tastypie/resources.py\", line 468, in dispatch_detail
return self.dispatch('detail', request, **kwargs)
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/tastypie/resources.py\", line 491, in dispatch
response = method(request, **kwargs)
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/tastypie/resources.py\", line 1656, in patch_detail
self.update_in_place(request, bundle, deserialized)
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/tastypie/resources.py\", line 1679, in update_in_place
return self.obj_update(bundle=original_bundle, **kwargs)
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/tastypie/resources.py\", line 2209, in obj_update
bundle = self.full_hydrate(bundle)
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/tastypie/resources.py\", line 909, in full_hydrate
value = field_object.hydrate(bundle)
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/tastypie/fields.py\", line 382, in hydrate
value = make_aware(parse(value))
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/dateutil/parser.py\", line 720, in parse
return DEFAULTPARSER.parse(timestr, **kwargs)
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/dateutil/parser.py\", line 308, in parse
res = self._parse(timestr, **kwargs)
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/dateutil/parser.py\", line 356, in _parse
l = _timelex.split(timestr)
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/dateutil/parser.py\", line 150, in split
return list(cls(s))
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/dateutil/parser.py\", line 147, in next
return self.__next__() # Python 2.x support
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/dateutil/parser.py\", line 141, in __next__
token = self.get_token()
File \"/Users/me/.virtualenvs/project/lib/python2.7/site-packages/dateutil/parser.py\", line 72, in get_token
nextchar = self.instream.read(1)
AttributeError: 'bool' object has no attribute 'read'
"}
Here is my model resource for UserProfile
class UserProfileResource(ModelResource):
"""A resource for the UserProfile model."""
class Meta:
queryset = UserProfile.objects.all()
resource_name = 'userprofile'
authorization = Authorization()
excludes = ['field_to_exclude']
always_return_data = True
Does anyone have tips on how to debug this error?
I had a field which was a datetimefield which was null, and instead of showing up as a a datetime in the api call, is showed up as a boolean. I'm not sure why this happened, but I think this is a bug in tastypie, or I misunderstood something about the configuration, or both.
I excluded this field from the tastypie resource and I was able to PUT and PATCH successfully to the model.

Django MongoDB QuerySet result Into JSON

I have these models:
class Projects(models.Model):
projectName =models.CharField(max_length = 100,unique=True,db_index=True)
projectManager = EmbeddedModelField('Users')
class Users(models.Model):
name = models.CharField(max_length = 100,unique=True)
designation = models.CharField(max_length =100 )
I need to return JSON from my view for all Projects objects,I tried json.dumps(Projects.objects.all()) but it did not worked,how do i accomplished it??
EDIT:
I used json.dumps(Projects.objects.all().values()) and got this:
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "D:\Python27\lib\json\__init__.py", line 238, in dumps
**kw).encode(obj)
File "D:\Python27\lib\json\encoder.py", line 203, in encode
chunks = list(chunks)
File "D:\Python27\lib\json\encoder.py", line 436, in _iterencode
o = _default(o)
File "D:\Python27\lib\json\encoder.py", line 178, in default
raise TypeError(repr(o) + " is not JSON serializable")
TypeError: [{'projectName': u'HELLO', 'projectManager': {u'id': u'4eb3b792b990a24e49f6bb26', u'name': u'anshul', u'designation': u'programmer', u'teams': []}, '
id': u'4eb3b7d0e814520db4000000'}] is not JSON serializable
Now i am getting the result what i want but why is this giving me error as well.
Try Jason.dumps-ing the result of Queryset.values().
Querysets are not serializable. You could try to use list(self.objects) instead self.objects to force the queryset to be processed as a list. In your case try something like this
json.dumps(list(Projects.objects.all().values()))

Error while using date between in django raw query

I am always getting this error TypeError: not all arguments converted during string formatting
Here is my query
State.objects.raw('...review_create_date between %s and %s group by error_type',[fromdate,todate])
Here fromdate=2011-05-21 and todate='2011-05-27'
The above query executes in mysql prompt but could not able to run in python shell
Please some one help me
Here is the traceback
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/local/lib/python2.6/dist-packages/django/db/models/query.py", line 1412, in __iter__
query = iter(self.query)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/sql/query.py", line 73, in __iter__
self._execute_query()
File "/usr/local/lib/python2.6/dist-packages/django/db/models/sql/query.py", line 87, in _execute_query
self.cursor.execute(self.sql, self.params)
File "/usr/local/lib/python2.6/dist-packages/django/db/backends/util.py", line 18, in execute
sql = self.db.ops.last_executed_query(self.cursor, sql, params)
File "/usr/local/lib/python2.6/dist-packages/django/db/backends/__init__.py", line 216, in last_executed_query
return smart_unicode(sql) % u_params
TypeError: not all arguments converted during string formatting
django raw sql query in view
I also faced this issue, so I changes the old formatting to new using
format. I it works for me.
models.py
class VehicleDamage(models.Model):
requestdate = models.DateTimeField("requestdate")
vendor_name = models.CharField("vendor_name", max_length=50)
class Meta:
managed=False
views.py
def location_damageReports(request):
#static date for testing
date_from = '2019-11-01'
date_to = '2019-21-01'
vehicle_damage_reports = VehicleDamage.objects.raw("SELECT * FROM VendorReport_vehicledamage WHERE requestdate BETWEEN '{0}' AND '{1}'".format(date_from, date_to))
damage_report = DashboardDamageReportSerializer(vehicle_damage_reports, many=True)
data={"data": damage_report.data}
return HttpResponse(json.dumps(data), content_type="application/json")
Try using ? instead of %s.