Reputation: 27806
Up to now a team mate used this code for the url patterns of user names:
# urls.py
urlpatterns = patterns('...',
url(r'^user/(?P<username>[.-_\w]+)/foo', 'myapp.views.foo'),
....
there is a hidden bug: If the username contains a -
the reversing would fail, since the beginning of the regex pattern [.-_
means "all chars from .
to _
".
What pattern can be used to match all valid usernames?
PS: I guess adding the -
sign to the regex is not enough, if you want to match all possible user names in django.
Upvotes: 6
Views: 3612
Reputation: 1475
I don't think you should put any username validation in your URL pattern. Keep your validation in one place -- the place you create your accounts for the first time.
You should match anything the user supplies there, and pass that to a safe database function to look up the username and fail if it doesn't exist.
So, in your url pattern, let the browser send anything that is nonempty, and rely on your very smart database to tell you what you previously decided was valid or not.
url(r'^user/(?P<username>.+)/foo$', 'myapp.views.foo'),
Also, note the "$" on the end.
Upvotes: 7
Reputation: 3299
You can use following way:
[-.\w]
(-
use in left most)
or [.\-\w]
(-
use with backslash in any place)
or [.\w-]
(-
use in right most)
if you use special characters then best use \
(backslash ) before any special characters (which are used in regex special char.).
For best use your regex will be ^user/(?P<username>[.\-_\w]+)/foo
Upvotes: 4
Reputation: 18727
First of all, it is not a bug but a feature well documented in the docs:
[]
Used to indicate a set of characters. In a set:
Ranges of characters can be indicated by giving two characters and separating them by a '-', for example [a-z] will match any lowercase ASCII letter, [0-5][0-9] will match all the two-digits numbers from 00 to 59, and [0-9A-Fa-f] will match any hexadecimal digit. If - is escaped (e.g. [a-z]) or if it’s placed as the first or last character (e.g. [a-]), it will match a literal '-'.
So, using -
between two literals will evaluate that regex as a character range:
re.compile("[a-0]+")
>> error: bad character range
re.findall("[.-_]+", "asdasd-asdasdad._?asdasd-")
>> ['._?']
As you see, python will always interperet -
as a range indicator when used between characters in character sets.
As it is (also) stated in the docs, avoiding a range declaration is done by escaping the -
with \-
or placing it as the first or the last literal in the character set []
If you want to capture that character range including -
, then try:
re.findall("[.-_\-]+", "asdasd-asdasdad._?asdasd-")
>> ['-', '._?', '-']
Note: \w
is equal to [a-zA-Z0-9_]
when LOCALE and UNICODE flags are not set. So you do not need to declare _
again
And in your situation:
url(r'^user/(?P<username>[-.\w]+)/foo', 'myapp.views.foo')
url(r'^user/(?P<username>[.\w-]+)/foo', 'myapp.views.foo')
url(r'^user/(?P<username>[.\-\w]+)/foo', 'myapp.views.foo')
Beyond the -
usage, if you are using default Django Username styling, then @navneet35371 is right about the valid character set. You may alter your regex character set to include @
and +
and use
url(r'^user/(?P<username>[\w.@+-]+)/foo', 'myapp.views.foo')
Upvotes: 0
Reputation: 4813
Based on what I see in the AbstractUser
model, I think a better regex to use to grab the username is (?P<username>[\w.@+-]+)
.
Upvotes: 9
Reputation: 308779
You can either move the hyphen to the start of the character class,
[-.\w]
or you can escape it with a backslash
[.\-\w]
Note I have removed the underscore, since it is included in \w
. I am also assuming that you only want to accept .
, -
and \w
, and you don't want to accept all the characters from .
to _
. That range includes characters like @
, so you might want to check that all your usernames match the new regex.
Upvotes: 4