Making Django queries with localized dates - python

In my form I have a DateField called booking_date that is rendered with the AdminDateWidget. The contents of the booking_date field needs to be internationalized. The problem appears when I want to use the value of the field in something like this:
booking = Booking.objects.get(booking_number='BN34D', booking_date='2010-11-21')
But if my date format is '%d.%m.%Y':
booking = Booking.objects.get(booking_number='BN34D', booking_date='21.11.2010')
I get a 'ValidationError: Enter a valid date in YYYY-MM-DD format'
How can I make the query regardless of the date format used?

You should parse it first with a localized version of the strftime format.
from datetime import datetime
d = datetime.strptime('...')
booking.objects.get(..., booking_date=d.date())
Use these formats in strptime:
http://linux.die.net/man/3/strftime
You shouldn't rely on passing directly from the user into the query.
Looks like you should be doing the following from your specific example:
d = datetime.strptime('%d.%m.%Y')
booking = Booking.objects.get(booking_nmber='BN34D', booking_date=d)

As I understand your question, you don't know for sure in advance, which locale will be used. That can bring you into unsolvable problems. ("10-11-12" could be Oct 11, 2012 or Nov 12, 2010 or ...)
So you must have a limited, distinguishable set of possible formats. Then you can do:
POSSIBLE_FORMATS = ('%d.%m.%Y', '%Y-%m-%d', '...')
for f in POSSIBLE_FORMATS:
try:
d = datetime.date.strptime(date_str, f)
break
except ValueError:
continue
raise ValueError
booking = Booking.objects.get(booking_number='BN34D', booking_date=d)

I have solved the problem using this:
from django.utils import formats
formats.get_format('DATE_INPUT_FORMATS')[0]
This format is then used for parsing the date like xyld showed.

Related

Date Parsing problem while Integrating to Oracle PMS

I'm recieving date in PMS message something like this |GA090616|GD090617|
which means Guest Arrival is at 09-06-16 and Guest Deprature is at 09-06-17
I wanted to parse it as date using python.
I've also visited stack oveflow[1, 2 ...] for this but as solution I've found
from datetime import datetime
self.DATE_FROMAT='%d/%m/%y'
arrival_date=datetime.strptime('90616', self.DATE_FROMAT).date()
print(arrival_date)
and it's not possible to parse it like this due to its unclear format.
I'm not sure if 09 is a month or a date, but from what I've seen in documents and PDFs, it appears to be a month.
Is there any better solution for this kind of date parsing? or suggestions for my expectations.
09-06-16,
09-06-17
Note:
Please Just take the date from the string 090617 and parse it as a date. That will be helpful.
You can do this with regex matching, you can either split the string with msg.split("|") or not, but that depends on your use case.
import re
from datetime import datetime
msg = "GA090616|GD090617|"
DATE_FORMAT='%d%m%y'
ar = re.match("GA(\d{6})", msg)
dp = re.match("GD(\d{6})", msg)
guest_arrival = datetime.strptime(ar.group(1), DATE_FORMAT).date()
guest_departure = datetime.strptime(dp.group(1), DATE_FORMAT).date()
Although not fully tested, this should be a boilerplate as to how to retrieve the date from the message. Remember to remove the \ from the date format, as that is not included in the message.

Django rest framework timefield input format

After hours of searching, I found many posts that are related but wasn't able to help.
What I want to do is input eg: 10:30 AM into the TimeField.
In the django rest framework API on the browser, it is using this 10:30 AM format ('%I:%M %p').
But when I am using postman to test it, the output is in 24hr format ('%H:%M:%S'). I also tried to use 10:30 PM as input but the output I get is 10:30:00 instead of 22:30:00.
Many of the answers I found suggest to change the TimeField format in settings.py by using this line:
TIME_INPUT_FORMATS = ('%I:%M %p',)
but it doesn't work for me.
Sorry for my inexperience on django rest framework as I am still learning.
Here is the screenshot of the result.
On browser API:
On postman:
If you check the documentation on the TimeField you will see:
Signature: TimeField(format=api_settings.TIME_FORMAT, input_formats=None)
Where
format - A string representing the output format. If not specified, this defaults to the same value as the TIME_FORMAT settings key, which will be 'iso-8601' unless set. Setting to a format string indicates that to_representation return values should be coerced to string output. Format strings are described below. Setting this value to None indicates that Python.
input_formats - A list of strings representing the input formats which may be used to parse the date. If not specified, the TIME_INPUT_FORMATS setting will be used, which defaults to ['iso-8601'].
So you either can specify the format and input_formats on the serializer, or set the settings.TIME_FORMAT and settings.TIME_INPUT_FORMATS.
Let's set the first case:
class MySerializer(serializers.Serializer):
...
birthTime=serializers.TimeField(format='%I:%M %p', input_formats='%I:%M %p')
Some suggestions:
Make your variable names snake case: birth_time.
You may need to play a bit around with the input format because you may expect many different inputs:
input_formats=['%I:%M %p','%H:%M',...]
Convert the result in Serializer validate method and return it.
import time
t = time.strptime(timevalue_24hour, "%H:%M")
timevalue_12hour = time.strftime( "%I:%M %p", t )

