create a new model instance version instead of update - django

I have a model with a version field - autocreate timestamp.
When a model instance is being saved I want to create a new instance with a new timestamp instead of updating the old model instance.
Is it possible?
I thought of overriding the model save() method but I don't know how to create a new instance without creating a infinite save() loop.
Thanks

You could set self.id = None in the overridden save method - then in the super method, Django would do an INSERT rather than an UPDATE.
Or, as pointed out in the documentation here, you could use the force_insert=True parameter in the call to save, which does the same thing.

Related

Add relations before adding them to DB in django

If I have a relation like this in django
class Reporter(models.Model):
pass
class Article(models.Model):
reporter = models.ForeignKey(Reporter)
and I want to create a new reporter with articles at once, I first have to save() the Reporter to DB and then I can add the articles.
But sometime, I would like to prepare everything "offline" (in sense of, before pushing anything to the DB), so like creating a Reporter object, adding articles to it and maybe afterwards still modifying some attributes of the Reporter object.
Then, when everything is done, I want to push all together to the DB. But of course when I use Reporter.article_set.add() before calling Reporter.save() I will get an error, because django will try to add the articles and foreign keys to the DB automatically. Is there any way to prevent this, and prepare my object inlcuding the relations "offline" ?
My own approach would be, to add a set_articles method to Reporter and then override the save() method so it will check if there are any articles set and add them after saving the Reporter
But before I start improvising I would like to know if there are already any solutions within django
The save() method accepts an optional commit keyword argument, which accepts either True or False. If you call save() with commit=False, then it will return an object that hasn’t yet been saved to the database. In this case, it’s up to you to call save() on the resulting model instance.

I don't understand how Django-Rest-Framework serializers work

This may seem like a dumb question but I really feel like Django-Rest-Framework does not explain really well how it works. There is too much black box magic which confuses the configuration instructions (in my opinion).
For instance, it says I can override create or update within my serializer. So when my view post, I can send data to the serializer which has an update method declared.
class MySerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
def update(self, instance, validated_data):
Does update only get called when the model already exists and we're just updating some of it's data? Or does it call create when it creates a new one?
if I were to add this method to that class,
def create(self, validated_data):
return MyObject.objects.create(**validated_data)
is this specifically the method that must be called in order to add a new object? and your ability to override should be put in the serializer, but if not declared this is the default method with parameters that's being called?
There is too much black box magic which confuses the configuration instructions (in my opinion).
If there is something in the documentation that you think can be improved, feel free to submit a pull request with an update. If it seems reasonable, it will probably be merged and show up in a future release.
Or does it call create when it creates a new one?
create is called when a serializer is not initialized with a model instance, but only data is passed into it. Once serializer.save() is called, the serializer check if an instance was passed in and directly calls create so the model instance is created and saved in the database.
Does update only get called when the model already exists and we're just updating some of it's data?
update is called when a serializer is initialized with a model instance (or other object) and serializer.save() is called. This is roughly equivalent to Model.objects.update() when compared to Model.objects.create().
is this specifically the method that must be called in order to add a new object?
Serializers are designed to be saved (including object creation and updating) using the central serializer.save() method. This is similar to how a model can be saved or created using the model.save() method.
and your ability to override should be put in the serializer, but if not declared this is the default method with parameters that's being called?
It is recommended to override create and update on the serializer level if you need to change the logic for how a model and its related objects need to be saved, such as when working with nested serializers.

confused about self.instance in save() of child of ModelForm()

The save() documentation explains that:
A subclass of ModelForm can accept an
existing model instance as the keyword
argument instance; if this is
supplied, save() will update that
instance. If it's not supplied, save()
will create a new instance of the
specified model
However, self.instance in save() always has an object.
So, how do I tell if the instance is existing or a newly created one?
You can check self.instance.pk to see if the model has previously been saved. However, that could be unreliable in the case where you created a new instance of the model and then initialized a modelform with that instance before saving it.
Another possibility, based on the BaseModelForm source code in Django 1.2, is to check self.instance._adding, which will be True if the model was created and False otherwise. However, I haven't tested this, so YMMV.
If the first option will work, I'd recommend using that rather than an undocumented feature of ModelForms--it's less likely to change in the future and probably clearer.

Is there any way to make Django's get_or_create() to create an object without saving it to database?

When using Django's get_or_create(), when created=True, is there any way to
make it so that it creates an object without saving it to DB?
I want to take the newly created object, do some validation tests, and
only save it to DB if it passes all tests.
Rather than try to make get_or_create something it's not, why not just create a new #classmethod (or use a custom manager) called get_or_new(), and then only do the save() when you want to?
Why not override the model's save method, and have it do the tests there? Then you don't have to make sure you use the right creation method each time.
class MyModel(Model)
def save(self):
self.run_presave_tests()
if self.passed_tests:
super(MyModel, self).save()

Django - logical delete

I want to make the following modification to the Django framework.
I want it to create a "deleted" field for each model I create.
I want it to be checked as deleted when I delete it from the admin page instead of being physically deleted.
I do not want these records checked as deleted to be listed.
I'm new to Django, I'm seeing if I can do what I want to do with it easily. I need this change because it's the way we currently work.
So far these are the changes I have made, I would like to understand how the whole Django framewok works inside but I'm so far from that, is there any documentation online which explains clearly how the inside framework parts/files/modules/classes work together, the specific role of each one, etc
In the base.py file, in the modelbase class, below this code,
for obj_name, obj in attrs.items():
new_class.add_to_class(obj_name, obj)
I added,
from django.db import models
new_class.add_to_class('deleted', models.BooleanField())
When it creates a model it adds the "deleted" field to it.
In the base.py file, in the save method, I changed what it was there for
self.deleted = True
self.save()
So, now it check as deleted a record instead of physically delete it.
Now what I want is those records not to be listed.
I don't understand why you're modifying the framework code instead of putting your deleted field in a model base class that all of your models extend from.
Nevertheless, a nice way to filter those records out would be to add a custom manager to the model (or your base model class, if you choose to create one). To this manager, override the get_query_set method as described here. In your overridden method, add a exclude(deleted=True) filter.
Take a look at the Django-logicaldelete app, You just inherit your models from their provided Model class and you get Logical delete for all of them.
It comes with an adminModel as well so you can manage logically deleted models there too.
Override the delete() method in your model class, set the deleted attribute there
Create a custom manager which will filter by deleted attribute and set it as the default one (objects = MyDeletedManager)