Skip to content

Conversation

charettes
Copy link
Member

Trac ticket number

ticket-27222

@charettes charettes marked this pull request as ready for review March 22, 2025 04:48
@charettes
Copy link
Member Author

The unveiled failures are related to this ticket

TL;DR the documented pattern for copying model instances breaks when some fields are deferred on the original instance.

This poses a problem with this patch as it marks any field assigned a database expression at save time, db_default included, as deferred instead of leaving a dangling expression assigned (a DatabaseDefault instance in the case of db_default).

@charettes
Copy link
Member Author

This is now based on #19445

Comment on lines +1149 to +1158
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If an explicit literal value is provided for a field there is no need to return it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Except that I've written some code like this for MongodB where the id is ObjectIdAutoField: Question.objects.create(id="000000000000000000000013"). Previously, this would refresh id to the returned value, ObjectId("000000000000000000000013"). What do you think?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the same problem might happen with some form of UUID field that returns uuid.UUID instances I guess. Could you write a regression test for it and file an issue?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I imagine UUIDAutoField (ticket-32577) could reproduce it. Do you have a more generic way in mind? I could try for some minimal implementation of UUIDFIeld + django.contrib.postgres.functions.RandomUUID to create a regression test in postgres_tests but this might be unnecessarily complicated in light of the MongoDB tests.

This works as a regression test, at least on SQLite and PostgreSQL. I'm unsure if all databases will accept it.

a = AutoModel.objects.create(pk="1")
self.assertEqual(a.pk, 1)

Copy link
Member Author

@charettes charettes Sep 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works as a regression test, at least on SQLite and PostgreSQL. I'm unsure if all databases will accept it.

That's perfect, the whole notion of auto-field is problematic anyway as discussed on #18365 (as any field with a db_default and primary_key=True should be allowed as a primary key in the first place).

I'm surprised we don't already have a test that covers this use case though 🤔

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR for the regression: #19868

@felixxm
Copy link
Member

felixxm commented Aug 28, 2025

Rebased.

@felixxm felixxm force-pushed the ticket-27222 branch 2 times, most recently from 83e6e61 to 6a44639 Compare September 11, 2025 20:54
Copy link
Member

@adamchainz adamchainz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice feature!

@felixxm
Copy link
Member

felixxm commented Sep 12, 2025

@adamchainz Thanks 👍 Updated.

Copy link
Member

@pauloxnet pauloxnet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this.🤗
Now I have to update the slides of my talk 😅

@felixxm
Copy link
Member

felixxm commented Sep 13, 2025

buildbot, test on oracle.

…pdate.

This required implementing UPDATE RETURNING machinery that heavily
borrows from the INSERT one.
…save().

Removed the can_return_columns_from_insert skip gates on existing
field_defaults tests to confirm the expected number of queries are
performed and that returning field overrides are respected.
@felixxm
Copy link
Member

felixxm commented Sep 13, 2025

buildbot, test on oracle.

@felixxm
Copy link
Member

felixxm commented Sep 13, 2025

Merged in 55a0073 and 9468043.

@felixxm felixxm closed this Sep 13, 2025
@charettes charettes deleted the ticket-27222 branch September 14, 2025 20:13
@charettes
Copy link
Member Author

Thanks to everyone for the review a particularly @felixxm for seeing this through 🎉 🙇

Comment on lines +563 to +581
def test_save_expressions(self):
article = Article(pub_date=Now())
article.save()
expected_num_queries = (
0 if connection.features.can_return_columns_from_insert else 1
)
with self.assertNumQueries(expected_num_queries):
article_pub_date = article.pub_date
self.assertIsInstance(article_pub_date, datetime)
# Sleep slightly to ensure a different database level NOW().
time.sleep(0.1)
article.pub_date = Now()
article.save()
expected_num_queries = (
0 if connection.features.can_return_rows_from_update else 1
)
with self.assertNumQueries(expected_num_queries):
self.assertIsInstance(article.pub_date, datetime)
self.assertGreater(article.pub_date, article_pub_date)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's fine to keep this test here if you feel it's most appropriate (I understand the intention is to test changes in Model, not to test expressions themselves), but wanted to note that similar tests are in expressions. Here's a list of skipped test for MongoDB:

"Insert expressions aren't supported.": {
    "bulk_create.tests.BulkCreateTests.test_bulk_insert_now",
    "bulk_create.tests.BulkCreateTests.test_bulk_insert_expressions",
    "expressions.tests.BasicExpressionsTests.test_new_object_create",
    "expressions.tests.BasicExpressionsTests.test_new_object_save",
    "expressions.tests.BasicExpressionsTests.test_object_create_with_aggregate",
    "expressions.tests.BasicExpressionsTests.test_object_create_with_f_expression_in_subquery",
    # PI()
    "db_functions.math.test_round.RoundTests.test_decimal_with_precision",
    "db_functions.math.test_round.RoundTests.test_float_with_precision",
},

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants