django-bulk-update-or-create icon indicating copy to clipboard operation
django-bulk-update-or-create copied to clipboard

How can I bulk_update_or_create with ManyToManyField?

Open Su-yj opened this issue 3 years ago • 5 comments

Su-yj avatar Nov 05 '21 06:11 Su-yj

You can't, same as with bulk_create, bulk_update or even with normal .save()

You can however use the callback or the returned objects to update those fields after.

I'll add example to documentation as I just noticed there is none using callback / returned objects, just need to finish #37 first

fopina avatar Feb 14 '23 07:02 fopina

You can't, same as with bulk_create, bulk_update or even with normal .save()

You can however use the callback or the returned objects to update those fields after.

I'll add example to documentation as I just noticed there is none using callback / returned objects, just need to finish #37 first

Maybe I can use callback, but the data returned by the callback function cannot find relationship with original data.

My code likes this:

def callback(ret):
    created, updated = ret
    ...

with RandomData.objects.bulk_update_or_create_context(update_fields=['data'], match_field='uuid', batch_size=10, status_cb=callback) as bulkit:
    for item in origin_data:
        bulkit.queue(RandomData(id=item['id'], data=item['data']))

Su-yj avatar Feb 15 '23 13:02 Su-yj

Indeed, you’ll have to keep track of that matching somewhere. I’ve done in before using the same unique field of each record as a dict key and a list of related objects as value.

Not an issue in this package though as none django ORM handles creating relationships. You always create them after creating the object.

fopina avatar Feb 15 '23 13:02 fopina

Indeed, you’ll have to keep track of that matching somewhere. I’ve done in before using the same unique field of each record as a dict key and a list of related objects as value.

Not an issue in this package though as none django ORM handles creating relationships. You always create them after creating the object.

Yes. I know i can keep a track to do that. But I think it`s not pythoning.

I have a idea. Can the bulkit queue accept the second param? Then, the callback function return a new model and param which passed in by the user. User can get the data without the track.

Just like this:

with RandomData.objects.bulk_update_or_create_context(update_fields=['data'], match_field='uuid', batch_size=10, status_cb=callback) as bulkit:
    for item in origin_data:
        # put the data to queue
        bulkit.queue(RandomData(id=item['id'], data=item['data']), param=item)

def callback(ret):
    created, updated = ret
    for model, data in created:
        pass
    ...

It just my think. It may not be easy to realize, and will destroy the previous interface.

Su-yj avatar Feb 16 '23 05:02 Su-yj

It’s not an uncommon for methods with callbacks to allow for passing extra context, it’s not a bad idea.

and I think the change can be retro compatible as context will be an optional kwarg and it can be sent to callback only if defined.

I’ll keep it in mind, thanks!

fopina avatar Feb 16 '23 07:02 fopina