Django error with (CRUD) urls.py - django

as part of my continuing want to do well on my Uni course, I'm doing a bit of web-dev in Python(2.7) using Django. I had followed Django's tutorial and now I am following this tutorial. However, I get a somewhat inexplicable error when I add in the urls.py part to give me some viewing models. The project is called 'practice' and the app is called 'orders'. Within 'orders' are the models (which all validate)
The (relevant part of) urls.py is:
'django.views.generic.list_details',
url(r'^orders/$', 'object_list', {'queryset': 'orders.Product.objects.all()'}),
url(r'^orders(?P<slug>[-\W]+)/$', 'object_detail', {'queryset': 'orders.Product.objects.all()'})
I've double checked ROOT_URLCONF is correctly set so the error appears to be somewhere within 'django.views.generic.list_details' as a use.
The error message is:
AttributeError: 'str' object has no attribute resolve
A good Google didn't seem to produce anything reasonable so any chance of a hand please guys?
Thanks!

Did you forget "patterns"?
urlpatterns = patterns('',
(r'^$', ...),
# ...
Also I've noticed a slash missing:
url(r'^orders(?P<slug>[-\W]+)/$', 'object_detail', {'queryset': 'orders.Product.objects.all()'})
url(r'^orders/(?P<slug>[-\W]+)/$', 'object_detail', {'queryset': 'orders.Product.objects.all()'})

The AttributeError suggests to me that the string 'django.views.generic.list_details' is being treated as a url to be resolved. However, you've omitted too much of your urls.py to say for sure.
Make sure the prefix string is the first argument to django.conf.urls.patterns. If you want to break up your urls and use different prefix strings, invoke patterns multiple times as described in the documentation:
urlpatterns = patterns('myapp.views',
url(r'^$', 'app_index'),
url(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$','month_display'),
)
urlpatterns += patterns('weblog.views',
url(r'^tag/(?P<tag>\w+)/$', 'tag'),
)

You've quoted the value in the arguments dictionary in each pattern, so it's being treated as a string. It should be:
url(r'^orders/$', 'object_list', {'queryset': orders.Product.objects.all()})
Not that you'll need to import orders - except I doubt that will work, because Product will be defined in the models file inside orders. It would be easier to just import Product and refer to it directly.

Related

How can I use a catch all route using `path` or `re_path` so that Django passes all unmatched requests to my index view?

My url patterns look like this:
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('api.urls')),
re_path('.*', IndexView.as_view()),
]
This works but it matches all URLs, including those prefixed with admin and api. I want those URLs to still match, and for any unmatched URLs to render IndexView.
Before 2.0 I used this regex for this purpose. I tried using it in re_path but that didn't work, which is what led me to trying the above.
url(r'^(?P<path>.*)/$', HtmlView.as_view())
Use case is a SPA where I handle 404s client side.
Many thanks in advance.
You can use two entries (one for '/', another one for anything else), but using path for both of them, which should be (slightly) more efficient:
urlpatterns = [
path('', IndexView.as_view(), {'resource': ''}),
path('<path:resource>', IndexView.as_view())
]
In this case, I'm using <path:resource> because path catches all resource names, inluding that with / in them. But it does not capture the main index resource, /. That's why the first entry. The dictionary as last argument for it is because we need to provide a resource parameter if we want to use the same view than in the second entry.
That view, of course, should have 'resource' as a paremeter:
def as_view(request, resource):
...
So as I said in the question description, trying the regex I was using before Django 2.0 in re_path did not work. It would basically match for all requests except / (i.e., index path). I fixed this by using both that regex and a second path matching / specifically. Here's the code:
urlpatterns = [
re_path(r'^(?P<path>.*)/$', IndexView.as_view()),
path('', IndexView.as_view()),
]
With these changes my other routes would match and these two routes would account for all other urls.
One Idea to go about this is let the django catch 404.
url.py
from django.conf.urls import handler404
handler404 = 'app_name.views.bad_request'
and in your views.py
views.py
def bad_request(request):
return redirect(reverse('home'))
You can always do some regex thingy to catch unmatched urls. but hey this gets the job done. :)

Django: formats of urlpatterns in urls.py

