u = UserDetails.objects.create(first_name='jake',last_name='sullivan')
u.save()
UserDetails.objects.create() and u.save() both perform the same save() function. What is the difference? Is there any extra check or benefit in using create() vs save()?
Similar questions:
What's the best way to create a model object in Django?
Django: Difference between save() and create() from transaction perspective
Django Model() vs Model.objects.create()
The Django documentation says it is the same. It is just more convenient to make it on one line. You could make a save() on one line too, but it would be more verbose and less readable -- it is clear you are creating a new object with the create() method.
create(**kwargs)
A convenience method for creating an object and saving it all in one
step. Thus:
p = Person.objects.create(first_name="Bruce", last_name="Springsteen")
and:
p = Person(first_name="Bruce", last_name="Springsteen")
p.save(force_insert=True)
are equivalent.
The force_insert parameter is documented elsewhere, but all it means
is that a new object will always be created. Normally you won’t need
to worry about this. However, if your model contains a manual primary
key value that you set and if that value already exists in the
database, a call to create() will fail with an IntegrityError since
primary keys must be unique. Be prepared to handle the exception if
you are using manual primary keys.
Similar question:
Django Model() vs Model.objects.create()
The difference between Model() vs Model.objects.create() are summarized as below.
.save() perform internally as either INSERT or UPDATE object to db, while .objects.create() perform only INSERT object to db.
Model.save() perform ....
UPDATE → If the object’s primary key attribute is set to a value that evaluates to True
INSERT →
If the object’s primary key attribute is not set or if the UPDATE didn’t update anything (e.g. if primary key is set to a value that doesn’t exist in the database).
If primary key attribute is set to a value then Model.save() perform UPDATE but Model.objects.create raise IntegrityError.
eg.
models.py
class Subject(models.Model):
subject_id = models.PositiveIntegerField(primary_key=True, db_column='subject_id')
name = models.CharField(max_length=255)
max_marks = models.PositiveIntegerField()
1) Insert/Update to db with Model.save()
physics = Subject(subject_id=1, name='Physics', max_marks=100)
physics.save()
math = Subject(subject_id=1, name='Math', max_marks=50) # Case of update
math.save()
Output:
Subject.objects.all().values()
<QuerySet [{'subject_id': 1, 'name': 'Math', 'max_marks': 50}]>
2) Insert to db with Model.objects.create()
Subject.objects.create(subject_id=1, name='Chemistry', max_marks=100)
IntegrityError: UNIQUE constraint failed: m****t.subject_id
Explanation: Above math.save() is case of update since subject_id is primary key and subject_id=1 exists django internally perform UPDATE, name Physics to Math and max_marks from 100 to 50 for this, but objects.create() raise IntegrityError
Model.objects.create() not equivalent to Model.save() however same can be achieved with force_insert=True parameter on save method i.e Model.save(force_insert=True).
Model.save() return None where Model.objects.create() return model instance i.e. package_name.models.Model
Conclusion: Model.objects.create() internally do model initialization and perform save with force_insert=True.
source-code block of Model.objects.create()
def create(self, **kwargs):
"""
Create a new object with the given kwargs, saving it to the database
and returning the created object.
"""
obj = self.model(**kwargs)
self._for_write = True
obj.save(force_insert=True, using=self.db)
return obj
The following links can be followed for more details:
https://docs.djangoproject.com/en/stable/ref/models/querysets/#create
https://github.com/django/django/blob/2d8dcba03aae200aaa103ec1e69f0a0038ec2f85/django/db/models/query.py#L440
Note: Above answer is from question.
Related
I want to restrict the user from creating a new record on a model based on a specific condition. for instance, I have two fields in the model both of them is Integer (move_item_count,item_number ) and they are computed field I compute their values. If their move_item_count != item_number I should prevent the user from creating the record and raise an error message. here is my code it gives me this error 'NoneType' object has no attribute 'id'.
here is my code :
# Overriding the Create Method in Odoo
#api.model
def create(self, vals):
# overriding the create method to add the sequence and prevent the user from
# creating a new record if a condition didn't fulfilled
for rec in self:
if rec.move_item_count != rec.item_number:
raise UserError(_("Some Item Are Missing."))
if vals.get('name', _('New')) == _('New'):
vals['name'] = self.env['ir.sequence'].next_by_code('move.sequence') or _('New')
result = super(LogisticMove, self).create(vals)
return result
Overriding the create is not recommended when applying a constraint on creation of a record as this can get really messy when 2 or more modules override the same create. You'd be better off using actual constraints (see doc right here for example).
If you feel like you must, then keep in mind that until the actual create (the super) has been called, the record is NOT in the database and also NOT present in self. All you have to go with are the values for creating this which are stored in your vals parameter.
If you inspect those values you can do the comparison and provide feedback to the user.
I'm using Django create_or_update function.
In case of update, Is there a way to know the list of changed fields.
Obviously I can use the get_or_create function before and in case, after this, I can update the model.. but I'm looking for a way to have this using a single query.
Is it possible?
update_or_create(defaults=None, **kwargs)
The update_or_create method tries to fetch an object from database based on the given kwargs. If a match is found, it updates the fields passed in the defaults dictionary.
The query doesn't care if the updated fields have changed or not, all the field in "default" are updated
Returns a tuple of (object, created), where object is the created or updated object and created is a boolean specifying whether a new object was created.
https://docs.djangoproject.com/en/3.0/ref/models/querysets/#update-or-create
Maybe it's not the best solution but I think it gets the job done. You could retrieve the instance that will be updated and then compute the fields that have changed using filter() and lambda functions, as suggested in this answer by Rahul Gupta.
Let's suppose you can identify the instance through say first_name and last_name as reported in the docs:
old_instance = Person.objects.filter(first_name=first_name, last_name=last_name)
old_instance = old_instance[0] if old_instance else None
new_instance, created = Person.objects.update_or_create(
first_name=first_name, last_name=last_name,
defaults={'first_name': 'Bob'},
)
# it's been updated and we have the old instance
if not created and old_instance:
# get a list of the model's fields
fields = Person._meta.get_all_field_names()
# compute the fields which have changed
diff_fields = filter(lambda field: getattr(old_instance,field,None)!=getattr(new_instance,field,None), fields)
The diff_fields list at this point should only contain first_name.
This is an example Python 2 code:
from django.db import models
def my_validator(value):
assert isinstance(value, (int, long))
class Foo(models.Model):
name = models.CharField(...) # irrelevant here
class Bar(models.Model):
name = models.CharField(...) # irrelevant here
foo = models.ForeignKey(Foo, validators=[my_validator])
If I create a Foo instance, then a Bar instance (assigning the foo instance), and then validate, this code passes: the FK value to validate is not a model instance but an ID (which is an integer, by default):
foo = Foo.objects.create(name='foo')
bar = Bar.objects.create(name='bar', foo=foo)
Edit: I forgot to include the full_clean() call. But yes: the troublesome code calls full_clean(). In fact, the first time I noticed this behavior was when trying to treat the value in the validator callable, as a model instance instead of a raw value, which triggered a int value has no attribute xxx when trying to invoke an instance method inside the validator.
bar.full_clean()
This happens in Django 1.9. Is this documented and expected?
Yes - this is implicitly referred to in the documentation for ForeignKey.to_field:
The field on the related object that the relation is to. By default, Django uses the primary key of the related object.
Also:
For fields like ForeignKey that map to model instances, defaults should be the value of the field they reference (pk unless to_field is set) instead of model instances.
That is, by default, the value of the ForeignKey is the primary key of the related object - i.e., an integer.
You can however specify a different to_field, in which case the value would take the type of that field.
In terms of what value is passed to the validators, it seems that the assumption is implicit that this is the to_field (what else would you validate other than the value that is going to be stored in the database? It does not make much sense to pass a model object when validating a foreign key, because the key itself is only a pointer to the object and does not say anything about what that object should be.).
But to answer your question - there doesn't appear to be any explicit documentation stating this.
I'm not sure that #solarissmoke answer is relevant to the question.
IMO, validation is not invoked at objects.create, if you want to validate your model before creating it you should either use a ModelForm, or call it manually.
foo = Foo.objects.create(name='foo')
bar = Bar(name='bar', foo=foo)
try:
bar.full_clean()
bar.save()
except ValidationError as e:
# Do something based on the errors contained in e.message_dict.
# Display them to a user, or handle them programmatically.
pass
UPDATE:
OK, so what exactly is happening is that when you call .full_clean() we get .clean_fields() called.
Inside the clean_fields we have something like:
raw_value = getattr(self, f.attname)
if f.blank and raw_value in f.empty_values:
continue
try:
setattr(self, f.attname, f.clean(raw_value, self))
except ValidationError as e:
errors[f.name] = e.error_list
Where two thing happens:
We get raw_value for the field
We call field.clean
In the field.clean() we have .to_python(), validate() and .run_validators() called in this order, its something like:
value = self.to_python(value)
self.validate(value)
self.run_validators(value)
return value
Which Django explains here: Form and field validation
BUT, that's not the reason why you get int/long in your custom validator.
The reason is because ForeignKey fields store their values in an attribute with _id at the end, which equals to f.attname. So during the whole process of validating FKs Django works with int/long values, not with objects.
If you see the ForeignKey.validate method, you will find out that it just checks if a row with that id exists.
I have refered this documentation page for save() method
https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#the-save-method
But in my view I have the following code
def saveEvent(request):
eventForm = EventForm(request.POST)
if eventForm.is_valid():
event=eventForm.save(commit=False)
requestor=None
if(event.is_hp_requestor):
#Save and get requestor
requestorHPPersonForm = PersonHiddenForm(request.POST, prefix = 'hp_requestor')
requestorHPEmployeeForm = HPEmployeeForm(request.POST, prefix = 'hp_requestor')
requestor=saveHPEmployeeHelper(requestorHPEmployeeForm, requestorHPPersonForm).person
else:
requestorHPPersonForm = PersonHiddenForm(request.POST, prefix = 'hp_requestor')
requestor=get_object_or_404(Person, pk=requestorHPPersonForm.data[requestorHPPersonForm.prefix+'-'+'email'])
if (requestor is not None) and eventForm.is_valid():
event.requestor_new=requestor
event.save()
if request.POST['opportunities']:
for str_sfid in request.POST['opportunities'].split(','):
sfid = int(str_sfid)
opportunity_object, dummy = Opportunity.objects.get_or_create(sfdc_id=sfid)
event.opportunities.add(opportunity_object)
event.save()
return HttpResponseRedirect(reverse('dashboard'))
else:
errors = eventForm.errors
return HttpResponse(json.dumps(errors), status=500, mimetype='application/json')
In my view I do not invoke the save_m2m() method, but still it save many2many field data.
How is it works, if this is working then why we need the save_m2m() method?
The docs you linked to explain this:
Calling save_m2m() is only required if you use save(commit=False). When you use a simple save() on a form, all data – including many-to-many data – is saved without the need for any additional method calls.
Also, it looks like event is itself a model instance rather than a form. save_m2m is required for forms, not model instances.
To paraphrase the explanation in the docs: a form's save method, if called with commit=True (the default) does two things - it creates a new model instance using the form's cleaned data, and it writes that model instance to the database. Then, if there are any many-to-many relationships, it writes those to the database as well. It does that after writing the instance because you can't write a many-to-many relationship until the instance has a primary key, which is auto-generated when you write it to the database.
If you call the form's save method with commit=False, it creates the new model instance but it does not write it to the database. Thus, it has no primary key yet and the many-to-many information can't be saved either. After you save the model instance and therefore generate a primary key for it, the many-to-many information is still stored only in the form object. So you need to notify the form object that it's now OK to save the many-to-many information, by calling save_m2m.
edit Since you've added more of your code I can see more clearly what you're asking. The above code will not save many-to-many relationships that are set in your EventForm instance. Is that what your loop to set opportunities is doing?
I have a function which currently calls Models.object.get(), which returns either 0 or 1 model objects:
if it returns 0, I create a new model instance in the except DoesNotExist clause of the function.
Otherwise, I would like to update the fields in the pre-existing
instance, without creating a new one.
I was originally attempting to
call .update() on the instance which was found, but .update()
seems to be only callable on a QuerySets. How do I get around
changing a dozen fields, without calling .filter() and comparing
the lengths to know if I have to create or update a pre-existing
instance?
With the advent of Django 1.7, there is now a new update_or_create QuerySet method, which should do exactly what you want. Just be careful of potential race conditions if uniqueness is not enforced at the database level.
Example from the documentation:
obj, created = Person.objects.update_or_create(
first_name='John', last_name='Lennon',
defaults={'first_name': 'Bob'},
)
The update_or_create method tries to fetch an object from database
based on the given kwargs. If a match is found, it updates the
fields passed in the defaults dictionary.
Pre-Django 1.7:
Change the model field values as appropriate, then call .save() to persist the changes:
try:
obj = Model.objects.get(field=value)
obj.field = new_value
obj.save()
except Model.DoesNotExist:
obj = Model.objects.create(field=new_value)
# do something else with obj if need be
if you want only to update model if exist (without create it):
Model.objects.filter(id = 223).update(field1 = 2)
mysql query:
UPDATE `model` SET `field1` = 2 WHERE `model`.`id` = 223
As of Django 1.5, there is an update_fields property on model save. eg:
obj.save(update_fields=['field1', 'field2', ...])
https://docs.djangoproject.com/en/dev/ref/models/instances/
I prefer this approach because it doesn't create an atomicity problem if you have multiple web app instances changing different parts of a model instance.
I don't know how good or bad this is, but you can try something like this:
try:
obj = Model.objects.get(id=some_id)
except Model.DoesNotExist:
obj = Model.objects.create()
obj.__dict__.update(your_fields_dict)
obj.save()
Here's a mixin that you can mix into any model class which gives each instance an update method:
class UpdateMixin(object):
def update(self, **kwargs):
if self._state.adding:
raise self.DoesNotExist
for field, value in kwargs.items():
setattr(self, field, value)
self.save(update_fields=kwargs.keys())
The self._state.adding check checks to see if the model is saved to the database, and if not, raises an error.
(Note: This update method is for when you want to update a model and you know the instance is already saved to the database, directly answering the original question. The built-in update_or_create method featured in Platinum Azure's answer already covers the other use-case.)
You would use it like this (after mixing this into your user model):
user = request.user
user.update(favorite_food="ramen")
Besides having a nicer API, another advantage to this approach is that it calls the pre_save and post_save hooks, while still avoiding atomicity issues if another process is updating the same model.
As #Nils mentionned, you can use the update_fields keyword argument of the save() method to manually specify the fields to update.
obj_instance = Model.objects.get(field=value)
obj_instance.field = new_value
obj_instance.field2 = new_value2
obj_instance.save(update_fields=['field', 'field2'])
The update_fields value should be a list of the fields to update as strings.
See https://docs.djangoproject.com/en/2.1/ref/models/instances/#specifying-which-fields-to-save
I am using the following code in such cases:
obj, created = Model.objects.get_or_create(id=some_id)
if not created:
resp= "It was created"
else:
resp= "OK"
obj.save()
update:
1 - individual instance :
get instance and update manually get() retrieve individual object
post = Post.objects.get(id=1)
post.title = "update title"
post.save()
2 - Set of instances :
use update() method that works only with queryset that what would be returned by filter() method
Post.objects.filter(author='ahmed').update(title='updated title for ahmed')