Opened 5 years ago
Last modified 19 months ago
#31539 assigned New feature
Add support for bulk operations on reverse many-to-one manager
Reported by: | Baptiste Mispelon | Owned by: | Rahul Biswas |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | dev |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Accepted | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Using the Book
and Author
models from the docs:
class Author(models.Model): name = models.CharField(max_length=100) class Book(models.Model): author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books') title = models.CharField(max_length=200)
This works and creates two books linked to their author correctly:
toni = Author.objects.create(name="Toni Morrison") toni.books.create(title="The Bluest Eye") toni.books.create(title="Beloved")
But if you try to use bulk_create
to achieve the same, you get an error:
toni = Author.objects.create(name="Toni Morrison") toni.books.bulk_create([ Book(title="The Bluest Eye"), Book(title="Beloved"), ])
This fails with an IntegrityError
because bulk_create
doesn't automatically fill in the value of Book.author
(the way it does it for create()
).
The documentation for RelatedManager
[1] doesn't mention bulk_create()
but it's not clear to me if that means the operation is unsupported or not (other methods like count()
or filter()
are not listed either but are clearly supported). Because of this I wasn't sure whether to mark this ticket as a bug or as a new feature.
Looking at the code [2], I can't find an explanation of why bulk_create
or bulk_update
are not implemented either.
I've come up with the following implementation which seems to work (I haven't tested it extensively):
def bulk_create(self, objs, **kwargs): def set_field_to_instance(instance): setattr(instance, self.field.name, self.instance) return instance objs = map(set_field_to_instance, objs) db = router.db_for_write(self.model, instance=self.instance) return super(RelatedManager, self.db_manager(db)).bulk_create(objs, **kwargs)
[1] https://docs.djangoproject.com/en/dev/ref/models/relations/#django.db.models.fields.related.RelatedManager
[2] https://github.com/django/django/blob/aff7a58aef0264e5b2740e5df07894ecc0d7a580/django/db/models/fields/related_descriptors.py#L559
Change History (4)
comment:1 by , 5 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
comment:2 by , 5 years ago
Triage Stage: | Unreviewed → Accepted |
---|
I think #27408 should be closed in favour of this ticket as we should only do this automatically for reverse many-to-one managers of saved objects and not systematically for all reverse relationship a model has. I think the scope of this ticket is better defined and more in line with the rest of the Manager
interface.
comment:3 by , 20 months ago
Owner: | removed |
---|---|
Status: | assigned → new |
comment:4 by , 19 months ago
Owner: | set to |
---|---|
Status: | new → assigned |
I'll try to come up with a PR. If you don't see any activity from me within a week you can assume I've given up and anyone can feel free to reassign the ticket to themselves :)