DateField in DRF django - django

I've a model which have a DateField.
class A(model.Model):
a = model.DateField()
class SerializerA(serializers.ModelSerializer):
class Meta:
model = A
fields = (a,)
The payload that I pass have a chance that it might send only year, for eg:-
{
"a": "1991"
}
It returns an error saying,
"Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]]."
I'm already passing one the format, as mentioned in the error, but still I'm getting an error.
Why?

One of the simple solutions will be, define field a as separate in your serializer and provide sufficient values to the input_formats argument
required_formats = ['%Y', '%d-%m-%Y'] # add other formats you need
class SerializerA(serializers.ModelSerializer):
a = serializers.DateField(input_formats=required_formats)
class Meta:
model = A
fields = ('a',)

You need to set all needed date formats to variable DATE_INPUT_FORMATS in settings.py, for example:
DATE_INPUT_FORMATS = ['%d-%m-%Y']

Related

Setting the Format for the Django DatetimeInput Widget

I would like to use the included Django DateTimeInput widget as a datetimepicker on my website. No matter what I try however, the widget returns a datetime value in an incorrect format which will not send to my database.
I need the format '%Y-%m-%d %H:%M:%S', but the widget returns '%d/%m/%Y %H:%M:%S'
This problem has been discussed a tad here:
http://stackoverflow.com/a/35968816/1382297
I believe the problem may be from setting the input_type to DateTime-local, but I don't know other options and cannot find any in the documentation. I've tried passing format='%Y-%m-%d %H:%M:%S' to the widget, as well as FORMAT_INPUTS = ['%Y-%m-%d %H:%M:%S'], and tried initializing these in the DateInput class, all with no luck.
Here is my forms.py
class DateTimeInput(forms.DateTimeInput):
input_type = 'datetime-local'
class EnterMatchForm(forms.ModelForm):
class Meta:
model = match
fields = ('match_name', 'player1', 'player2', 'victory', 'match_description', 'match_date')
widgets = {
'match_date': DateTimeInput(),
}
What is the right way to set up the widget so that it returns datetime values in the format Y-m-d H:M:S? Thanks in advance!
You have to pass input_formats not formats or FORMAT_INPUTS.
https://docs.djangoproject.com/en/3.0/ref/forms/fields/#datetimefield

can't use lookup_expr list in django_filters class?

Url: /user?u=root works
class UserFilter(django_filters.rest_framework.FilterSet):
u = django_filters.rest_framework.CharFilter(name='username', lookup_expr='contains')
class Meta:
model = User
fields = ['username','u']
but when i changed it to
class UserFilter(django_filters.rest_framework.FilterSet):
u = django_filters.rest_framework.CharFilter(name='username', lookup_expr=['contains'])
class Meta:
model = User
fields = ['username','u']
url: /user?u__contains=root doesn't work.
django 1.11.1
django-filter 1.0.4
djangorestframework 3.6.3
Ykh is close, but incorrect. In your second example, the filter is still exposed as u, so filtering by u__contains is a no-op since it's not a recognized name. u__contains is not somehow translated into a u__contains__contains lookup.
Additionally, passing a list or tuple of lookups to lookup_expr might provide a different behavior than you would expect. It is not related to the automatic filter generation that you see with Meta.fields. Instead, it creates a multi-lookup filter (docs). This filter has two inputs:
a text input for the value to filter by
a select widget to select which lookup to use
It accomplishes this by using a django.forms.MultiWidget, so your query would need to be something like /user?u_0=root&u_1=contains.
In general, MultiWidgets are not that compatible with API usage, given the _0 and _1 suffixes.
If you're trying to expose a filter named u__contains, you should do something like:
class UserFilter(django_filters.rest_framework.FilterSet):
u = django_filters.rest_framework.CharFilter(name='username', lookup_expr='exact')
u__contains = django_filters.rest_framework.CharFilter(name='username', lookup_expr='contains')
class Meta:
model = User
fields = ['u', 'u__contains']
And there are several ways to use lookup_expr and the way you write it is incorrect would be "icontains" for contain and "iexact" for exact. Also another well used expressions would be gte and lte.
class UserFilter(django_filters.rest_framework.FilterSet):
u_contain = django_filters.rest_framework.CharFilter(
field_name='username',
lookup_expr='icontains'
)
l_exact = django_filters.rest_framework.CharFilter(
field_name='lastname',
lookup_expr='iexact'
)
class Meta:
model = User
fields = ['u_contain', 'l_exact']

