Django partial update - django

I have two threads, one which runs something like update t set ColA=foo and the other runs update t set ColB=foo. If they were doing raw SQL statements there would be no contention, but since Django gets and saves the entire row, a race condition can occur.
Is there any way to tell Django that I just want to save a certain column?

Update old topic.
Now, we have update_fields argument with save:
If save() is passed a list of field names in keyword argument
update_fields, only the fields named in that list will be updated.
https://docs.djangoproject.com/en/stable/ref/models/instances/#specifying-which-fields-to-save
product.name = 'Name changed again'
product.save(update_fields=['name'])

You are correct that save will update the entire row but Django has an update which does exactly what you describe.
https://docs.djangoproject.com/en/stable/ref/models/querysets/#update

I think your only option to guarantee this is to write the raw SQL by hand by using Manager.raw() or a cursor depending on which one is more appropriate.

Related

Get part of django model depending on a variable

My code
PriceListItem.objects.get(id=tarif_id).price_eur
In my settings.py
CURRENCY='eur'
My Question:
I would like to pick the different info depending on the CURRENCY variable in settings.py
Example:
PriceListItem.objects.get(id=tarif_id).price_+settings.CURRENCY
Is it possible?
Sure. This has nothing to do with Django actually. You can reach the instance's attribute through pure Python:
getattr(PriceListItem.objects.get(id=tarif_id), 'price_'+settings.CURRENCY)
Note it might be a better idea to have a method on the model which accepts the currency as a parameter and returns the correct piece of data (through the line I wrote above, for example).
I think this should work
item = PriceListItem.objects.get(id=tarif_id)
value = getattr(item, price_+settings.CURRENCY)
In case you are only interested in that specific column, you can make the query more efficient with .values_list:
my_price = PriceListItem.objects.values_list_(
'price_{}'.format(settings.CURRENCY),
flat=True
).get(id=tarif_id)
This will only fetch that specific column from the database, which can be a (a bit) faster than first fetching the entire row into memory, and then discard all the rest later.
Here my_price is thus not a PriceListItem object, but the value that is stored for the specific price_cur column.
It will thus result in a query that looks like:
SELECT pricelistitem.price_cur
FROM pricelistitem
WHERE id=tarif_id

How to get the date when the particular attribute was first changed in rails

I have a boolean atrribute whose default is false. How can i get the date when the attribute was changed to true?
The is_changed gives you if the value was changed. I want the date when the attribute was first changed.
How do i get it in rails?
add attribute 'first_change' in that table which will save time stamp of every first change of the boolean attribute changed to true or false, then in model write the callback like this
before_update :check_changes
def check_changes
if self.<boolean_attribute>.is_changed? and first_change.nil?
self.update(first_change: Time.now)
end
end
After this you can check when the boolean attribute was changed.
You can wrap your boolean attribute in distinct model and from there you can easily trace when specific field was initially setted up or updated. In your current model you can't trace changing state of specific attributes, only the whole object, but it's not what you need I guess.
Well, looks like you basically want the feature of git in ActiveRecord records.
There are two ways
Use a separate col like changed_date. Update it whenever the field is changed for the first time.
I recommend this if your requirement is that simple. Do not use heavier gems.
Use libraries like VestalVersion or PaperTrail
these are helpful to track every activity in your records.
you can keep track of every changes, what its changed to and when
also you can revert your record to any point of time it was changed
I think there are two ways like above answer suggested to make a separate field and add date there when field changed first time or
you can use Public Activity gem that will log all the model activity with params.
It creates a activities table based on this table you can get the date of the fields when it was first changed but it is a lengthy process

How to update by order

I have a django application with a model. I need to update the model objects according to ascending id. Something like this.
MyModel.objects.filter(my_field='value').order_by("id").update(another_field='anotheValue')
Can i be assure that the update will happen by the order according to the order by?
Since you already ordered the query set using id, it should update sequentially.
From the docs,
Using update() also prevents a race condition wherein something might
change in your database in the short period of time between loading
the object and calling save().
So I think the ordering might not matter. However to be perfectly sure, you can iterate over the items and update them:
rows = MyModel.objects.filter(my_field='value').order_by("id")
for row in rows:
row.another_field = 'another value'
row.save()
However, the update method would generate one SQL query, where as the iteration would generate many. So this might be an issue with performance.

Django - Insert Without Returning the Id of the Saved Object

Each time the save() method is called on a Django object, Django executes two queries one INSERT and one SELECT. In my case this is usefull except for some specific places where each query is expensive. Any ideas on how to sometimes state that no object needs to be returned - no SELECT needed.
Also I'm using django-mssql to connect to, this problem doesn't seem to exist on MySQL.
EDIT : A better explanation
h = Human()
h.name='John Foo'
print h.id # Returns None, No insert has been done therefore no id is available
h.save()
print h.id # Returns the ID, an insert has taken place and also a select statement to return the id
Sometimes I don't the need the retruning ID, just insert
40ins's answer was right, but probably it might have higher costs...
When django execustes a save(), it needed to be sure if the object is a new one or an existing one. So it hits the database to check if related objext exists. If yes, it executes an UPDATE, orherwise it executes an ISERT
Check documentatin from here...
You can use force_insert or force_update ,but that might be cause serious data integrity problems, like creating a duplicate entry instead of updating the existing one...
So, if you wish to use force , you must be sure whether it will be an INSERT or an UPDATE...
Try to use save() method with force_insert or force_update attributes. With this attributes django knows about record existence and don't make additional query.
The additional select is the django-mssql backend getting the identity value from the table to determine the ID that was just inserted. If this select is slow, then something is wrong with your SQL server/configuration because it is only doing SELECT CAST(IDENT_CURRENT(*table_name*) as bigint) call.

How to limit columns returned by Django query?

That seems simple enough, but all Django Queries seems to be 'SELECT *'
How do I build a query returning only a subset of fields ?
In Django 1.1 onwards, you can use defer('col1', 'col2') to exclude columns from the query, or only('col1', 'col2') to only get a specific set of columns. See the documentation.
values does something slightly different - it only gets the columns you specify, but it returns a list of dictionaries rather than a set of model instances.
Append a .values("column1", "column2", ...) to your query
The accepted answer advising defer and only which the docs discourage in most cases.
only use defer() when you cannot, at queryset load time, determine if you will need the extra fields or not. If you are frequently loading and using a particular subset of your data, the best choice you can make is to normalize your models and put the non-loaded data into a separate model (and database table). If the columns must stay in the one table for some reason, create a model with Meta.managed = False (see the managed attribute documentation) containing just the fields you normally need to load and use that where you might otherwise call defer(). This makes your code more explicit to the reader, is slightly faster and consumes a little less memory in the Python process.