I noticed that in Django there are two formats of urlpatterns in file urls.py:
urlpatterns = [
url(...),
url(...),
]
and
urlpatterns = pattern('',
url(...),
url(...),
)
The first is a list of url instances, and the second invokes the pattern module with an empty string and a number of url instances as parameters.
What is the difference between the two?
What is the purpose of an empty string in the second format?
Which one is recommended to use?
In Django 1.8+, urlpatterns should simply be a list of url()s. This new syntax actually works in 1.7 as well.
urlpatterns = [
url(...),
url(...),
]
The old syntax using pattern is deprecated in Django 1.8, and is removed in Django 1.10.
urlpatterns = pattern('',
url(...),
url(...),
)
With the old syntax, you could provide a prefix. The example given in the docs is
urlpatterns = patterns('news.views',
url(r'^articles/([0-9]{4})/$', 'year_archive'),
url(r'^articles/([0-9]{4})/([0-9]{2})/$', 'month_archive'),
url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', 'article_detail'),
)
However, using strings arguments for the view is now deprecated as well, and you should provide the callable instead.
Per the documentation, patterns is:
A function that takes a prefix, and an arbitrary number of URL
patterns, and returns a list of URL patterns in the format Django
needs.
The first argument to patterns() is a string prefix.
It also provides an example of why you might want to use it:
from django.conf.urls import patterns, url
urlpatterns = patterns('',
url(r'^articles/([0-9]{4})/$', 'news.views.year_archive'),
url(r'^articles/([0-9]{4})/([0-9]{2})/$', 'news.views.month_archive'),
url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', 'news.views.article_detail'),
)
In this example, each view has a common prefix – 'news.views'.
Instead of typing that out for each entry in urlpatterns, you can
use the first argument to the patterns() function to specify a
prefix to apply to each view function.
With this in mind, the above example can be written more concisely as:
from django.conf.urls import patterns, url
urlpatterns = patterns('news.views',
url(r'^articles/([0-9]{4})/$', 'year_archive'),
url(r'^articles/([0-9]{4})/([0-9]{2})/$', 'month_archive'),
url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', 'article_detail'),
)
However, note that this function is deprecated:
Deprecated since version 1.8:
urlpatterns should be a plain list of django.conf.urls.url() instances instead.
Note that the explanation as to why includes (with good reason, clearly!):
Thus patterns() serves little purpose and is a burden when teaching
new users (answering the newbie’s question "why do I need this empty
string as the first argument to patterns()?").

Django url patterns for different currencies

I am building a site in english and simply want to offer a small subset of currencies. For SEO and caching I am planning to develop the following url structure with the prices being displayed in the relevant currencies.
Home(s)
site.com/
site.com/au/
site.com/us/
...
Categories Index Pages
site.com/categories/
site.com/au/categories/
site.com/us/categories/
...
Product Index Pages
site.com/categories/category1/
site.com/au/categories/category1/
site.com/us/categories/category1/
...
Product Pages
site.com/categories/category1/product-1/
site.com/au/categories/category1/product-1/
site.com/us/categories/category1/product-1/
...
This is my attempted url.py
urlpatterns = patterns('',
#url(r'^$', views.homeCurrency, {'cur_slug': '' }, name='home'),
url(r'^(?P<cur_slug>[:au|nz|us|eu|ca|uk]+)/$', views.homeCurrency, name='home'),
url(r'^categories/', include('parts.urls', namespace="parts")),
url(r'^(?P<cur_slug>[:au|nz|us|eu|ca|uk]+)/bike-parts/', include('parts.urls', namespace="parts")),
)
This is the sort of dynamic url I need in my base.html
Home
My problem is two fold (I think)
Firstly, I can't allow for the default case i.e. site.com(/) in the url pattern so that there is a common url name that can be used dynamically throughout each version of the site.
Secondly, even ignoring the default case, I am getting the following error:
Request Method: GET
Request URL: site.com/au/
Django Version: 1.5.4
Exception Type: NoReverseMatch
Exception Value:
Reverse for 'home' with arguments '()' and keyword arguments '{}' not found.
Any help would be greatly appreciated as this is my first project in Django. Cheers
The first problem is with your regex. [] means character class, i.e. [a|bc] would match a, |, b or c but never bc.
Hence, your regex should be using groups ():
url(r'^(?P<cur_slug>au|nz|us|eu|ca|uk)/$', views.homeCurrency, name='home'),
If you're not 100% confident with regex, you should have a look into the excellent surlex library, which provides a neat little DSL for writing URL patterns.
from surlex.dj import surl
// a macro for valid currencies
surlex.register_macro('$', r'au|nz|us|eu|ca|uk')
urlpatterns = patterns('',
// macros are only used in match groups (surrounded with `<>`)
surl(r'<cur_slug:$>/$', views.homeCurrency, name='home'),
surl(r'<cur_slug:$>/bike-parts/$', include('parts.urls', namespace="parts")),
)
regarding your choice of "dynamic url", why not instead base your url roots on locale, and choose the correct currency based on locale. REF

understading django.shortcuts.reverse, part 2

In Understanding django.shortcuts.redirect I started a thread about reverse and redirect_to.
I still have some problems understanding how reverse works when the first parameter is a string. I read https://docs.djangoproject.com/en/1.4/topics/http/shortcuts/#django.shortcuts.redirect many times and the corresponding part with reverse. But I am still getting a NoReverseMatch exception.
In my ROOT_URLCONF I have
urlpatterns = patterns('',
url(r'^$', redirect_to, {'url': '/monitor/'}),
url(r'^monitor/', include('monitor.urls')),
)
In monitor.urls I have
urlpatterns = patterns('monitor.views',
(r'^$', 'index'),
(r'^list', 'listall'),
)
and in monitor.urls I've defined code for both functions, index and listall. In listall I added the following lines:
def listall(request):
<more code goes here>
print "reversing 1 index: %s " % reverse(index)
print "reversing 2 index: %s " % reverse('index')
render_to_response("monitor/list.htmld", params)
If I visit localhost:3000/monitor/list then I can see
reversing 1 index: /monitor/
and nothing else, the second reverse raises an exception. Why? What am I missing?
I tracked it down to djangos code django.core.urlresolvers.callable and django.core.urlresolvers.get_mod_func. get_mod_func seems to expect something like "a.b", thats why in callable the very first line returned "index" for func_name but an empty string for mod_name. I changed my second line to
print "reversing 2 index: %s " % reverse('monitor.views.index')
and it worked as intended. So, why do I need to call reverse with the full module and function name (when I use strings) and the documentation doesn't? What am I missing?
Thanks
I'm not sure what part of the documentation you're hung up on, but reverse's first parameter is some identifying method of getting to a view: it can be either a urlpattern name, a full dotted path to the view, or the view itself
So, based on your example, the first method is out because you didn't define a name for your urlpattern. Your first try, reverse(index) worked because you literally passed it the view. Your second try, reverse('index'), doesn't work because it need the full import context, i.e. 'monitor.views.index'. The difference between the two is that when it's a string, Django must interpret that string to create an import for the view -- and 'index' is not enough information to determine the import path.
However, it's far, far better to just name your views if you intend on reversing them, and you should also namespace your included urlpatterns so two different apps don't end up conflicting. So in the project-level urls.py:
urlpatterns = patterns('',
url(r'^$', redirect_to, {'url': '/monitor/'}),
url(r'^monitor/', include('monitor.urls', namespace='monitor', app_name='monitor')),
)
Then, in monitor/urls.py:
urlpatterns = patterns('monitor.views',
(r'^$', 'index', name='index'),
(r'^list', 'listall', name='listall'),
)
Then, reversing is as simple as reverse('monitor:index').
you should be doing something like
reverse('monitor:index')
In ROOT_URLCONF I have
urlpatterns = patterns('',
(r'^$', redirect_to, {'url': '/monitor/'}),
(r'^monitor/', include('monitor.urls'),namespace='monitor'),
)
and in monitor.url.py:
urlpatterns = patterns('monitor.views',
url(r'^$', 'index',name='index'),
)
for more details look at https://docs.djangoproject.com/en/1.4/topics/http/urls/#django.core.urlresolvers.reverse

Django: include other urlpatterns in a single urls.py

I am doing something like this in myproject.myapp.urls:
from django.conf.urls.defaults import *
urlpatterns = patterns('myproject.myapp.views',
(ur'^$', 'index'),
(ur'^browse/$', 'browse'),
(ur'^request/new/$', 'new_request'),
(ur'^(?P<url_key>[-a-zA-Z0-9]+)/$', 'view1'),
(ur'^(?P<url_key>[-a-zA-Z0-9]+)/asdf$', 'view2'),
(ur'^(?P<url_key>[-a-zA-Z0-9]+)/qwer$', 'view3'),
(ur'^(?P<url_key>[-a-zA-Z0-9]+)/zxcv$', 'view4'),
(ur'^(?P<url_key>[-a-zA-Z0-9]+)/tyui$', 'view5'),
(ur'^(?P<url_key>[-a-zA-Z0-9]+)/ghjk$', 'view6'),
(ur'^(?P<url_key>[-a-zA-Z0-9]+)/bnm/more-looong-url/$', 'view7'),
...
)
I've tried to refactor above rules and define them in another file urls2.py like this:
(ur'^(?P<url_key>[-a-zA-Z0-9]+)/', include('myproject.myapp.urls2')),
but it seems to cause problems with unit tests including urlresolvers.
Is there better way to "refactor" the common part of regular expression (<url_key>) here?
I'm no django expert, but wouldn't the 'view1' item match all of the other entries below it since it doesn't have a '$' at the end? So the other views wouldn't have a chance to get matched.
I don't think you can do what you are trying to do with this line:
(ur'^(?P<url_key>[-a-zA-Z0-9]+)/', include('myproject.myapp.urls2'))
What view is the url_key parameter going to be passed to?
I'm not sure why you want to refactor the urlpatterns to begin with, but maybe this would be better?:
from django.conf.urls.defaults import *
URL_KEY = ur'^(?P<url_key>[-a-zA-Z0-9]+)'
urlpatterns = patterns('myproject.myapp.views',
(ur'^$', 'index'),
(ur'^browse/$', 'browse'),
(ur'^request/new/$', 'new_request'),
(URL_KEY+ur'/$', 'view1'),
(URL_KEY+ur'/asdf$', 'view2'),
(URL_KEY+ur'/qwer$', 'view3'),
...etc
)
Perhaps you could simplify the expressions in myproject.myapp.urls, and instead pass the information along as a parameter to a function in myproject.myapp.views?
I'm not sure what was going wrong in your tests, but generally speaking you'll be able to do more in myproject.myapp.views since you don't have to base it all on regex logic.
That function in myproject.myapp.views would be a switchboard that calls view1, view2, etc