sauerburger
sauerburger

Reputation: 5148

Synchronized Model instances in Django

I'm building a model for a Django project (my first Django project) and noticed that instances of a Django model are not synchronized.

a_note = Notes.objects.create(message="Hello")  # pk=1
same_note = Notes.objects.get(pk=1)

same_note.message = "Good day"
same_note.save()

a_note.message  # Still is "Hello"

a_note is same_note  # False

Is there a built-in way to make model instances with the same primary key to be the same object? If yes, (how) does this maintain a globally consistent state of all model objects, even in the case of bulk updates or changing foreign keys and thus making items enter/exit related sets?

I can imagine some sort of registry in the model class, which could at least handle simple cases (i.e. it would fail in cases of bulk updates or a change in foreign keys). However, the static registry makes testing more difficult.

I intend to build the (domain) model with high-level functions to do complex operations which go beyond the simple CRUD actions of Django's Model class. (Some classes of my model have an instance of a Django Model subclass, as opposed to being an instance of subclass. This is by design to prevent direct access to the database which might break consistencies and to separate the business logic from the purely data access related Django Model.) A complex operation might touch and modify several components. As a developer using the model API, it's impossible to know which components are out of date after calling a complex operation. Automatically synchronized instances would mitigate this issue. Are there other ways to overcome this?

Upvotes: 0

Views: 1357

Answers (1)

dirkgroten
dirkgroten

Reputation: 20702

TL;DR "Is there a built-in way to make model instances with the same primary key to be the same object?" No.

A python object in memory isn't the same thing as a row in your database. So when you create a_note and then fetch same_note from the db, those are two different objects in memory, even though they are the same representation of the underlying row in your database. When you fetch same_note, in fact, you instantiate a new Notes object and initialise it with the values fetched from the database.

Then you change and save same_note, but the a_note object in memory isn't changed. If you did a_note.refresh_from_db() you would see that a_note.message was changed.

Now a_note is same_note will always be False because the location in memory of these two objects will always be different. Two variables are the same (is is True) if they point to the same object in memory.

But a_note == same_note will return True at any time, since Django defines two model instances to be equal if their pk is the same.

Note that if the complexity you're talking about is that in the case of multiple requests one request might change underlying values that are being used by another request, then use F to avoid race conditions.

Within one request, since everything is sequential and single threaded, there's not risk of variables going out of sync: You know the order in which things are done and therefore can always call refresh_from_db() when you know a previous method call might have changed the database value.

Note also: Having two variables holding the same row means you'll have performed two queries to your db, which is the one thing you want to avoid at all cost. So you should think why you have this situation in the first place.

Upvotes: 1

Related Questions