Django validate data when updating model with primary key

I am having trouble with updating fields of a model instance. The model is as follows:
class commonInfo(models.Model):
mothers_id = models.IntegerField(primary_key=True)
date = models.DateField()
data_collector = models.CharField(max_length=50)
Essentially, I just want to do this, but it won't work because commonInfo has a user defined primary key
commonInfo_form(request.POST or None).is_valid()
Since I am updating, I am overriding date and data_collector, but not mothers_id. So I would want to do something like this, but this specific code is not working
obj = commonInfo.objects.get(pk=commonInfo_id)
form = commonInfo_form(request.POST)
date = form.cleaned_data['data_collector'] #this line is not working
data_collector = form.cleaned_data['data_collector'] #this line is not working
obj.update(**{'date':date, 'data_collector':data_collector})
any ideas? I feel like it is just those two lines that I need to fix. Or if there is a more pythonic way or built method in Django?
Just validate with isinstance. so like,
if isinstance(request.POST['date'], datetime.date) and isinstance(request.POST['data_collector'], str):
# you might have to use getattr for request.POST here, I'm not sure
# and request.POST['date'] would have to be converted from a string to datetime.date I think
date = request.POST['date']
data_collector = request.POST['data_collector']
obj.update(**{'date':date, 'data_collector':data_collector})
The process for adding a record from a form is different from updating an existing instance. All you need to do differently is indicate which instance to bind the form to when you create it, ex:
obj = commonInfo.objects.get(pk=commonInfo_id)
form = commonInfo_form(request.POST, instance=obj)

Filtering on DateTimeField with Django Rest Framework

I have a model with a DateTimeField:
class MyShell(models):
created = models.DateTimeField(auto_now=true)
I have an api linked to it using Django Rest Framework:
class ShellMessageFilter(django_filters.FilterSet):
created = django_filters.DateTimeFilter(name="created",lookup_type="gte")
class Meta:
model = ShellMessage
fields = ['created']
class ShellListViewSet(viewsets.ModelViewSet):
"""
List all ShellMessages
"""
serializer_class = ShellMessageSerializer
queryset = ShellMessage.objects.all()
filter_class = ShellMessageFilter
When I hit my API using the following URL it works perfectly:
http://127.0.0.1:8000/api/shell/?created=2014-07-17
# It returns all shell with a date greater than the one provided in URL
But, I want to do more than that by filtering base on a date and a time. I tried the following URL without success:
http://127.0.0.1:8000/api/shell/?created=2014-07-17T10:36:34.960Z
# It returns an empty array whereas there are items with a created field greater than 2014-07-17T10:36:34.960Z
If you guys know how to proceed... I don't find any good informations or example in django-filters documentation...
Simpler solution if you don't care about fractions of seconds: replace the "T" with space (%20):
http://127.0.0.1:8000/api/shell/?created=2014-07-17%2010:36:34
Worked for me.
This may not be what you want, but you could simply convert from Unix time. E.g.:
def filter_unix_dt(queryset, value):
if not value:
return queryset
try:
unix_time = int(value)
t = datetime.fromtimestamp(unix_time)
result = queryset.filter(created__gte=t)
return result
except ValueError:
return queryset
class ShellMessageFilter(django_filters.FilterSet):
created = django_filters.DateTimeFilter(action=filter_unix_dt)
class Meta:
model = ShellMessage
fields = ['created']
The issue and solution are documented in this DRF issue page: https://github.com/tomchristie/django-rest-framework/issues/1338
TL;DR: A Django ISO conversion 'issue' is preventing DRF from working as you are expecting. A fix for this has been written in DRF, allowing you to use IsoDateTimeField instead of DateTimeField. Just replaying the T with a space in your request param value also works.

How to save an empty datefield in django

I have an optional datefield in my form, when I save it and it's empty I got the validation error about the invalid format.
In my model, I wrote blank=True and null=True.
Model :
created = models.DateTimeField(blank=True,null=True)
Form :
class XxxForm(forms.ModelForm):
created=forms.DateField(required=False)
class Meta:
model = Xxx
Error :
u"" value has an invalid format. It must be in YYYY-MM-DD HH:MM format
Update :
I found the solution which is :
created = request.POST['created']
if not created:
created = None
It works that way ! thanks everyone
You need to use a DateTimeField in the form, not a DateField.
[EDIT]
Also try to drop created=forms.DateField(required=False) from your form declaration. It is not needed there since you have it in the model already.