-
-
Notifications
You must be signed in to change notification settings - Fork 33.1k
Fixed #29049 -- Added slicing notation to F expressions. #11208
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
Conversation
Hey @adamchainz. When you have capacity, can I ask you to look at this since you inputted on the original PR. (Thanks!) |
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.
Looking good, I have some comments on the general direction though
docs/ref/models/expressions.txt
Outdated
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.
I'd suggest:
However, step-argument is not supported in slicing.
changed to:
The step-argument is not supported. For example::
Also a ..versionadded
annotation is needed
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.
Changed this to your suggestion. Added a versionadded, although I'm not sure which line to put it on?
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.
Looks great! ready for final review.
F expressions on string-based fields and arrays can now use standard python slicing-notation. Added a new class SlicableF that handles identification of slicable fields. Step-argument is not supported. Added unit-tests and documentation, with an entry in release-notes.
Used a variable 'field_type' to avoid multiple lookups.
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.
Some style guides. django.contrib.postgres
is also used in the test cases 👍
* ``connection.queries`` now shows ``COPY … TO`` statements on PostgreSQL. | ||
|
||
* :class:`~django.db.models.FilePathField` now accepts a callable ``path``. | ||
* Slicing notation added to F expressions over the following field types: |
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.
Just nitpicking, but please add a blank line.
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.
Please also move this to 3.1.txt
.
normal Python assignment of value to an instance attribute, in fact it's an SQL | ||
construct describing an operation on the database. | ||
|
||
For fields that are string-expressions (or ``django.contrib.postgres.fields.ArrayField``), you can use the standard slicing |
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.
Wrap at 79 chars.
def slice_expression(self, expression, start, length): | ||
if length is None: | ||
return SliceTransform(start, 2147483647, expression) | ||
|
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 this blank line is not needed.
first_instance.field = F('field')[:2] | ||
first_instance.save() | ||
first_instance.refresh_from_db() | ||
self.assertSequenceEqual( |
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.
You could collapse this to one line.
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.
@nip3o Thanks for this patch 👍 I left comments.
|
||
def slice_expression(self, expression, start, length): | ||
"""Return a slice of an expression, or None if field is not sliceable.""" | ||
return None |
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.
Default implementation should raise NotSupportedError
, IMO, e.g.
raise NotSupportedError('This field does not support slicing.')
also test for this error is required.
companies = Company.objects.annotate(first_three=F('name')[:3]) | ||
self.assertEqual(companies[0].first_three, "Exa") | ||
self.assertEqual(companies[1].first_three, "Foo") | ||
self.assertEqual(companies[2].first_three, "Tes") |
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.
You can use assertSequenceEqual()
.
third_instance.refresh_from_db() | ||
self.assertSequenceEqual( | ||
third_instance.field, [2, 3] | ||
) |
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.
You can use subTest()
.
Closing due to inactivity. |
Supersedes PRs django#9670, django#11208, django#14731, and django#16310. This adds the following changes over the previous PRs: - Used `None` to omit `end` in `ArrayField.slice_expression()` - Handled nested slicing, e.g. `F("name")[1:][:5]` - Simplified `.resolve_expression()` - Renamed `SliceableF` to `Sliced` - Clarified some inline comments Co-authored-by: Priyansh Saxena <[email protected]> Co-authored-by: Niclas Olofsson <[email protected]> Co-authored-by: David Smith <[email protected]> Co-authored-by: Mariusz Felisiak <[email protected]> Co-authored-by: Abhinav Yadav <[email protected]>
Fixed issue https://code.djangoproject.com/ticket/29049
This is a continuation on #9670