Estoy trabajando para actualizar mi proyecto de Django 2 a Django 3, he leído sus notas de lanzamiento de Django 3 y hay un punto en el que realmente no entiendo qué impacto tendrá en mi proyecto actual. Aquí dicen:
Según tengo entendido, si intentamos llamar a Model.save() , siempre crearía un nuevo registro en lugar de actualizar si el modelo es un registro existente. Por ejemplo:
car = Car.objects.first() car.name = 'Honda' car.save() # does it INSERT or UPDATE? I suspect it is an "INSERT" statement as their explanation and "UPDATE" statement in Django 2.He experimentado y sigue siendo el mismo comportamiento que Django 2, no estoy seguro de lo que significan.
In [5]: u = User.objects.first() (0.001) SELECT "accounts_user"."id", "accounts_user"."password", "accounts_user"."last_login", "accounts_user"."is_superuser", "accounts_user"."username", "accounts_user"."first_name", "accounts_user"."last_name", "accounts_user"."is_staff", "accounts_user"."is_active", "accounts_user"."date_joined", "accounts_user"."email", "accounts_user"."avatar", "accounts_user"."last_location"::bytea, "accounts_user"."uuid", "accounts_user"."country", "accounts_user"."city", "accounts_user"."phone" FROM "accounts_user" ORDER BY "accounts_user"."id" ASC LIMIT 1; args=() In [6]: u.save() (0.006) UPDATE "accounts_user" SET "password" = 'pbkdf2_sha256_sha512$180000$FbFcNuPMrOZ6$GwIftEo+7+OpsORwn99lycye46aJn/aJNAtc50N478Y=', "last_login" = NULL, "is_superuser" = false, "username" = 'email0@mail.com', "first_name" = 'Noah', "last_name" = 'Spencer', "is_staff" = false, "is_active" = true, "date_joined" = '2020-05-12T07:06:20.605650+00:00'::timestamptz, "email" = 'email0@mail.com', "avatar" = 'account/user_avatar/example_HseJquC.jpg', "last_location" = NULL, "uuid" = 'f6992866-e476-409e-9f1b-098afadce5b7'::uuid, "country" = NULL, "city" = NULL, "phone" = NULL WHERE "accounts_user"."id" = 1; args=('pbkdf2_sha256_sha512$180000$FbFcNuPMrOZ6$GwIftEo+7+OpsORwn99lycye46aJn/aJNAtc50N478Y=', False, 'email0@mail.com', 'Noah', 'Spencer', False, True, datetime.datetime(2020, 5, 12, 7, 6, 20, 605650, tzinfo=<UTC>), 'email0@mail.com', 'account/user_avatar/example_HseJquC.jpg', UUID('f6992866-e476-409e-9f1b-098afadce5b7'), 1)Actualizar:
In [38]: u1 = User.objects.first() (0.000) SELECT "accounts_user"."id", "accounts_user"."password", "accounts_user"."last_login", "accounts_user"."is_superuser", "accounts_user"."username", "accounts_user"."first_name", "accounts_user"."last_name", "accounts_user"."is_staff", "accounts_user"."is_active", "accounts_user"."date_joined", "accounts_user"."email", "accounts_user"."avatar", "accounts_user"."last_location"::bytea, "accounts_user"."uuid", "accounts_user"."country", "accounts_user"."city", "accounts_user"."phone" FROM "accounts_user" ORDER BY "accounts_user"."id" ASC LIMIT 1; args=() In [39]: u1.pk Out[39]: 1 In [40]: u2 = User(pk=1) In [41]: u2.email = 'email@email.com' In [42]: u2.save() (0.006) UPDATE "accounts_user" SET "password" = '', "last_login" = NULL, "is_superuser" = false, "username" = 'email@email.com', "first_name" = '', "last_name" = '', "is_staff" = false, "is_active" = true, "date_joined" = '2020-05-13T01:20:47.718449+00:00'::timestamptz, "email" = 'email@email.com', "avatar" = '', "last_location" = NULL, "uuid" = '89ba0924-03a7-44d2-bc6d-5fd2dcb0de0b'::uuid, "country" = NULL, "city" = NULL, "phone" = NULL WHERE "accounts_user"."id" = 1; args=('', False, 'email@email.com', '', '', False, True, datetime.datetime(2020, 5, 13, 1, 20, 47, 718449, tzinfo=<UTC>), 'email@email.com', '', UUID('89ba0924-03a7-44d2-bc6d-5fd2dcb0de0b'), 1)Debe leerse con atención
ya no intenta encontrar una fila al guardar una nueva instancia de modelo y se proporciona un valor predeterminado para la clave principal ,
Entonces, en caso de que vaya a crear un nuevo objeto con una identificación que ya está en la base de datos , ahora fallará en lugar de tener un comportamiento similar a update_or_create, ya que ahora realizará la INSERT en lugar de UPDATE
Considere este ejemplo. Supongamos que tenemos un modelo simple como
CONSTANT = 10 def foo_pk_default(): return CONSTANT class Foo(models.Model): id = models.IntegerField(primary_key=True, default=foo_pk_default ) name = models.CharField(max_length=10)Lo principal que he hecho en este ejemplo es que configuré una función invocable predeterminada para Claves primarias . Además, devolví solo un valor único de la función, por el bien de la demostración.
## Django 2.2 In [5]: foo_instance_1 = Foo(name='foo_name_1') In [6]: foo_instance_1.save() In [7]: print(foo_instance_1.__dict__) {'_state': , 'id': 10, 'name': 'foo_name_1'} In [8]: foo_instance_2 = Foo(name='foo_name_2') In [9]: foo_instance_2.save() In [10]: print(foo_instance_2.__dict__) {'_state': , 'id': 10, 'name': 'foo_name_2'} ## Django 3.X In [6]: foo_instance_1 = Foo(name='foo_name_1') In [7]: foo_instance_1.save() In [8]: print(foo_instance_1.__dict__) {'_state': , 'id': 10, 'name': 'foo_name_1'} In [9]: foo_instance_2 = Foo(name='foo_name_2') In [10]: foo_instance_2.save() # Raised "IntegrityError: UNIQUE constraint failed: music_foo.id" En Django<3.0 , Model.save() realizará una operación de actualización o inserción si hay un valor PK asociado con la instancia del modelo, mientras que en Django>=3.0 , solo realizará una operación de inserción, por lo tanto, la UNIQUE constraint failed excepción.
Dado que este cambio de Django solo es aplicable cuando se crea una nueva instancia y, por lo general, no establecemos ninguna función de valor predeterminado para las claves principales.
En resumen, este cambio no generará ningún problema a menos que proporcione un valor predeterminado durante la creación de la instancia del modelo.