Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

is this library suitable for this kind of bulk updates? #3

Closed
simkimsia opened this issue May 10, 2020 · 6 comments
Closed

is this library suitable for this kind of bulk updates? #3

simkimsia opened this issue May 10, 2020 · 6 comments

Comments

@simkimsia
Copy link

simkimsia commented May 10, 2020

Hi there,

i read your bad, ugly, good examples in the docs. I am still unsure if your library solves my use case well.

my version would be

in english

find all books which is not null at field1 and is null at field2 and then update individual book such that individual book field2 equals to individual book field1.

in sql

update books set field2=field1 where field1 is not null and field2 is null

in django orm bad

from django.db.models import F

from books.models import Book

Book.objects.filter(field1__isnull=False,field2__isnull=True).update(field2=F('field1'))

in django-model-values

??

Is this usecase even suitable?

Thank you

@coady
Copy link
Owner

coady commented May 10, 2020

Sure. For this case, you could use any combination of:

  • F attributes: F.field
  • '__ne' lookups with nulls: F.field != None
  • item assignment for update: ['field2'] = F.field1

All of them would like:

from model_values import F

Book.objects.filter(F.field1 != None, F.field2 == None)['field2'] = F.field1

@simkimsia
Copy link
Author

simkimsia commented May 11, 2020

Thanks for response

from model_values import F

Book.objects.filter(F.field1 != None, F.field2 == None)['field2'] = F.field1

Is this possible instead?

from model_values import F
Book.objects.filter(field1__isnull=False,field2__isnull=True)['field2'] = F.field1

what abt custom save logic

Another follow up question I have is:

image

so custom logic in the save method of Book model is NOT triggered when i update using the model-values way yes?

For e.g. I use model-utils to have modified timestamp field that gets auto updated when save

Will those be triggered in my bulk_update via model-values?

@coady
Copy link
Owner

coady commented May 11, 2020

Is this possible instead?

from model_values import F
Book.objects.filter(field1__isnull=False,field2__isnull=True)['field2'] = F.field1

Yes, that works.

so custom logic in the save method of Book model is NOT triggered when i update using the model-values way yes?

Correct, but that's true of Django's update method:

Finally, realize that update() does an update at the SQL level and, thus, does not call any save() methods on your models, nor does it emit the pre_save or post_save signals (which are a consequence of calling Model.save())

not just in model-values.

For e.g. I use model-utils to have modified timestamp field that gets auto updated when save
Will those be triggered in my bulk_update via model-values?

No, but that also is consistent with Django's DateField.auto_now:

The field is only automatically updated when calling Model.save(). The field isn’t updated when making updates to other fields in other ways such as QuerySet.update(), though you can specify a custom value for the field in an update like that.

The way to do implement a modified field without calling .save is to specify the field in the update call:

from django.utils import timezone

.update(modified=timezone.now(), **...)

That updates modified for all matching rows. In some use cases, modified shouldn't be updated unless the other tracked field(s) actually changed. model-values provides a utility for that as well:

.change({'modified': timezone.now()}, **...)

@simkimsia
Copy link
Author

abt Django update

Correct, but that's true of Django's update method:

So can I say that ultimately, model-values is calling the Django update method but gives the
developer a better interface to call it?

That updates modified for all matching rows. In some use cases, modified shouldn't be updated unless the other tracked field(s) actually changed. model-values provides a utility for that as well:

Oh... that's very very sweet!

question abt affected records

using the same Book example I gave above, ultimately model-values will just generate a single SQL query? If so, does model-values provide a way to tell me how many records were affected?

If I run the SQL query on postgres via a UI client like TablePlus, there's feedback on the number of records matched and affected.

I know that the regular Django update only returns rows matched but not affected. See
https://docs.djangoproject.com/en/3.0/topics/db/queries/#updating-multiple-objects-at-once

and i quote

The update() method is applied instantly and returns the number of rows matched by the query (which may not be equal to the number of rows updated if some rows already have the new value). The only restriction on the QuerySet being updated is that it can only access one database table: the model’s main table. You can filter based on related fields, but you can only update columns in the model’s main table.

@coady
Copy link
Owner

coady commented May 12, 2020

ultimately model-values will just generate a single SQL query? If so, does model-values provide a way to tell me how many records were affected?

model-values' .change runs a single SQL update query, and returns the number of changed rows.

@coady coady closed this as completed May 16, 2020
@simkimsia
Copy link
Author

Thanks @coady ! Sorry I just saw this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants