convert string to timezone iso format in python - python

i'm trying to convert a string with this form "2019-07-17T16:00:50.282203+01:30" to timezone format so i can update models.DateTimeField field.
models.py:
from django.utils import timezone
class task(models.Model):
title = models.CharField(max_length=100)
create_date = models.DateTimeField(default=timezone.now)
.
.
.
request will be like this:
{
"title": "editeddd task",
"create_date" : "2019-07-17T16:00:50.282203+01:30"
}
being stuck in converting UTC part.
view.py:
.
.
.
create_date = datetime.strptime(self.request.data['expiration_date'], '%Y-%m-%dT%H:%M:%S.%f%z')
.
.
‍‍the error is for %z part. it can converting "2019-07-17T16:00:50.282203+0130" but not "2019-07-17T16:00:50.282203+01:30" (notice to : in UTC part)

As you are referencing request.data, it looks as though you are using Django REST Framework. In that case the most straightforward way is to use DRF's serializers to parse / validate the incoming data.
from rest_framework import serializers
class TaskSerializer(serializers.ModelSerializer):
class Meta:
model = Task
fields = ('title', 'create_date')
If you just want to retrieve the validated data you can do:
>>> serializer = TaskSerializer(data=request.data)
>>> serializer.is_valid(raise_exception=True)
>>> serializer.validated_data
OrderedDict([('title', 'editeddd task'), ('create_date', datetime.datetime(2019, 7, 17, 14, 30, 50, 282203, tzinfo=<UTC>))])
Or if you want to save a new task:
task = serializer.save()
It's important to validate all incoming data and validating each field manually by reaching into request.POST or request.data tends to be error prone. DRF's serializers (or Django's forms) have a lot of pre-built logic and make the task significantly easier and safer.

Being strict while sending and tolerant while receiving, you should do a little string mangling on that create_date string before passing it on to strptime.
My suggestions is to work with a regular expression, or to have look at rreplace - How to replace the last occurrence of an expression in a string? to get rid of that last :.
Hope this helps!

Related

Django datetime format different from DRF serializer datetime format

I am trying to understand why this is happening. I have a Django DateTime field and Django Rest Framework serializer that uses the field.
I am trying to compare the dates for both of them and get the following results from JSON endpoint and model result:
DRF: 2018-12-21T19:17:59.353368Z
Model field: 2018-12-21T19:17:59.353368+00:00
Is there a way to make them similar? So, either to make both of them be "Z" or "+00:00."
It's because django rest framework uses it's own datetime formating. To change that, in your settings.py file, there should exist a dict variable called REST_FRAMEWORK (if not create it) and add this:
REST_FRAMEWORK = {
...
'DATETIME_FORMAT': "%Y-%m-%d - %H:%M:%S",
...
}
Also check USE_TZ variable state too in your settings.py
I came here from google looking for a quick fix to get this (e.g. copy and paste). So, borrowing from #RezaTorkamanAhmadi's answer, for anyone looking to get a DRF serializer DateTimeField to have the format 2018-12-21T19:17:59.353368+00:00 (the same format as the default models.DateTimeField so that your serialized values match your model values -- the OP's question and mine too) you're looking for either:
# settings.py
REST_FRAMEWORK = {
...
'DATETIME_FORMAT': "%Y-%m-%d %H:%M:%S.%f%z",
...
}
or if you just want it for a specific DateTimeField serializer field you're looking for
from rest_framework import serializers
class MySerializer(serializers.Serializer):
some_date = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S.%f%z")
Sources:
https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior
https://www.django-rest-framework.org/api-guide/fields/#datetimefield
https://stackoverflow.com/a/53893377/10541855 (Reza Torkaman
Ahmadi's answer)
Apart from previous answer, also you can change DateTime format in your serializer.
from rest_framework import serializers
class YourSerializer(serializers.ModelSerializer):
your_datetime_field = serializers.DateTimeField(format="%Y-%m-%dT%H:%M:%S")
class Meta:
model = YourModel
fields = '__all__'

ValueError badly formed hexadecimal UUID string django ListView

Assume all imports done.
I have a model like this:
class Package(models.Model):
uuid = models.UUIDField(default=uuid.uuid4, editable=False)
name = models.CharField(max_length=400)
Then I want to use generic ListView like so:
class PackageList(ListView):
model = Package
template_name = 'package/list.html'
All with url like so:
url(r'^package/list/$', views.PackageList.as_view(), name='package_list'),
When I visit the localhost:8000, I get
ValueError at /package/list/
badly formed hexadecimal UUID string
However, a DetailView generic view loads the detail based on the uuid successfully, without any issues.
The error comes up only when using the ListView.
What am I doing wrong?
Figured.
The url sequence was the culprit. Having sequence this way fixed it:
url(r'^travel/add/$', views.TravelAdd.as_view(), name='travel_add'),
url(r'^travel/list/$', views.TravelList.as_view(), name='travel_list'),
url(r'^travel/(?P<uuid>[\w-]+)/$', views.TravelDetail.as_view(), name='travel_detail'),
Previously, it was this:
url(r'^travel/add/$', views.TravelAdd.as_view(), name='travel_add'),
url(r'^travel/(?P<uuid>[\w-]+)/$', views.TravelDetail.as_view(), name='travel_detail'),
url(r'^travel/list/$', views.TravelList.as_view(), name='travel_list'),

Overriding create method in Django RestFramework to POST data

I'm currently using Django RestFramework to create APIs that use both GET and POST to retrieve/insert data within my Django application. I currently have a database model called TransactionDateTime that has a field called start_dt (see below), which takes DateTimeField. The challenge is that I'm passing a string in my json POST data structure (see below) and I need to override the create method in order to loop through the JSON structure to convert the string to the appropriate datetime structure. I know the logic to be used to successfully convert string to datetime, because I was able to perform it in the Django shell (see below), but I don't know how to override the create method and write the appropriate code within the create method to make this happen. Please assist. Below is a copy of my view that is successfully returning JSON data structure via GET, with a BIG question within the create method
TransactionDateTime model from models.py
class TransactionDateTime(models.Model):
room = models.ForeignKey(Room, on_delete = models.CASCADE)
start_dt = models.DateTimeField('start_dateTime')
end_dt = models.DateTimeField('end_dateTime', blank=True, null=True)
def __str__(self):
return str(self.start_dt)
Data Structure to be used on POST
[
{
"start_dt": "2015-01-28 03:00:00"
},
{
"start_dt": "2015-01-28 05:30:00"
}
]
Logic to convert string to datetime
from datetime import datetime
my_date = datetime.strptime('2015-01-28 05:30:00', '%Y-%m-%d %H:%M:%S')
Django Mixin and View
class DateTimeMixin(object):
serializer_class = SimpleSerializer4
permission_classes = (permissions.IsAuthenticated,)
class DateTimeViewSet(DateTimeMixin, generics.BulkModelViewSet):
def get_queryset(self):
num = self.kwargs['dt_rm']
num2 = self.kwargs['id']
r1 = Room.objects.get(id = num)
s1 = Schedule.objects.get(pk=num2)
u= self.request.user.pk
usr = User.objects.get(pk=u)
if(s1.user.username == usr.username):
queryset = r1.transactiondatetime_set.all()
return queryset
else: raise Http404("User does not exist")
def get_serializer_context(self):
num = self.kwargs['id']
s1 = Schedule.objects.get(pk=num)
var = s1.user.username
context = super(DateTimeViewSet, self).get_serializer_context()
return {'request' : var}
def created(self, request, *args, **kwargs):
???
I think the proper way to go about it is not to write your own custom create method, but rather to teach your serializer how to accept the date format you use, e.g.
class SimpleSerializer4(something_here):
...
start_dt = serializers.DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=['%Y-%m-%d %H:%M:%S'])
...
Then later all you have to do is to add CreateModelMixin to you ViewSet and it should work, e.g.
from rest_framework.mixins import CreateModelMixin
...
class DateTimeViewSet(DateTimeMixin, CreateModelMixin, generics.BulkModelViewSet):
...
Docs on DateTimeField here
Docs on extending view sets here
And I found it often very helpful to look how things are done in the rest_framework itself, so here is the link to the source on GitHub

