All my models except my User model inherit from this model:
class BaseModel(models.Model):
created_date = models.DateTimeField(auto_now_add=True)
modified_date = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
Whenever a user signs-up, I get the following warning:
RuntimeWarning: DateTimeField User.date_joined received a naive datetime (2018-07-04 06:38:11.288567) while time zone support is active.
Since I don't control the user creation process (I'm using the default user model supplied by Django), I can't figure out how to solve this.
Use timezone of django utils.
from django.utils import timezone
class BaseModel(models.Model):
created_date = models.DateTimeField(default=timezone.now)
modified_date = models.DateTimeField()
# override default save funtion
def save(self, *args, **kwargs):
self.modified_date = timezone.now()
return super(BaseModel, self).save(*args, **kwargs)
Related
I am writing an API in Django Rest Framework- when using the POST method to create a new object, if the 'done' field is True and the 'done_date' is Null, I would like the 'done_date' to automatically be set to current time. Here's what I tried to do, overriding the save method in my models:
In models.py
from django.db import models
from django.utils import timezone
class Task(models.Model):
title = models.CharField(max_length=100)
done = models.BooleanField(default=False)
author_ip = models.GenericIPAddressField()
created_date = models.DateTimeField(default=timezone.now)
done_date = models.DateTimeField(null=True, blank=True)
class Meta:
ordering = ('id',)
def __str__(self):
return '{} - {}'.format(self.pk, self.title)
def save(self, *args, **kwargs):
if self.done and not self.done_date:
self.done_date = timezone.now
super(Task, self).save(*args, **kwargs)
However, this throws a "TypeError when calling Task.objects.create(). This may be because you have a writable field on the serializer class that is not a valid argument to Task.objects.create(). You may need to make the field read-only, or override the TaskSerializer.create() method to handle this correctly."
Now, I am fairly certain that it's related to timezone.now in the save method, could someone advise me on how to proceed? I apologise if it is a basic question, thanks!
All you have to do is to call the timezone.now() function (with the parenthesis)
alternatively, you could use: auto_now=True and set editable=True
I'm using Django 1.10
In our base model (that few model inherit from) we set
class BaseModel(models.Model):
created_at = models.DateTimeField(db_index=True, auto_now_add=True)
now, in specific sub-class model I need to override it's save and update the 'created_at':
class Item(BaseModel):
title = models.CharField(max_length=200)
identifier = models.CharField(max_length=15)
def save(self, *args, **kwargs):
existing_item = Item.objects.active_and_deleted().get(
identifier=self.identifier)
existing_item.created_at = now()
super(Item, existing_item).save(args, kwargs)
That updated instance created_at is 'None'.
I've tried 'editable=True' unsuccessfully.
Any idea?
With the following example, change the default parameter of DateTimeField, django will allow you to edit it manually: assign the attribute with django.utils.timezone.now() in the save() method
import django
class BaseModel(models.Model):
created_at = models.DateTimeField(db_index=True,
default=django.utils.timezone.now())
I want to change the model used for the default LogEntry class so it creates a varchar rather than a clob in the database for the attribute "object_id"
The original model is defined in
django/contrib/admin/models.py
class LogEntry(models.Model):
action_time = models.DateTimeField(_('action time'), auto_now=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL)
content_type = models.ForeignKey(ContentType, blank=True, null=True)
object_id = models.TextField(_('object id'), blank=True, null=True)
object_repr = models.CharField(_('object repr'), max_length=200)
action_flag = models.PositiveSmallIntegerField(_('action flag'))
change_message = models.TextField(_('change message'), blank=True)
I want to change the definition of object_id to
object_id = models.Charfield(_('object id'), max_length=1000, blank=True, null=True)
I'm aware that this could cause issues if someone defined a primary key on an entity which is larger than a varchar(1000), but I wouldn't want an entity with a PK defined like that so I'm happy with the limitation.
This will greatly improve the efficiency of the queries when accessing the history log.
I don't really want to hack the actual model definition, but I can't find out how to elegantly override the model definition.
Any ideas?
Django’s model fields provide an undocumented contribute_to_class method.
The other feature of Django we can use is the class_prepared signal.
from django.db.models import CharField
from django.db.models.signals import class_prepared
def add_field(sender, **kwargs):
"""
class_prepared signal handler that checks for the model named
MyModel as the sender, and adds a CharField
to it.
"""
if sender.__name__ == "MyModel":
field = CharField("New field", max_length=100)
field.contribute_to_class(sender, "new_field")
class_prepared.connect(add_field)
To override field you can simply delete original field from model:
from django.db.models import CharField
from django.db.models.signals import class_prepared
def override_field(sender, **kwargs):
if sender.__name__ == "LogEntry":
field = CharField('object id', max_length=1000, blank=True, null=True)
sender._meta.local_fields = [f for f in sender._meta.fields if f.name != "object_id"]
field.contribute_to_class(sender, "object_id")
class_prepared.connect(override_field)
I have just tested this solution by placing this code in __init__.py of my app. You will also need to write a custom migration:
from django.db import migrations, models
class Migration(migrations.Migration):
def __init__(self, name, app_label):
# overriding application operated upon
super(Migration, self).__init__(name, 'admin')
dependencies = [
('my_app', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='logentry',
name='object_id',
field=models.CharField('object id', max_length=1000, blank=True, null=True),
),
]
Looks like it works but use it on your own risk.
You can read more here.
am working on a concept in which I want to capture certain information when a model is saved. To understand the full picture, I have a app core with the following model
core/models.py
from django.db import models
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from transmeta import TransMeta
from django.utils.translation import ugettext_lazy as _
import signals
class Audit(models.Model):
## TODO: Document
# Polymorphic model using generic relation through DJANGO content type
operation = models.CharField(_('Operation'), max_length=40)
operation_at = models.DateTimeField(_('Operation At'), auto_now_add=True)
operation_by = models.ForeignKey(User, null=True, blank=True, related_name="%(app_label)s_%(class)s_y+")
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
Audit model is a generic content type, am currently attaching it with other apps such as in blog
blog/models.py
from django.db import models
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
from django.template.defaultfilters import slugify
from django.utils.translation import ugettext_lazy as _
# Create your models here.
class Meta:
verbose_name_plural = "Categories"
class article(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField(editable=False, unique_for_year=True)
content = models.TextField()
is_active = models.BooleanField()
published_at = models.DateTimeField('Publish at',auto_now=True)
related_articles = models.ManyToManyField('self', null=True, blank=True)
audit_obj = generic.GenericRelation('core.Audit', editable=False, null=True, blank=True)
My first attempt was, I made a post_save signal in which I was checking if the instance passed containing audit_obj attribute and then saving a record in using article.audit_obj.create().save().
Unfortunately, this did not entirely work out for me since I cannot pass the request nor I can access the request to retrieve the user information.
So, I was thinking to create a custom signal and override the form_save method (if there is such a thing) and then using arguments to pass the request object as well as the model object.
Any advice on how I can do that?
Regards,
EDIT (20th of Jan, 2011):
Thanks #Yuji for your time. Well, what am trying to achieve is to keep my code as DRY as possible. What I want to do ultimately, every time I create new model, I will only create an additional attribute and name it audit_obj and I will create a single piece of code, either a signal or to override the save method inside the django core itself. The peiece of code will always check if an attribute with the following name exists and therefore creates a record in aduti table.
I'd just create a function in my model class or Manager and call it from my form save (wherever yours might be)
class AuditManager(models.Manager):
def save_from_object(self, request, obj):
audit = Audit()
audit.object_id = obj.id
audit.operation_by = request.user
# ...
audit.save()
class Audit(models.Model):
## TODO: Document
# Polymorphic model using generic relation through DJANGO content type
operation = models.CharField(_('Operation'), max_length=40)
operation_at = models.DateTimeField(_('Operation At'), auto_now_add=True)
operation_by = models.ForeignKey(User, null=True, blank=True, related_name="%(app_label)s_%(class)s_y+")
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
objects = AuditManager()
class MyBlogForm(forms.ModelForm):
class Meta:
model = article # btw I'd use Capital Letters For Classes
def save(self, *args, **kwargs):
super(MyBlogForm, self).save(*args, **kwargs)
Audit.objects.save_from_object(request, self.instance)
I'm trying to get an abstract model working in Django and I hit a brick wall trying to set the related_name per the recommendation here: http://docs.djangoproject.com/en/dev/topics/db/models/#be-careful-with-related-name
This is what my abstract model looks like:
class CommonModel(models.Model):
created_on = models.DateTimeField(editable=False)
creared_by = models.ForeignKey(User, related_name="%(app_label)s_%(class)s_created", editable=False)
updated_on = models.DateTimeField(editable=False)
updated_by = models.ForeignKey(User, related_name="%(app_label)s_%(class)s_updated", editable=False)
def save(self):
if not self.id:
self.created_on = datetime.now()
self.created_by = user.id
self.updated_on = datetime.now()
self.updated_by = user.id
super(CommonModel, self).save()
class Meta:
abstract = True
My common model is in [project_root]/models.py. It is the parent object of this model, which is located in an app called Feedback [project_root]/feedback/models.py:
from django.db import models
from mediasharks.models import CommonModel
class Feedback(CommonModel):
message = models.CharField(max_length=255)
request_uri = models.CharField(max_length=255)
domain = models.CharField(max_length=255)
feedback_type = models.IntegerField()
Basically I'm trying to set up a common model so that I'll always be able to tell when and by whom database entries were created.
When I run "python manage.py validate" I get this error message: KeyError: 'app_label'
Am I missing something here?
Note the bold text on your link: "Changed in development version". If you're not using a recent checkout of Django trunk - for instance, you're on the latest released version, 1.1 - you should be using this link for the documentation. That version of the text makes no reference to app_label, because it had not yet been introduced.