Setting DateField Default value in Django Rest Framework serializer - django

I have a serializer with datefield which needs to be set to a default date of three days from today.
I'm unable to set it using "default" argument of the datefield in the serializer.
Any kind of help would be highly appreciated.

You can't do in normal way, So you need to write custom functions in models.
from datetime import timedelta
from django.utils import timezone
def in_three_days():
return timezone.now() + timedelta(days=3)
class TestModel(models.Model):
event = models.DateTimeField(default=in_three_days)

Related

How to make import-export save JSONField not as string

I'm trying to import JSONField using django import-export, it keeps saving JSON as string (adding "" to it)
models.py
from django.db import models
from django.contrib.postgres.fields import JSONField
class Governorate(models.Model):
name = models.CharField(max_length=500)
data = JSONField()
def __str__(self):
return ("%s" %(self.name))
admin.py
from django.contrib import admin
from .models import Governorate
from import_export.admin import ImportExportModelAdmin
from import_export import resources
class GovernorateResource(resources.ModelResource):
class Meta:
model = Governorate
class GovernorateAdmin(ImportExportModelAdmin):
list_display = ('id','name', 'data')
resources_class = GovernorateResource
admin.site.register(Governorate,GovernorateAdmin)
I expected the output to be: {"xx":{"xx":"xx","xx":"xx"} however it saves it as "{"xx":{"xx":"xx","xx":"xx"}"
Tried uploading XLSX and CSV.
Version 1.2.0 of import-export doesn't automatically recognise the JSONField in your Resource so it just defaults to a CharField type. It's already added to the master branch but not released.
So just override the field to use the JSONWidget which is already available in version 1.2.0:
from import_export import fields, widgets
class GovernorateResource(resources.ModelResource):
data = fields.Field(widget=widgets.JSONWidget())
class Meta:
model = Governorate
So basically, the import-export library was saving the JSONField() as a string. So my solution was to create a signal to check if the instance was a string or a dict. then fix it.
I tried to create a Field with the JSONWidget widget, but doesn't work.
models.py
#receiver(post_save, sender=Governorate)
def fix_json(sender, instance, **kwargs):
if (type(instance.data) is str):
instance.data = eval(instance.data)
instance.save()
print(instance.data)
The Django import-export library is really good, but lacks proper documentation to be honest.

How to use DateField in a Django form in a timezone-aware way?

I have a DateField in a Django 1.8 model, something like:
from django.db import models
birth_date = models.DateField()
When it goes onto a form, I get back a 'naive' object:
birth_date = the_form.cleaned_data['birth_date']
Printing birth_date in the debugger:
ipdb> birth_date
datetime.date(2015, 6, 7)
Then when this thing is saved to a database, I get a warning, as the documentation promises:
RuntimeWarning: SQLite received a naive datetime (2015-06-08 01:08:21.470719) while time zone support is active.
I've read some articles on this, and I am still confused. What should I do with this date?
Should I convert it to a DateTime, make it timezone-aware, then back into a Date? Should I make the model a DateTimeField and abandon DateFields? What are best practices here?
#kalo's answer didn't work for me, so I created this utility function from what ended up working for me based on his answer:
from django.utils import timezone
from django.utils.dateparse import parse_date
from django.utils.datetime_safe import time
def make_timezone_aware(date):
return timezone.make_aware(timezone.datetime.combine(parse_date(date), time.min))
Combining the date with a 00:00 time solved the following errors:
'datetime.date' object has no attribute 'tzinfo'
'str' object has no attribute 'tzinfo'
I think that you can try to use make_aware to convert the date to aware format. From make_aware django documentation:
make_aware(value, timezone=None, is_dst=None)
Returns an aware datetime that represents the same point in time as
value in timezone, value being a naive datetime.
This should fix the warning:
from django.utils import timezone
birth_date = timezone.make_aware(the_form.cleaned_data['birth_date'], timezone.get_default_timezone())

Django custom field validator vs. clean

I would like to create TodayOrLaterDateField() which would subclass DateField() field as I am using this condition in many places. The purpose of this field would be avoiding putting dates from the past.
What is the most straightway way of doing this? I am confused with validator vs. clean method.
I've tried with clean() but when comparing value to datetime.date.today() I am getting "compare unicode object to date" error.
I'm using Django 1.3
Validators only validate, they don't return the improved format;
Clean methods both validate and return a (sometimes amended) value.
I think the way to go here is to just use a DateField with a validator as a inherited class of DateField with a default_validators set.
import datetime
from django.core import exceptions
from django.db import models
from django.utils.translation import ugettext_lazy as _
def validate_date_today_or_later(value):
'Place this in validators.py and import it to keep your model a bit cleaner'
if value < datetime.date.today():
raise exceptions.ValidationError(_('Date must be today or later'))
class TodayOrLaterDateField(models.DateField):
default_validators = [validate_date_today_or_later,]
edit:
You can apply the same validator to your form fields as well if you just want it there and not in your whole app.
You can extend models.DateField and override to_python method. Didn't tested on Django 1.3 but should work.
import datetime
from django.core import exceptions
from django.db import models
class TodayOrLaterDateField(models.DateField):
def to_python(self, value):
value = super(TodayOrLaterDateField, self).to_python(value)
if value < datetime.date.today():
raise exceptions.ValidationError(u'Date must be today or later')
return value

Django: Get model from string?

In Django, you can specify relationships like:
author = ForeignKey('Person')
And then internally it has to convert the string "Person" into the model Person.
Where's the function that does this? I want to use it, but I can't find it.
As of Django 1.11 to 4.0 (at least), it's AppConfig.get_model(model_name, require_ready=True)
As of Django 1.9 the method is django.apps.AppConfig.get_model(model_name).
-- danihp
As of Django 1.7 the django.db.models.loading is deprecated (to be removed in 1.9) in favor of the the new application loading system.
-- Scott Woodall
Found it. It's defined here:
from django.db.models.loading import get_model
Defined as:
def get_model(self, app_label, model_name, seed_cache=True):
django.db.models.loading was deprecated in Django 1.7 (removed in 1.9) in favor of the the new application loading system.
Django 1.7 docs give us the following instead:
>>> from django.apps import apps
>>> User = apps.get_model(app_label='auth', model_name='User')
>>> print(User)
<class 'django.contrib.auth.models.User'>
just for anyone getting stuck (like I did):
from django.apps import apps
model = apps.get_model('app_name', 'model_name')
app_name should be listed using quotes, as should model_name (i.e. don't try to import it)
get_model accepts lower case or upper case 'model_name'
Most model "strings" appear as the form "appname.modelname" so you might want to use this variation on get_model
from django.db.models.loading import get_model
your_model = get_model ( *your_string.split('.',1) )
The part of the django code that usually turns such strings into a model is a little more complex This from django/db/models/fields/related.py:
try:
app_label, model_name = relation.split(".")
except ValueError:
# If we can't split, assume a model in current app
app_label = cls._meta.app_label
model_name = relation
except AttributeError:
# If it doesn't have a split it's actually a model class
app_label = relation._meta.app_label
model_name = relation._meta.object_name
# Try to look up the related model, and if it's already loaded resolve the
# string right away. If get_model returns None, it means that the related
# model isn't loaded yet, so we need to pend the relation until the class
# is prepared.
model = get_model(app_label, model_name,
seed_cache=False, only_installed=False)
To me, this appears to be an good case for splitting this out into a single function in the core code. However, if you know your strings are in "App.Model" format, the two liner above will work.
2020 solution:
from django.apps import apps
apps.get_model('app_name', 'Model')
per your eg:
apps.get_model('people', 'Person')
per:
Import Error :cannot import name get_model
The blessed way to do this in Django 1.7+ is:
import django
model_cls = django.apps.apps.get_model('app_name', 'model_name')
So, in the canonical example of all framework tutorials:
import django
entry_cls = django.apps.apps.get_model('blog', 'entry') # Case insensitive
In case you don't know in which app your model exists, you can search it this way:
from django.contrib.contenttypes.models import ContentType
ct = ContentType.objects.get(model='your_model_name')
model = ct.model_class()
Remember that your_model_name must be lowercase.
Another rendition with less code for the lazy. Tested in Django 2+
from django.apps import apps
model = apps.get_model("appname.ModelName") # e.g "accounts.User"
I'm not sure where it's done in Django, but you could do this.
Mapping the class name to the string via reflection.
classes = [Person,Child,Parent]
def find_class(name):
for clls in classes:
if clls.__class__.__name__ == name:
return clls
Here is a less django-specific approach to get a class from string:
mymodels = ['ModelA', 'ModelB']
model_list = __import__('<appname>.models', fromlist=mymodels)
model_a = getattr(model_list, 'ModelA')
or you can use importlib as shown here:
import importlib
myapp_models = importlib.import_module('<appname>.models')
model_a = getattr(myapp_models, 'ModelA')

How to get the app a Django model is from?

I have a model with a generic relation:
TrackedItem --- genericrelation ---> any model
I would like to be able to generically get, from the initial model, the tracked item.
I should be able to do it on any model without modifying it.
To do that I need to get the content type and the object id. Getting the object id is easy since I have the model instance, but getting the content type is not: ContentType.object.filter requires the model (which is just content_object.__class__.__name__) and the app_label.
I have no idea of how to get in a reliable way the app in which a model is.
For now I do app = content_object.__module__.split(".")[0], but it doesn't work with django contrib apps.
The app_label is available as an attribute on the _meta attribute of any model.
from django.contrib.auth.models import User
print User._meta.app_label
# The object name is also available
print User._meta.object_name
You don't need to get the app or model just to get the contenttype - there's a handy method to do just that:
from django.contrib.contenttypes.models import ContentType
ContentType.objects.get_for_model(myobject)
Despite the name, it works for both model classes and instances.
You can get both app_label and model from your object using the built-in ContentType class:
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import User
user_obj = User.objects.create()
obj_content_type = ContentType.objects.get_for_model(user_obj)
print(obj_content_type.app_label)
# u'auth'
print(obj_content_type.model)
# u'user'
This is better approach respect of using the _meta properties that are defined for private purposes.