Django - allow manually setting auto_now attribute for Sub-class - python

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())

Related

Unable to update/delete related model in the save() method of a model

I have two Django models:
from django.db import models
class Policy(models.Model):
status = models.IntegerField()
def save(self, *args, **kwargs):
quote = self.documents.get(document_type=DocumentType.quote)
if self.status == 0:
quote.delete()
elif self.status == 1:
new_quote_content = create_new_quote()
quote.s3_file.save(quote.name, File(new_quote_content))
super().save(*args, *kwargs)
class Document(models.Model):
policy = models.ForeignKey(
to=Policy,
null=True,
blank=True,
on_delete=models.CASCADE,
related_name="documents",
)
s3_file = models.FileField(
storage=S3Storage(aws_s3_bucket_name="policy-documents"),
upload_to=get_document_s3_key,
max_length=255,
)
I want to delete/update the document when the policy status is updated and I've overriden the save() method in Policy to do it. However, neither the doc deletion nor the doc's FieldFile update works in the save() method. If I move them to outside the save() method, everything works.
Does someone understand what's the issue here?
It is not calling the super method to save the model. To override a model it has to be something like this as given in the documentation of Django.
from django.db import models
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
def save(self, *args, **kwargs):
do_something()
super().save(*args, **kwargs) # Call the "real" save() method.
do_something_else()
The save() was being called from a Policy ModelAdmin with a inlined Document form set. After it was run, Django executed the ModelAdmin's save_related() method, which saved the Document form set data, overwriting the Document changes I had just saved in save(). I solved it by overriding save_related() and deleting/updating the document after form.save_m2m() and form.save_formset().

Timezone.now throwing a Type Error when overriding a save method

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

Django: default user model RunTimeWarning about naïve DateTimeField

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)

How to make dynamically parameters django models fields

This code is a abstract class for many
Class Base (models.Model):
Created_by = models.ForeignKey(User)
Modified_by = models.ForeignKey(User, null=True)
I want related_name like this related_name = self.default_related_name + '_name_field'
As the following
Class Base(models.Model):
Created_by = models.ForeignKey(User,
related_name = self.default_related_name + '_created_by')
Modified_by = models.ForeignKey(User,
null = True,
related_name = self.default_related_name + '_modified_by')
But i know that, I cant have access to instance in the attributes of the class.
So what method do I can to overload to create a field with a method (or property)?
(I tried to create the field in the __init__ method, but it doesnt not work).
If you can use the subclass name instead of default_related_name then it's trivial:
related_name="%(class)s_created"
https://docs.djangoproject.com/en/1.8/topics/db/models/#be-careful-with-related-name
Also, as the base class is a abstract model, you will need
class Meta:
abstract = True
Pre save signal is what you are looking for.
for reference : https://docs.djangoproject.com/en/1.11/ref/signals/#pre-save
right before save it to the database, you can apply all the changes you want. :)
here is an example where I capitalize the first letter of every word and create a slug.
def pre_save_city(sender, instance, *args, **kwargs):
instance.name = instance.name.title()
if not instance.slug:
instance.slug = slugify(instance.name)
this is how you run the function :
pre_save.connect(pre_save_city,sender=City)

How to create a timestamp on submit in Django class based views for Update?

I'm new to class based views in Django and was using a simple UpdateView CBV. The view has many fields that is being displayed on a template, except one; the Date field. How do I add a timestamp to this field? The timestamp should be added only the first time the object is created. From the next time onwards, it should only show the timestamp that was added the first time. This is my code:
class ReviewsEdit(UpdateView):
model = ProductReview
fields = ['title', 'body', 'score', 'responder_name', 'response']
template_name = 'review_system/review_edit.html'
context_object_name = 'review'
The ProductReview model has all the above fields with another Date field, I'd like to save it with timestamp data when the submit button was clicked - only if it is blank when submitting. Is this possible with CBV?
If you want to implement fields that let you know when the object was created and/or last edited you can achieve that with these Django fields:
class TouchStampModel(Model):
created = DateTimeField(auto_now_add=True, editable=False, null=False, blank=False)
last_modified = DateTimeField(auto_now=True, editable=False, null=False, blank=False)
class Meta:
abstract = True
Any model subclasses will have those fields and they won't be editable by default (won't show up in forms for editing), and last_modified will be updated automatically on each DB update while created will be set to the DB insert time.
Of course, you can modify your existing model's DateTimeField. There is no need for the superclass unless you have several models that require created and last_modified.
class ReviewModel(Model):
created_at = DateTimeField(auto_now_add=True, editable=False, null=False, blank=False)
why don't you just display this on the template then.
obj.created_at
this will always show the time the review was created
I got it, I had to over-ride the save() method to get it done. It works something like this. After defining your models, over-ride save() method.
def save(self, *args, **kwargs):
if not self.your.field:
self.date_field = datetime.datetime.now()
super(ModelName, self).save(*args, **kwargs)

Categories

Resources