Django | reverse relationship adding objects: many to one

Time:2020-11-20

In the associated model, such as many to one or many to many, in some scenarios, such as simply and quickly adding tags to specific users, in order to quickly add objects, reverse addition will be used. Here we briefly describe the many to one scenario

django 1.10.3

1 non custom model primary key

1.1 model example

@python_2_unicode_compatible
class Author(models.Model):
    name = models.CharField(max_length=30)

    def __str__(self):
        return self.name


@python_2_unicode_compatible
class Posts(models.Model):
    headline = models.CharField(max_length=100)
    author = models.ForeignKey(Author, related_name="author_posts")

    def __str__(self):
        return self.headline

1.2 operation process

In [6]: author2 = Author.objects.create(name='paul')

In [7]: post2 = Posts(headline='hello post2')

In [11]: author2.author_posts.add(post2, bulk=False)
BEGIN

Execution time: 0.000018s [Database: default]

INSERT INTO "apple_posts" ("headline",
                           "author_id")
VALUES ('hello post2',
        2)

Execution time: 0.000314s [Database: default]

Add the same instance repeatedly
In [12]: author2.author_posts.add(post2, bulk=False)
BEGIN

Execution time: 0.000018s [Database: default]

UPDATE "apple_posts"
SET "headline" = 'hello post2',
    "author_id" = 2
WHERE "apple_posts"."id" = 3

Execution time: 0.000257s [Database: default]

Attention should be paid to the addition herebulk=False

2 user defined model primary key

2.1 model examples

import uuid


class BaseBackBone(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid1().hex, editable=False, max_length=32)

    class Meta:
        abstract = True


@python_2_unicode_compatible
class AuthorWithId(BaseBackBone):
    name = models.CharField(max_length=30)

    def __str__(self):
        return self.name


@python_2_unicode_compatible
class PostsWithId(BaseBackBone):
    headline = models.CharField(max_length=100)
    author = models.ForeignKey(AuthorWithId, related_name="author_posts")

    def __str__(self):
        return self.headline

2.2 operation process

In [2]: author1 = AuthorWithId.objects.create(name='paul')

In [3]: post1 = PostsWithId(headline='hello post1 with id')

In [5]: author1.author_posts.add(post1, bulk=False)
BEGIN

Execution time: 0.000019s [Database: default]

UPDATE "apple_postswithid"
SET "headline" = 'hello post1 with id',
    "author_id" = '7d9d0f91ad6f11e6b0c1f45c89a84eed'
WHERE "apple_postswithid"."id" = '7d9d0f91ad6f11e6b0c1f45c89a84eed'

Execution time: 0.000141s [Database: default]

INSERT INTO "apple_postswithid" ("id",
                                 "headline",
                                 "author_id")
SELECT '7d9d0f91ad6f11e6b0c1f45c89a84eed',
       'hello post1 with id',
       '7d9d0f91ad6f11e6b0c1f45c89a84eed'

Execution time: 0.000291s [Database: default]

Add the same instance repeatedly
In [6]: author1.author_posts.add(post1, bulk=False)
BEGIN

Execution time: 0.000021s [Database: default]

UPDATE "apple_postswithid"
SET "headline" = 'hello post1 with id',
    "author_id" = '7d9d0f91ad6f11e6b0c1f45c89a84eed'
WHERE "apple_postswithid"."id" = '7d9d0f91ad6f11e6b0c1f45c89a84eed'

Execution time: 0.001262s [Database: default]

3 Summary

When adding objects with a custom primary key, the database will do an additional query operation, because Django needs to verify whether it is an update or an insert operation. In the scenario of using a custom primary key, the query operation of the database will be increased.