I have the following field:
from rest_framework import serializers
class ActivitySerializer(serializers.Serializer):
startDate = serializers.DateTimeField(input_formats=['%Y-%m-%d %H:%M:%S %z'])
activity = {u'startDate': "2015-10-18 15:11:50 +0000"}
serializer = ActivitySerializer(data=activity)
serializer.is_valid() # False
serializer.errors
# {'startDate': [u'Datetime has wrong format. Use one of these formats instead: YYYY-MM-DD hh:mm:ss [+HHMM|-HHMM].']}
Any thoughts as to why the datetime string that I'm using doesn't match that format? Given that datetime string, what's the right format string to parse it?
I just created a new field, ActivityStartDateField, and implemented a custom to_internal_value. I'm surprised I couldn't get it to work with the built-in DateTimeField.
class ActivityStartDateField(serializers.Field):
def to_representation(self, obj):
return str(obj)
def to_internal_value(self, data):
dt = arrow.get(data,'YYYY-MM-DD HH:mm:ss Z').datetime
return dt
Related
Given a long string (serialized Django object) how can we search all the timestamps and replace them with the correct format (dd/mm/YYYY HH:MM)
Example date (from the given example): 2022-01-11T16:49:43.897
Desired date time format: 11/01/2022 16:49
What I've tried so far:
#login_required
def my_view(request):
response = dict()
if request.method == 'GET':
files = Files.objects.all().filter(user=request.user)
for fhr in files:
fhr.updated = fhr.updated.strftime("%d/%m/%Y %H:%M:%S")
data = serialize("json", files)
return HttpResponse(data, content_type="application/json")
return HttpResponse('')
Basically I tried to edit the queryset with the correct format strftime("%d/%m/%Y %H:%M:%S") so that when I serialize the QuerySet into JSON data data = serialize("json", files) the string (data) contains the date and time in the correct format but it did not work.
So now I think that the only chance is to edit directly the string and replace those timestamps with the timestamps in the correct format.
The easiest way is to specify encoder class in serialize function. Refer to the documentation.
import typing
from datetime import datetime
from django.core.serializers.json import DjangoJSONEncoder
class DatetimeJSONEncoder(DjangoJSONEncoder):
def default(self, o: typing.Any) -> str:
result = super().default(o)
if isinstance(o, datetime):
result = o.strftime("%d/%m/%Y %H:%M:%S")
return result
data = serialize("json", files, cls=DatetimeJSONEncoder)
I am creating an API that contains a DateTimeField using Django but I am getting the following error "TypeError: descriptor 'strftime' for 'datetime.date' objects doesn't apply to a 'str' object" I have tried checking different sources but I haven't found a solution.
The error is arising from the start_date line.
from datetime import datetime
def question_view(request):
if request.method == 'GET':
return HttpResponse("Вопрос не создан")
elif request.method == 'POST':
poll_question = request.POST['poll_question']
title = request.POST['title']
start_date = datetime.strftime(request.POST['start_date'],'%Y-%m-%d')
Question.objects.create(poll_question=poll_question,title=title, start_date=start_date)
return HttpResponse("Вопрос создан")
else:
return "Попробуйте снова"
I think an easy way to fix this is to convert the object to a string according to a given format using datetime.strptime as stated in the doc
Your view will now be written as:
from datetime import datetime
def question_view(request):
if request.method == 'GET':
return HttpResponse("Вопрос не создан")
elif request.method == 'POST':
poll_question = request.POST['poll_question']
title = request.POST['title']
start_date = datetime.strptime(request.POST['start_date'],'%Y-%m-%d')
Question.objects.create(poll_question=poll_question,title=title, start_date=start_date)
return HttpResponse("Вопрос создан")
else:
return "Попробуйте снова"
strptime Parse a string into a datetime object given a corresponding format.
(As per the datetime documentation)
There is two methods in datetime:
strftime: used to convert date object into string.
strptime: used to convert string into date object.
In your case, you need a second one. The code of yours will be:
start_date = datetime.strptime(request.POST['start_date'],'%Y-%m-%d')
I am sending some dates from the front made in vue. I am receiving these dates in my viewSet in django, I want to filter data from these received dates.
I have two questions:
How do I convert dates into Python Datetime?
How do I filter the dates equal or greater or equal or less. => <=
In other words: bring records whose date is equal to or greater than another date.
date format in the front: 2021-08-03 10:12:14
date format in the back:
# print(type(fechas['desde']))
fecha <class 'str'>
# print(fechas['desde'])
fecha 2021-08-03 10:12:14
VIEWSET:
class TecnicosViewSet(
mixins.CreateModelMixin,
mixins.UpdateModelMixin,
mixins.RetrieveModelMixin,
mixins.ListModelMixin,
mixins.DestroyModelMixin,
viewsets.GenericViewSet):
queryset = Tecnico.objects.all()
serializer_class = Tecnicoserializer
def list(self, request):
dataQ = request.GET
newQ = json.dumps(dict(dataQ))
newQ1= json.loads(newQ)
tecnicos = ''
fechas= json.loads(newQ1['fechas'][0])
for item in newQ1['tecnicos']:
itemN = json.loads(item)
tecnicos = itemN['tecnicos']
print('fechas', fechas['desde'], fechas['hasta'])
# fecha = datetime.strptime(fechas['desde'], '%Y-%m-%d %H:%M')
print('fecha', type(fechas['desde']))
print('fecha', fechas['desde'])
for id in tecnicos:
ordenes = Servicio_realizados_orden_trabajo.objects.filter(date_range = [fechas['desde'], fechas['hasta']]).filter(state = 1).filter(tecnico = id)
ordenS = ServicioRealizadosserializer(ordenes, many=True)
return Response({'OK'})
As I fixed before: I want to convert that date into understandable python format and then use that transformed date to filter data by that date.
The for loop seen in the viewsewt is where I am trying to do the query.
I think you are pretty close based off your code...
You basically use strptime to convert a string to date in a desired format and then once you have created python datetime objects you can compare them.
Here's an example:
from datetime import datetime
date = datetime.strptime("2021-08-03 10:12:14", "%Y-%m-%d %H:%M:%S")
if date >= datetime.strptime("2021", "%Y"):
print('After or in 2021')
if date >= datetime.strptime("2021-09", "%Y-%m"):
print('After or in September 2021')
For some reason, the jsonify function is converting my datetime.date to what appears to be an HTTP date. How can I keep the date in yyyy-mm-dd format when using jsonify?
test_date = datetime.date(2017, 4, 27)
print(test_date) # 2017-04-27
test_date_jsonify = jsonify(test_date)
print(test_date_jsonify.get_data(as_text=True)) # Thu, 27 Apr 2017 00:00:00 GMT
As suggested in the comments, using jsonify(str(test_date)) returns the desired format. However, consider the following case:
test_dict = {"name": "name1", "date":datetime.date(2017, 4, 27)}
print(test_dict) # {"name": "name1", "date":datetime.date(2017, 4, 27)}
test_dict_jsonify = jsonify(test_dict)
print(test_dict_jsonify.get_data(as_text=True)) # {"date": "Thu, 27 Apr 2017 00:00:00 GMT", "name": "name1"}
test_dict_jsonify = jsonify(str(test_dict))
print(test_dict_jsonify.get_data(as_text=True)) # "{"date": datetime.date(2017, 4, 27), "name": "name1"}"
In this case, the str() solution does not work.
edit: this answer is now too old for Flask versions 2.3+.
for those newer versions, instead customize json_provider_class; reference: https://flask.palletsprojects.com/en/2.2.x/api/?highlight=json_encoder#flask.Flask.json_provider_class
Following this snippet you can do this:
from flask.json import JSONEncoder
from datetime import date
class CustomJSONEncoder(JSONEncoder):
def default(self, obj):
try:
if isinstance(obj, date):
return obj.isoformat()
iterable = iter(obj)
except TypeError:
pass
else:
return list(iterable)
return JSONEncoder.default(self, obj)
app = Flask(__name__)
app.json_encoder = CustomJSONEncoder
Route:
import datetime as dt
#app.route('/', methods=['GET'])
def index():
now = dt.datetime.now()
return jsonify({'now': now})
datetime.date is not a JSON type, so it's not serializable by default. Instead, Flask adds a hook to dump the date to a string in RFC 1123 format, which is consistent with dates in other parts of HTTP requests and responses.
Use a custom JSON encoder if you want to change the format. Subclass JSONEncoder and set Flask.json_encoder to it.
from flask import Flask
from flask.json import JSONEncoder
class MyJSONEncoder(JSONEncoder):
def default(self, o):
if isinstance(o, date):
return o.isoformat()
return super().default(o)
class MyFlask(Flask):
json_encoder = MyJSONEncoder
app = MyFlask(__name__)
It is a good idea to use ISO 8601 to transmit and store the value. It can be parsed unambiguously by JavaScript Date.parse (and other parsers). Choose the output format when you output, not when you store.
A string representing an RFC 2822 or ISO 8601 date (other formats may be used, but results may be unexpected).
When you load the data, there's no way to know the value was meant to be a date instead of a string (since date is not a JSON type), so you don't get a datetime.date back, you get a string. (And if you did get a date, how would it know to return date instead of datetime?)
Flask 2.2 shows a deprecation warning
'JSONEncoder' is deprecated and will be removed in Flask 2.3. Use 'Flask.json' to provide an alternate JSON implementation instead.
An update is needed to remove it and/or have it work in Flask 2.3+. Another example from the Flask repository here
from datetime import datetime, date
from flask import Flask
from flask.json.provider import DefaultJSONProvider
class UpdatedJSONProvider(DefaultJSONProvider):
def default(self, o):
if isinstance(o, date) or isinstance(o, datetime):
return o.isoformat()
return super().default(o)
app = Flask(__name__)
app.json = UpdatedJSONProvider(app)
You can change your app's .json_encoder attribute, implementing a variant of JSONEncoder that formats dates as you see fit.
When I try to return documents based on the date created, I get an empty list when I know for a fact that there are documents in the database that meet the criteria. I used postman to send the request which would be a string input from the user eg. "Tue Apr 28 2020". This string input would then be converted to a datetime object like so:
def get(self):
try:
body = request.get_json()
search_field = datetime.datetime.strptime(body, '%a %b %d %Y') #format string to datetime object
next_day = search_field
next_day += relativedelta(days=1) #Set the end of the range to the next day
search_field = search_field.replace(tzinfo=datetime.timezone.utc).isoformat()
next_day = next_day.replace(tzinfo=datetime.timezone.utc).isoformat()
print(search_field) #Verify the fields are correct : 2020-04-28T00:00:00+00:00
print(next_day) #2020-04-29T00:00:00+00:00
date_search = Reports.objects.filter(__raw__={'creation_timestamp' : {'$gte' : search_field, '$lte' : next_day}}).to_json() #This is where the documents should be filtered for return
print(date_search)
return Response(date_search, mimetype="application/json", status=200) #The document/s should be returned here as a JSON array.
except Exception as e:
print(e)
return make_response(jsonify(message='Something went wrong :('), 401)
Here is the partial database model:
class Reports(db.Document):
creation_timestamp = db.DateTimeField(default=datetime.utcnow, required=True)
When the document is created, it is stored in the database and the time is stored as isoformat(). The user can only input the search field in the format stated above with a date picker so I format the date to fit the format Mongodb would understand.
Using the above code, I get an empty list and the 200 status code. Checking the database shows I have documents that would fit the criteria, can anyone help figure out what is wrong? Thanks.
If you can have your search_field and nextday in datetime format then you can write the query. I also suggest using Q for pymongo queries in mongoengine.
Your query :
import Q from mongoengine
search_time=datetime.datetime(2017, 11, 8)
nextday=datetime.datetime(2017, 11, 9)
date_search=Report.objects(Q(creation_timestamp__gte=search_field) & Q(timestamp__lte=nextday)).to_json()