New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixed #30186 -- Made showmigrations --list display the applied datetimes at verbosity 2+. #10997
Conversation
99ab5be
to
436b63b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any thoughts about changing plan nodes to be three elements (app, name, applied=None)
instead of using this custom tuple subclass and loosing the containment check abilities on the returned set?
django/db/migrations/recorder.py
Outdated
return {tuple(x) for x in self.migration_qs.values_list('app', 'name')} | ||
return { | ||
AppliedMigration([m.app, m.name], applied=m.applied) | ||
for m in self.migration_qs.iterator() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It don't think it's worth using iterator()
here given the small size of the result set and the fact it will be fully materialized. Also you could keep using values_list('app', 'name', 'applied')
.
class AppliedMigration(tuple):
def __init__(self, app, name, applied):
instance = tuple.__new__(cls, (app, name))
instance.applied = applied
return instance
return {AppliedMigration(x) for x in self.migration_qs.values_list('app', 'name', 'applied')
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good.
@@ -84,9 +86,15 @@ def show_list(self, connection, app_names=None): | |||
title = plan_node[1] | |||
if graph.nodes[plan_node].replaces: | |||
title += " (%s squashed migrations)" % len(graph.nodes[plan_node].replaces) | |||
# Get the applied migration instance | |||
filtered = filter(lambda m: m == plan_node, loader.applied_migrations) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was a problem before as well but I guess it should be fixed while you are around.
In the case where showmigrations
is not called with an app label (or called with multiple ones) this will incur len(app_names)
queries since each access to loader.applied_migrations
incurs one. It might be worth assigning a applied_migrations = loader.applied_migrations
variable outside of the loop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait, loader.applied_migrations
is not the same as Recorder.applied_migrations()
where the latter actually makes a DB query. loader.applied_migrations
is a property that doesn't make any DB queries, but gets set in build_graph()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh never mind then, I assumed it was the same function based on the name.
@timgraham Brought up a similar issue. I implemented this way because there are a number of places where there are comparisons to the results of There are three proposed options so far, this tuple subclass I have, Tim suggested returning the |
Thanks for the summary @tim-schilling!
I like this option a lot. It preserves the current the |
566c6c0
to
c8ec2ea
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @tim-schilling.
This looks super. Thanks.
I just left a few minor comments. I'm not insistent on those...
Can you rebase and squash to a single commit?
I'm going to mark this RFC. Good stuff!
django/db/migrations/loader.py
Outdated
migration[0], migration[1], parent[0], parent[1], | ||
connection.alias, | ||
migration_key[0], migration_key[1], parent[0], | ||
parent[1], connection.alias, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could go on one line I think.
(Would be less than 120 chars and splitting parent[0]
from parent[1]
is a little weird.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I thought the limit was 80 characters. I was wondering why there were so many offending lines.
django/db/migrations/recorder.py
Outdated
return {tuple(x) for x in self.migration_qs.values_list('app', 'name')} | ||
return { | ||
(migration.app, migration.name): migration | ||
for migration in self.migration_qs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Single line?
django/db/migrations/recorder.py
Outdated
@@ -69,13 +69,16 @@ def ensure_schema(self): | |||
raise MigrationSchemaMissing("Unable to create the django_migrations table (%s)" % exc) | |||
|
|||
def applied_migrations(self): | |||
"""Return a set of (app, name) of applied migrations.""" | |||
"""Return a dict of (app, name), Migration of applied migrations.""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe "Return a dict of (app, name) to Migration instances of applied migrations."
(Just not sure the comma reads...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Works for me.
docs/releases/3.0.txt
Outdated
@@ -259,7 +262,7 @@ to remove usage of these features. | |||
* Support for the ``context`` argument of ``Field.from_db_value()`` and | |||
``Expression.convert_value()`` is removed. | |||
|
|||
* The ``field_name`` keyword argument of ``QuerySet.earliest()` and | |||
* The ``field_name`` keyword argument of ``QuerySet.earliest()`` and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Merged this as 38c3f7e. Thanks!
c8ec2ea
to
e46aa5e
Compare
Implemented your suggestions, squashed and rebased. Thanks for the review! |
Could you send the refactoring code/test changes as a separate PR so that's not tied up with the feature change? Then we can rebase this and it'll look less invasive. |
@timgraham I'm confused. I should have two PRs? One with the changes to django (with failing tests) and then the other with the tests for non-existing functionality that fail? Or would the second include the functionality changes? |
What I meant as "the refactoring" is all the changes for changing the return type of |
That was refactoring in order to make the feature possible. I can't separate them. |
The refactoring can precede the feature, no? |
Yes. Sorry, I (for some reason) assumed the order was the opposite. If that's what works best, I can break it up that way. What do I title the refactoring PR? |
Refs #30186 -- Changed MigrationRecorder.applied_migrations() to return a dict. |
Thanks for the help. |
e46aa5e
to
f2369ec
Compare
Did you want me to rebase this off of master without the commit from #11058? |
ef4f352
to
c78b848
Compare
…mes at verbosity 2+.
When verbosity is 2 or greater and listing migrations with
showmigrations, include the applied datetime in the output.