0

Consider the following Django model:

class Outlet(models.Model):
    a = models.CharField(max_length=253, primary_key=True, db_index=True)
    def _split(self, idx):
        if not self.a:
            return None
        return self.a.split(".")[idx]
    @property
    def b(self):
        return self._split(0)
    @property
    def c(self):
        return self._split(1)

Couple with this class registered in admin:

@admin.register(Outlet)
class OutletAdmin(admin.ModelAdmin):
    fields = ("a", "b", "c")
    readonly_fields = ("b", "c")

Start with an empty DB:

enter image description here

Add one instance in the admin UI:

enter image description here

enter image description here

Fine so far. Now go to modify that instance:

enter image description here

enter image description here

Huh? What just happened? Django just performed an INSERT when it should reliably be expected to perform an UPDATE.

Directly from How Django knows to UPDATE vs. INSERT:

You may have noticed Django database objects use the same save() method for creating and changing objects. Django abstracts the need to use INSERT or UPDATE SQL statements. Specifically, when you call save(), Django follows this algorithm:

  • If the object’s primary key attribute is set to a value that evaluates to True (i.e., a value other than None or the empty string), Django executes an UPDATE.
  • If the object’s primary key attribute is not set or if the UPDATE didn’t update anything, Django executes an INSERT.

Now, this question will tell me that this is because a is a primary key. Firstly, I don't see that mentioned anywhere in the Django docs. Secondly, I'm not able to remove the primary_key attribute from a.

I'm more interested in knowing why this is the case, what causes it internally with Django, and where it is documented (if anywhere)? Are there other undocumented conditions wherein an INSERT gets done when you would expect an UPDATE to happen?

Brad Solomon
  • 38,521
  • 31
  • 149
  • 235

1 Answers1

4

https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.Field.primary_key

The primary key field is read-only. If you change the value of the primary key on an existing object and then save it, a new object will be created alongside the old one.

Işık Kaplan
  • 2,815
  • 2
  • 13
  • 28