Opened 5 years ago

Closed 5 years ago

Last modified 5 years ago

#30690 closed Uncategorized (duplicate)

get_or_create() ignores database router's db_for_read() method

Reported by: Maciej Olko Owned by: nobody
Component: Database layer (models, ORM) Version: 2.2
Severity: Normal Keywords: router, database-router, get_or_create
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

class Foo(models.Model):  # model in `legacy` app
    bar = models.CharField()

class FizRouter:
    @staticmethod
    def db_for_read(model, **hints):
        if model._meta.app_label == 'legacy':
            return 'legacy'
        return 'default'

    @staticmethod
    def db_for_write(model, **hints):
        return 'default'

# file: settings.py
DATABASE_ROUTERS = ['path.FizRouter']

Foo.objects.get_or_create() will hit default database no matter if requested object is in legacy database.
I would assume that we would try to get object from legacy database and create in default if not found.

As far as I'm concerned current behaviour is not documented, IMHO it should be, if current behaviour is desired.

Change History (2)

comment:1 by Simon Charette, 5 years ago

Resolution: duplicate
Status: newclosed

By it's nature of dealing with both read and writes the get_or_create method has to be targeting the write database for reads.

There's a comment in the method definition about it and following the git blame trace leads to this commit.

If in a single transaction, the master deletes a record and then get_or_creates a similar record, under the new behavior the get_or_create would find the record in the slave db and fail to re-create it, leaving the record nonexistent, which violates the contract of get_or_create that the record should always exist afterwards. We need to do everything against the master here in order to ensure correctness.

Closing as duplicate of #16865.

Last edited 5 years ago by Simon Charette (previous) (diff)

comment:2 by Maciej Olko, 5 years ago

I couldn't find the duplicate. Thank you for response.

Note: See TracTickets for help on using tickets.
Back to Top