Best practices to filter in Django

In one of the pages of my Django app I have a page that simply displays all employees information in a table:
Like so:
First Name: Last Name: Age: Hire Date:
Bob Johnson 21 03/19/2011
Fred Jackson 50 12/01/1999
Now, I prompt the user for 2 dates and I want to know if an employee was hired between those 2 dates.
For HTTP GET I just render the page and for HTTP POST I'm sending a URL with the variables in the URL.
my urls.py file has these patterns:
('^employees/employees_by_date/$','project.reports.filter_by_date'),
('^employees/employees_by_date/sort/(?P<begin_date>\d+)/(? P<end_date>\d+)/$', EmployeesByDate.as_view()),
And my filter_by_date function looks like this:
def filter_by_date(request):
if request.method == 'GET':
return render(request,"../templates/reports/employees_by_date.html",{'form':BasicPrompt(),})
else:
form = BasicPrompt(request.POST)
if form.is_valid():
begin_date = form.cleaned_data['begin_date']
end_date = form.cleaned_data['end_date']
return HttpResponseRedirect('../reports/employees_by_date/sort/'+str(begin_date)+'/'+str(end_date)+'/')
The code works fine, the problem is I'm new to web dev and this doesn't feel like I'm accomplishing this in the right way. I want to use best practices so can anyone either confirm I am or guide me in the proper way to filter by dates?
Thanks!
You're right, it's a bit awkward to query your API in that way. If you need to add the employee name and something else to the filter, you will end up with a very long URL and it won't be flexible.
Your filter parameters (start and end date) should be added as a query in the url and not be part of path.
In this case, the url would be employees/employees_by_date/?start_date=xxx&end_date=yyy and the dates can be retrieved in the view using start_date = request.GET['start_date].
If a form is used with method='get', the input in the form are automatically converted to a query and appended at the end of the url.
If no form is used, parameters need to be encoded with a function to be able to pass values with special characters like \/ $%.
Use Unix timestamps instead of mm/dd/yyyy dates. A unix timestamp is the number of seconds that have elapsed from Jan 1 1970. ("The Epoch".) So it's just a simple integer number. As I'm writing this, the Unix time is 1432071354.
They aren't very human-readable, but Unix timestamps are unambiguous, concise, and can be filtered for with the simple regex [\d]+.
You'll see lots of APIs around the web use them, for example Facebook. Scroll down to "time based pagination", those numbers are Unix timestamps.
The problem with mm/dd/yyyy dates is ambiguity. Is it mm/dd/yyyy (US)? or dd/mm/yyyy (elsewhere)? What about mm-dd-yyyy?

Python datetime.strptime Default

Is there a way to get datetime.strptime() to give me a default value on a failed parse (None in this case)? I have user entered data from a file that could be improperly formatted dates. The dates should be in the form mm/dd/yy, but some people have put them dd/mm/yy. So the file could look like this:
user1 01/30/14
user2 02/19/12
user3 27/02/11
I don't need to account for the improperly formatted dates, so I can just return None. I know I can do this with:
try:
return datetime.strptime(row[1], '%m/%d/%y')
except:
return None
But I'd like to have something a little more gracefully. Is anyone aware of a solution here?
Thanks in advance.
The datetime package does not offer a built-in solution to your problem.
A more graceful (close to your suggestion) solution would be to define your own function (for instance, in your utils.py file or equivalent).
from datetime import datetime
def strptime(date_string, format, default=None):
try:
return datetime.strptime(date_string, format)
except (ValueError, TypeError):
return default
The following exception will be raised (you might want to handle other exceptions):
TypeError: In case date_string is not a str (e.g. if you pass None)
ValueError: In case date_string mismatch the format
You could then import your strptime (from your utils for instance) instead of datetime.datetime.strptime.

Formating Django Datetime objects outside template

I love the date tag that comes with Django.
Exceptionally, I'd like to format a DateTime object in my view (because I need to send a formated date string to an API, and not to display it in a Django template).
Do you know if there is a way to use this Django "system" outside templates?
In the mean time, I tried to use the strftime Python method but found out some con's:
It does not use the same format chars as Django, which makes my code deals with 2 different ways to handle date formatting.
By default, it doesn't care about the Django locales and writes English dates.
Thanks :)
The template tag is built on the Django formats utility libraries. See django.utils.formats.date_format for a named date format or django.utils.formats.dateformat.format for arbitrary ones. For example:
from datetime import datetime
# Date format string
from django.utils.formats import dateformat
formatted_date = dateformat.format(datetime.now(), "r")
# Named format
from django.utils.formats import date_format
formatted_date = date_format(datetime.now(), "SHORT_DATE_FORMAT")

Categories

Resources