Add {% querystring %} template tag to add, remove, and update querystring parameters
Review Request #9712 — Created March 1, 2018 and submitted
Previously, it was only possible to update a single query parameter with
{% querystring_with %}
. However, in the name of future proofing, it
became necessary to make a new template tag{% querystring %}
that can take an arbitrary number of key-value pairs now with different
modes in the form of:
{% querystring “mode” "key1=value1" "key2=value2" %}
The three different modes are:
“remove” - Will remove keys from the query string.
“append” - Will append values for its given key without overwriting.
“update” - Will add to or replace part of a query string.
Ran unit tests.
Description | From | Last Updated |
---|---|---|
You have several lines that contain whitespace. You can set up Sublime to trim this on save via Preferences -> … |
brennie | |
Please wrap your description at 72 lines. You can install AutoWrap (Cmd+Shift+P, PCI (for package control install), AutoWrap) and set … |
brennie | |
Your description mentions RB but this is a change to Djblets. Your future change to RB should refer to those … |
brennie | |
Your summary should be in the imperitive mood, i.e., it should read like you are giving a command or order. … |
brennie | |
Your summary should be in the imperitive mood, i.e., it should read like a command. For example: Update querystring_with to … |
brennie | |
Can you add unit tests for {% querystring_with_fragments "foo" %} |
brennie | |
Can you add unit tests for {% querystring_with_fragments "foo=bar=baz" %} |
brennie | |
Can you add unit tests for Can you add unit tests for {% querystring_with_fragments "foo=" %} |
brennie | |
Can you add unit tests for {% querystring_with_fragments "foo bar=baz qux" %} |
brennie | |
Can you add unit tests for {% querystring_with_fragments "=foo" %} |
brennie | |
Can you add unit tests for {% querystring_with_fragments "a=1" "a=2" "a=3 %}? The result should be ?a=1&a=2&a=3. |
brennie | |
Can you add unit tests for {% querystring_with_fragments "a=b=c=d" "e=f=g=h" %} |
brennie | |
Your summary should be in the imperitive mood (i.e., it should read like a command or order). How about: Add … |
brennie | |
Can you add unit tests with unicode keys and values with e.g. han characters? |
brennie | |
Description has a grammar-o: "There are three different modes are" |
brennie | |
Can you add a test for {% querystring "remove" "foo=1" "foo=2" %} for a querystring ?foo=1&foo=2&foo=3? |
brennie | |
W291 trailing whitespace |
reviewbot | |
This documentation needs to be updated to indicate that the function can update multiple query parameters. |
brennie | |
This function no longer takes these aruments. You will want to update this section. |
brennie | |
I did some talking with Christian and I'm not convinced this is the best way to handle this. Instead, we … |
brennie | |
E226 missing whitespace around arithmetic operator |
reviewbot | |
Since attr and value are used immediately, we can move them inline, like so: query[args[i].encode('utf-8')] = args[i + 1].encode('utf-8') |
brennie | |
E226 missing whitespace around arithmetic operator |
reviewbot | |
W293 blank line contains whitespace |
reviewbot | |
Undo this change. |
brennie | |
W293 blank line contains whitespace |
reviewbot | |
W293 blank line contains whitespace |
reviewbot | |
tmp isn't a very descriptive variable name. How about render_result? |
brennie | |
E303 too many blank lines (2) |
reviewbot | |
Can you add a trailing comma? |
brennie | |
E126 continuation line over-indented for hanging indent |
reviewbot | |
This is only used once so it could be moved inline. |
brennie | |
t_dict isn't a very expressive variable name. How about expected_result? However, it can be moved inline (see next comment) |
brennie | |
I think it would be fine to do: self.assertEqual( parse_qs(render_result[1:]), { 'bar': ['baz'], 'foo': ['bar'], }) |
brennie | |
E303 too many blank lines (2) |
reviewbot | |
W293 blank line contains whitespace |
reviewbot | |
Can you add a trailing comma? This should also be dedented so that it looks like: render_result = t.render(Context({ 'request': … |
brennie | |
See comments on previous function about moving things inline. |
brennie | |
W391 blank line at end of file |
reviewbot | |
E501 line too long (91 > 79 characters) |
reviewbot | |
E501 line too long (91 > 79 characters) |
reviewbot | |
E501 line too long (91 > 79 characters) |
reviewbot | |
We are going to want to make this into a new template tag. The reason being is that an old … |
brennie | |
Docstring summary should fit on a single line. |
brennie | |
Missing context (which is a django.template.Context) |
brennie | |
*args (tuple) |
brennie | |
Documentation should always be sentence-case. How about: Multiple querystring fragments (e.g., "foo=1") that will be used to update the initial … |
brennie | |
These should no longer be here. |
brennie | |
These tests would be easier to read if the initial state was: { 'foo': 'foo', 'bar': 'bar', 'baz': 'baz', 'qux': … |
brennie | |
Typo: `context. |
brennie | |
While technically correct, how about: The Django template rendering context. It is what we use elsewhere. |
brennie | |
Blank line between these. |
brennie | |
Undo this indentation. |
brennie | |
""" on next line. |
brennie | |
context |
brennie | |
See comment on other templatetag about this. |
brennie | |
The description should not be indented, i.e. unicode: The new URL ... |
brennie | |
Wrong templatetag :) |
brennie | |
This should use the parse_qs method becuase dict iteration order is not guaranteed. |
brennie | |
Mind doing bar: "bar" just to keep in line with other examples? |
brennie | |
Mind ordering this foo then bar like above? |
brennie | |
E501 line too long (88 > 79 characters) |
reviewbot | |
E501 line too long (90 > 79 characters) |
reviewbot | |
E501 line too long (88 > 79 characters) |
reviewbot | |
E128 continuation line under-indented for visual indent |
reviewbot | |
E501 line too long (81 > 79 characters) |
reviewbot | |
E303 too many blank lines (2) |
reviewbot | |
F401 'django.utils.six.moves.urllib.parse.parse_qs' imported but unused |
reviewbot | |
E501 line too long (85 > 79 characters) |
reviewbot | |
E231 missing whitespace after ',' |
reviewbot | |
E501 line too long (83 > 79 characters) |
reviewbot | |
E122 continuation line missing indentation or outdented |
reviewbot | |
E122 continuation line missing indentation or outdented |
reviewbot | |
E122 continuation line missing indentation or outdented |
reviewbot | |
E122 continuation line missing indentation or outdented |
reviewbot | |
E122 continuation line missing indentation or outdented |
reviewbot | |
E122 continuation line missing indentation or outdented |
reviewbot | |
E122 continuation line missing indentation or outdented |
reviewbot | |
E128 continuation line under-indented for visual indent |
reviewbot | |
E122 continuation line missing indentation or outdented |
reviewbot | |
E122 continuation line missing indentation or outdented |
reviewbot | |
E122 continuation line missing indentation or outdented |
reviewbot | |
E122 continuation line missing indentation or outdented |
reviewbot | |
E122 continuation line missing indentation or outdented |
reviewbot | |
E122 continuation line missing indentation or outdented |
reviewbot | |
E122 continuation line missing indentation or outdented |
reviewbot | |
E122 continuation line missing indentation or outdented |
reviewbot | |
E303 too many blank lines (2) |
reviewbot | |
E127 continuation line over-indented for visual indent |
reviewbot | |
W391 blank line at end of file |
reviewbot | |
E303 too many blank lines (2) |
reviewbot | |
E501 line too long (85 > 79 characters) |
reviewbot | |
E501 line too long (83 > 79 characters) |
reviewbot | |
six.moves before six.moves.urllib |
brennie | |
""" on next line. |
brennie | |
Undo |
brennie | |
This should be a header of Args and describe what it is in addition to its values. E.g. Args: mode … |
brennie | |
This just returns the querystring, not the URL. |
brennie | |
The < should line up with the c in code-block. |
brennie | |
Instead of having this highly nested, we can pull things out into temporaries to make it more readable. How about: … |
brennie | |
Can we add support to remove specific key-vaue pairs, in addition to removing the entire set? e.g. "remove" "a=4" would … |
brennie | |
How about: query.pop(arg.encode('utf-8'), None) This does not require the try/except. |
brennie | |
You can use the same approach I outlined above to make this more readable. |
brennie | |
The tag is no longer called QuerystringWithFragments |
brennie | |
The < in <a should be aligned with the c in the code-block above. |
brennie | |
This message is no longer correct. It should include the update mode. |
brennie | |
Can we format like the following example? This makes it clear it is a string literal and renders as a … |
brennie | |
This should be first in the list of args. This is missing its type. |
brennie | |
These all need to be de-dented one space so that the first character lines up with the c in code-block. … |
brennie | |
No blank line here. |
brennie | |
The implementation of QueryDict.urlencode actually forces the text to bytes, so we don't need to encode the attrs or values … |
brennie | |
No blank line here. |
brennie | |
No blank line here. |
brennie | |
No blank line here. |
brennie | |
This is no longer required. |
brennie | |
Six has moves support for this: from django.utils.six.moves.html_parser import HTMLParser |
brennie | |
No blank line after function docstrings. Here and below. |
brennie | |
This one doesn't assert that rendered_result.startswith('?'). |
brennie | |
""" on next line. "args get" fits on previous line. |
brennie | |
This blank line is unnecessary here and in all tests below. |
brennie | |
No period at the end of test docstrings (because they print out as <DOCSTRING> ... OK). Here and below. |
brennie | |
This fits on a single line. You seem to be wrapping your docstrings at ~70 rather than 79. Please correct … |
brennie | |
E501 line too long (116 > 79 characters) |
reviewbot | |
Undo this change, please. |
brennie | |
Undo this change, please. |
brennie | |
This is not indented a multiple of four. (It is missing one space.) |
brennie | |
Should not be indented relative to prior line. |
brennie | |
Remove this blank line |
brennie | |
This is setting the same list in a loopp len(parsed.getlist(attr)) times. This also doesn't need to encode values. What this … |
brennie | |
Remove this line. |
brennie | |
Blank line between these. |
brennie | |
Remove this line. |
brennie | |
I think this will miss some cases, e.g. {% querystring "remove" "x&y=1&z=" %}. Now, this is an edge case, but … |
brennie | |
Again, no need to encode. |
brennie | |
We only need to do getlist once since we are modifying the same list in each iteration of the loop |
brennie | |
Remove this line. |
brennie | |
Since we are appending every single entry in args into query, we can simply do: for arg in args: query.update(QueryDict(arg)) … |
brennie | |
Again, no need to encode. |
brennie | |
Again, no need to encode. |
brennie | |
Can you surround "foo=1" with double backticks, e.g. ``"foo=1"`` |
brennie | |
Can you fix the formatting here? These can both go on the same line. |
brennie | |
The second for loop needs to be nested in the first, otherwise only the last element in args will be … |
brennie | |
This needs to be indented to be aligned with the if. It is currently always executing because there is no … |
brennie | |
This will actually be a django.template.RequestContext. |
chipx86 | |
This should not be indented. |
chipx86 | |
No blank line here. |
chipx86 | |
The key=value should be in quotes, right? For "mode", is the equivalent always "update"? If so, we can say that … |
chipx86 | |
Too long for the line. Must fit in 79 characters. It's also missing an ending period. |
chipx86 | |
See the type above. |
chipx86 | |
This can be on the same line. |
chipx86 | |
I think you can just do: query = context['request'].GET.copy() The copy will be mutable. |
chipx86 | |
This is going to set the list of values for every value in the list of values. You should be … |
chipx86 | |
This doesn't seem right. We're overriding to_remove every time, meaning we're only ever getting the list for the last attribute. … |
chipx86 | |
This should raise a TemplateSyntaxError. |
chipx86 | |
This is in the wrong import group. |
chipx86 | |
The trailing period should remain. You only remove this for docstrings for unit tests themselves (as they're outputted to the … |
chipx86 | |
The tests in this module should be updated to check for warnings as well. Search the codebase for catch_warnings for … |
chipx86 | |
Same here. |
chipx86 | |
Needs a trailing period. |
chipx86 | |
This should be removed. |
chipx86 | |
Last entries in a dictionary should always have a trailing comma. |
chipx86 | |
I'd recommend just setting self.request in setUp() (not setUpClass(), since it'll be modified) and referencing it in all the tests. |
chipx86 | |
Trailing comma. |
chipx86 | |
""" on the next line. "overridden". |
chipx86 | |
Trailing comma. |
chipx86 | |
Best to explicitly check the resulting value, rather than introducing another parsing/checking step. That just leads to problems, as more … |
chipx86 | |
"overridden" I'd also add "that" before "get". |
chipx86 | |
You can start the template on the first line, like: t = Template('{% load djblets_utils %}' '{% querystring .... %}') … |
chipx86 | |
Trailing comma. |
chipx86 | |
Trailing comma. |
chipx86 | |
Trailing comma. |
chipx86 | |
Trailing comma. |
chipx86 | |
""" on the next line. "overridden" |
chipx86 | |
Test docstrings that go over one line need to have """ on the following line. Same for all other tests … |
brennie | |
Trailing comma. |
chipx86 | |
""" on the next line. No trailing period. |
chipx86 | |
This should be removed. |
chipx86 | |
"existing" |
chipx86 | |
""" on the next line. |
chipx86 | |
Trailing comma. |
chipx86 | |
""" on the next line. |
chipx86 | |
Trailing comma. |
chipx86 | |
""" on the next line. "a key fragments" doesn't make sense. Maybe just "a key fragment?" What's a key fragment? |
chipx86 | |
Trailing comma. |
chipx86 | |
""" on the next line. |
chipx86 | |
Trailing comma. |
chipx86 | |
This should be removed. |
chipx86 | |
""" on the next line. |
chipx86 | |
Trailing comma. |
chipx86 | |
"non-existing" """ on the next line. |
chipx86 | |
Trailing comma. |
chipx86 | |
""" on the next line. |
chipx86 | |
Trailing comma. |
chipx86 | |
""" on the next line. |
chipx86 | |
Trailing comma. |
chipx86 | |
""" on the next line. |
chipx86 | |
Trailing comma. |
chipx86 | |
""" on the next line. |
chipx86 | |
Trailing comma. |
chipx86 | |
""" on the next line. |
chipx86 | |
Trailing comma. |
chipx86 | |
The } should line up with the % and the D in DeprecationWarning. |
brennie | |
Can you specify that this comes from this template tag, e.g. raise TemplateSyntaxError('Invalid mode for {%% querystring %%}: %s' % … |
brennie | |
Single quotes here. |
brennie |
-
Thanks for the patch Mandeep!
I've left some mostly-stylistic comments here as it looks pretty good.
However, I think it might be better to take a different approach (which I outline in one of the comments).
As you fix issues locally, make sure to mark them as fixed here and then, once you've fixed them all, commit and re-post (
rbt post -u
).Thanks again!
-
You have several lines that contain whitespace. You can set up Sublime to trim this on save via
Preferences -> Settings -> User and adding the following:
"trim_trailing_white_space_on_save": true
and
"ensure_newline_at_eof_on_save": true
-
Please wrap your description at 72 lines.
You can install AutoWrap (Cmd+Shift+P, PCI (for package control install), AutoWrap) and set the following settings for the Git Commit syntax
{ "rulers": [52, 72], "auto_wrap": true, "auto_wrap_width": 72 }
(To edit the syntax setting for a specific filetype you can open a new file and do Cmd+Shift+P, and type syntax git commit. Then go to Preferences -> Settings -> Syntax Specific and add those settings.)
-
Your description mentions RB but this is a change to Djblets. Your future change to RB should refer to those changes since Djblets has no notion review requests, etc.
How about:
Previously, it was only possible to update a single query parameter with `{% querystring_with %}`. However, it is frequently the case that it would be handy to update the querystring from within the template rather than having to enumerate all possible cases in the view. Now `{% querystring_with %}` can take an arbitrary number of key-value pairs in the form of: ```html+django {% querystring_with "key1" "value1" "key2" "value2" %} ```
Our description and testing done fields support markdown
-
Your summary should be in the imperitive mood, i.e., it should read like you are giving a command or order. How about:
Update querystring_with to take an arbitrary number of key-value pairs
-
This documentation needs to be updated to indicate that the function can update multiple query parameters.
-
-
I did some talking with Christian and I'm not convinced this is the best way to handle this. Instead, we may want to forgo the simple parsing that
register.simple_tag
gives us and do our own parsing so that we could do:{% querystring_with sorted='1' page='2' foo-bar='baz' %}
I can work with you to write a templatetag parser that understands this syntax.
-
Since
attr
andvalue
are used immediately, we can move them inline, like so:query[args[i].encode('utf-8')] = args[i + 1].encode('utf-8')
-
-
-
-
-
t_dict
isn't a very expressive variable name.How about
expected_result
?However, it can be moved inline (see next comment)
-
I think it would be fine to do:
self.assertEqual( parse_qs(render_result[1:]), { 'bar': ['baz'], 'foo': ['bar'], })
-
Can you add a trailing comma?
This should also be dedented so that it looks like:
render_result = t.render(Context({ 'request': request, })
-
- Commit:
-
c05d8ff2e0016e92754f72f36d1353367dcad645f9b54b18e0144fded8557f4b822b8b0510dd3405
Checks run (2 succeeded)
-
-
Your summary should be in the imperitive mood, i.e., it should read like a command. For example:
Update querystring_with to support an arbitrary number of attributes and values
-
-
-
-
Documentation should always be sentence-case.
How about:
Multiple querystring fragments (e.g., "foo=1") that will be used to update the initial querystring.
-
-
These tests would be easier to read if the initial state was:
{ 'foo': 'foo', 'bar': 'bar', 'baz': 'baz', 'qux': 'qux', }
and the templatetag changed them to something else.
-
-
We are going to want to make this into a new template tag.
The reason being is that an old usage of
{% querystring_with "foo" "bar" %}
which used to do?foo=bar
now does?foo&bar
(and both are correct usages).So we will want this to do
warning.warn("...", DeprecationWarning)
with instructions to use the new template tag (lets call itquerystring_with_fragments
).
- Description:
-
~ Fix the issue of RB not updating "page" URL attribute when clicking "show closed". The issue arised while on the last page of "review request" list and switching to "hide closed". The URL not changing from "show-closed=1" to "show-closed=0" with same page number resulting in a ERROR 404.
~ Previously, it was only possible to update a single query parameter with
+ {% querystring_with %}
. However, it is frequently the case that it+ would be handy to update the querystring from within the template rather + than having to enumerate all possible cases in the view. Now + {% querystring_with %}
can take an arbitrary number of key-value pairs+ in the form of: ~ To fix this issue, it was required to change how the funciton querystring_with behaved. The funciton now takes in an arbitrary number of arguments in order to incorperate the page number that can be set in the templatetags. The user will now automatically go to the specified page number if clicked on "hide closed" to "show closed".
~ + + {% querystring_with "key1=value1" "key2=value2" %}
+
- Summary:
-
Update querystring_with to support an arbitrary number of attributes and valuesAdded a new template tag querystring_with_fragments to support an arbitrary number of attributes and values
- Description:
-
Previously, it was only possible to update a single query parameter with
{% querystring_with %}
. However, it is frequently the case that itwould be handy to update the querystring from within the template rather than having to enumerate all possible cases in the view. Now ~ {% querystring_with %}
can take an arbitrary number of key-value pairs~ in the form of: ~ {% querystring_with_fragments %} can take an arbitrary number of ~ key-value pairs in the form of: ~ {% querystring_with "key1=value1" "key2=value2" %}
~ {% querystring_with "key1=value1" "key2=value2" %}
- - Commit:
-
f9b54b18e0144fded8557f4b822b8b0510dd3405f3e2f4d9295a62b17999fece75318188c3ea2bcb
Checks run (2 succeeded)
- Commit:
-
f3e2f4d9295a62b17999fece75318188c3ea2bcb5887d815320d43e69fc74815b6f405d2df9c0006
Checks run (2 succeeded)
- Summary:
-
Added a new template tag querystring_with_fragments to support an arbitrary number of attributes and valuesUpdated template tag querystring_with_fragments to support "modes"
- Description:
-
Previously, it was only possible to update a single query parameter with
{% querystring_with %}
. However, it is frequently the case that itwould be handy to update the querystring from within the template rather than having to enumerate all possible cases in the view. Now {% querystring_with_fragments %} can take an arbitrary number of ~ key-value pairs in the form of: ~ key-value pairs in the form of now with different modes: ~ {% querystring_with "key1=value1" "key2=value2" %}
~ {% querystring_with “mode” "key1=value1" "key2=value2" %}
+ + There are three different modes are:
+ “remove” - Will remove keys from the query string. + “append” - Will append values for its given key without overwriting. + “update” - Will add to or replace part of a query string. - Testing Done:
-
~ Ran unit tests
~ Ran unit tests.
- Commit:
-
5887d815320d43e69fc74815b6f405d2df9c0006a8a77edf85e9aacc716ca899e9ebd728852cdabd
Checks run (1 failed, 1 succeeded)
flake8
- Summary:
-
Updated template tag querystring_with_fragments to support "modes"Updated template tag querystring to support "modes"
- Description:
-
Previously, it was only possible to update a single query parameter with
~ {% querystring_with %}
. However, it is frequently the case that it~ would be handy to update the querystring from within the template rather ~ than having to enumerate all possible cases in the view. Now ~ {% querystring_with_fragments %} can take an arbitrary number of ~ {% querystring_with %}
. However, in the name of future proofing, it~ became necessary to make a new template tag {% querystring %}
~ that can take an arbitrary number of key-value pairs now with different ~ modes in the form of: - key-value pairs in the form of now with different modes: ~ ~ {% querystring “mode” "key1=value1" "key2=value2" %}
- - {% querystring_with “mode” "key1=value1" "key2=value2" %}
There are three different modes are:
“remove” - Will remove keys from the query string. “append” - Will append values for its given key without overwriting. “update” - Will add to or replace part of a query string.
- Commit:
-
dcbbc35d43ba1c1736f2c8ac9efb054b5119b7645b2bb7a89d7675b6a74ed02e3b886eb9c6088839
Checks run (2 succeeded)
-
-
Your summary should be in the imperitive mood (i.e., it should read like a command or order).
How about:
Add {% querystring %} template tag to add, remove, and update querystring parameters
-
-
-
-
-
This should be a header of
Args
and describe what it is in addition to its values. E.g.Args: mode (unicode): How the querystring will be modified. This should be one of the following values: ``"update"``: Replace the values for the specified key(s) in the query string. ``"append"``: Add new values for the specified key(s) to the query string. ``"remove"``: Remove the specified key(s) from the query string. If no value is provided, all instances of the key will be removed.
-
-
-
Instead of having this highly nested, we can pull things out into temporaries to make it more readable.
How about:
for arg in args: parsed = QueryDict(arg) for key in part: key = key.encode('utf-8') values = [ value.encode('utf-8') for value in sparsed.getlist(key) ] query.setlist(key, value)
-
Can we add support to remove specific key-vaue pairs, in addition to removing the entire set?
e.g.
"remove" "a=4"
would remove "a=4" from?a=1&a=2&a=3&a=4
leavinga=1&a=2&a=3
. -
-
-
- Commit:
-
5b2bb7a89d7675b6a74ed02e3b886eb9c6088839bc0f79dcfb6e715c1efc673e636e3d4b4cdbeb83
Checks run (2 succeeded)
-
Some minor style nitpicks. Otherwise this looks good to me.
-
-
-
Can we format like the following example? This makes it clear it is a string literal and renders as a
<code>
element in the docs.``'update'``: .... ``'append'``: .... ``'remove'``: ....
-
-
These all need to be de-dented one space so that the first character lines up with the
c
incode-block
.reStructuredText code blocks are only indented three spaces instead of the usual four that we use.
You may want to enable "show indents" in ST3 (View->Indentation).
-
-
The implementation of
QueryDict.urlencode
actually forces the text to bytes, so we don't need to encode the attrs or values here or below.See: implementation
-
-
-
-
-
-
-
-
-
-
No period at the end of test docstrings (because they print out as
<DOCSTRING> ... OK
). Here and below. -
This fits on a single line.
You seem to be wrapping your docstrings at ~70 rather than 79. Please correct this here and below.
- Commit:
-
b4f86bfa7e642d94dcebb52c2c11daa12d55a58532b96e52efc6b7b402d0049733127b5154083cef
Checks run (2 succeeded)
-
Again, mostly some formatting nits. I did have a few suggestions on ways to simplify a few things :)
-
-
-
-
-
-
-
This is setting the same list in a loopp
len(parsed.getlist(attr))
times.This also doesn't need to encode values.
What this should be is:
query.setlist(parsed.getlist(attr))
-
-
-
-
-
-
Since we are appending every single entry in
args
intoquery
, we can simply do:for arg in args: query.update(QueryDict(arg))
QueryDict.update
appends to lists instead of overwriting them. -
-
- Description:
-
Previously, it was only possible to update a single query parameter with
{% querystring_with %}
. However, in the name of future proofing, itbecame necessary to make a new template tag {% querystring %}
that can take an arbitrary number of key-value pairs now with different modes in the form of: {% querystring “mode” "key1=value1" "key2=value2" %}
~ There are three different modes are:
~ The three different modes are:
“remove” - Will remove keys from the query string. “append” - Will append values for its given key without overwriting. “update” - Will add to or replace part of a query string.
- Commit:
-
32b96e52efc6b7b402d0049733127b5154083cefc6ffeb14dde934fbe563c8c3e3be26654792d0c9
Checks run (2 succeeded)
-
-
I think this will miss some cases, e.g.
{% querystring "remove" "x&y=1&z=" %}
. Now, this is an edge case, but we should still handle it well.We know that in the above example it will result in:
{'x': [''], 'y': ['1'], 'z': ['']}
We can't really distinguish between
z=
andz
in the argument, so we should treat them both the same.for attr in parsed: values = parsed.getlist(attr) if values == ['']: # An empty value means either `attr` or `attr=` was provided. # In either case, remove all values. query.pop(attr, None) else: values = query.getlist(attr) for value in parsed.getlist(attr): try: values.remove(value) except ValueError: pass
-
- Commit:
-
c6ffeb14dde934fbe563c8c3e3be26654792d0c9f1859476efe3b52553393539ce2edb71b2863e61
Checks run (2 succeeded)
-
-
-
The second for loop needs to be nested in the first, otherwise only the last element in
args
will be removed form the querystring. Can you add a unit test that does multiple removes? e.g.{% querystring "remove" "a" "b" "c=1" %}
-
This needs to be indented to be aligned with the
if
. It is currently always executing because there is nobreak
in the for loop
- Commit:
-
f1859476efe3b52553393539ce2edb71b2863e61933e89878606fa1353c8558d6dcb0d119fe85ef4
Checks run (2 succeeded)
-
-
-
-
-
The
key=value
should be in quotes, right?For "mode", is the equivalent always "update"? If so, we can say that explicitly. In fact, we can help further with examples:
warnings.warn( '{% querystring_with "%(attr)s" "%(value)s" %} is deprecated ...' 'Please use {% querystring "update" "%(attr)s=%(value)s" %} instead.' % { 'key': attr, 'value': value, }, DeprecationWarning)
-
-
-
-
-
This is going to set the list of values for every value in the list of values. You should be able to remove the
for
loop here. -
This doesn't seem right. We're overriding
to_remove
every time, meaning we're only ever getting the list for the last attribute. Was the rest of this meant to be within the for loop?This means to me that we're missing some very crucial unit tests somewhere.
-
-
-
The trailing period should remain. You only remove this for docstrings for unit tests themselves (as they're outputted to the terminal and shouldn't end in a period).
-
The tests in this module should be updated to check for warnings as well. Search the codebase for
catch_warnings
for examples. -
-
-
-
-
I'd recommend just setting
self.request
insetUp()
(notsetUpClass()
, since it'll be modified) and referencing it in all the tests. -
-
-
-
Best to explicitly check the resulting value, rather than introducing another parsing/checking step. That just leads to problems, as more things can go wrong, and reviewers/future contributors have no idea what the result is even supposed to be.
This applies to all tests.
-
-
You can start the template on the first line, like:
t = Template('{% load djblets_utils %}' '{% querystring .... %}')
Same for other tests.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
"""
on the next line."a key fragments" doesn't make sense. Maybe just "a key fragment?" What's a key fragment?
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Commit:
-
933e89878606fa1353c8558d6dcb0d119fe85ef4aa774d8790e674a441d257a3f8d7525f38ea3481