DRF serializes datetime differently in the GET response vs POST response

class Event(models.Model):
start_date = models.DateTimeField()
end_date = models.DateTimeField()
class EventSerializer(serializers.ModelSerializer):
bar = serializers.SerializerMethodField()
class Meta:
model = Event
fields = ('id', 'start_date', 'end_date')
It works all fine and dandy:
GET .../api/v1/Event/
{
"count":23,
"next":null,
"previous":null,
"results":[{
"databaseId":101488,
"start_date":"2013-11-01T09:46:25",
"end_date":"2013-11-02T09:46:25"
},...
]}
Now when I create a new event:
POST /api/v1/Event/
{
"start_date":"2013-11-03T09:46:25",
"end_date":"2013-11-04T09:46:25"
}
In the JSON response I get:
{
"databaseId":101489,
"start_date":"2013-11-03T09:46:25.250000",
"end_date":"2013-11-04T09:46:25.750000"
}
So I get back a more precise format. I'd like to get back exactly the same format, so the client developer won't have to write different parser codes.
I'm using Python 2.7, DRF 3.1.3, Django 1.4.21 (I know it's old but it's a large codebase, one day we'll migrate).
So far I couldn't figure out what causes this, but explicitly enforcing format string helps:
start_date=serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S')

Django values get year from DateTimeField

I have a page where users can search for other users. The search is called with AJAX and the results are returned using JSON with the following code:
return HttpResponse(json.dumps({'users': list(users.values('first_name', 'last_name', 'gender', 'zip_code__city', 'zip_code__state')) }))
I have the users birthday stored in the model with birthday = models.DateTimeField(). I am trying to return just the year of the birthday with the results, but I am having trouble. Returning the whole date would work as well as I can always parse out the year later.
When I try just adding 'birthday' to the arguments in values, I get an error that it is not JSON serializable. I also tried 'birthday__year', but that returned an error that there was no such thing as 'year'.
How do I get the DateTimeField into the list?
Build a models.py method to return the year:
models.py
from django.db import models
class MyModel(models.Model):
birthday = models.DateTimeField()
def get_year(self):
return self.birthday.year
Then call this function from your views.py
You can't set a dynamic default like this, nor should you really need to store it in a database
Just make it a property (maybe even cached_property)
#property
def age(self):
return date.today().year - self.DOB.year

Categories