In Django, is it not possible to have multiple views imports from the urls.py?
For example, I have the following code in urls.py:
from mysite.books import views
from mysite.contact import views
urlpatterns = patterns('',
(r'^contact/$', views.contact),
(r'^search/$', views.search),
)
However, the server displays an error unless I disable one of the couples. So my questions are threefold:
1) Is it not possible to have multiple import views statements?
2) How to get around this?
3) What is best practice for where to put all your views.py? One file? Multiple files? etc.
Thank you.
1) Yes it is.
2)
from mysite.books import views as books_views
from mysite.contact import views as contact_views
urlpatterns = patterns('',
(r'^contact/$', contact_views.contact),
(r'^search/$', books_views.search),
)
3) Per Django docs, "This code can live anywhere you want, as long as it’s on your Python path.". I keep all the app views in app/views.py
You can import as many things as you like, but objects have to have unique names for them to be distinguished.
There are a couple of ways of dealing with this. One is to simply import the functions, rather than the module:
from mysite.books.views import books
from mysite.contact.views import contact
This is obviously only good if you only have one or two views in each file. A second option is to import the modules under different names:
from mysite.books import views as books_views
from mysite.contact import views as contact_views
A third option is not to import the views at all, but use strings to refer to them:
urlpatterns = patterns('',
(r'^contact/$', 'contact.views.contact'),
(r'^search/$', 'book.views.search'),
)
A fourth is to have separate urls.py for each application, and include the urlconfs in the main urls.py.
I think that another option would be:
urlpatterns = patterns('mysite.books.views',
(r'^contact/$, 'contact'),
)
urlpatterns += patterns('mysite.contact.views',
(r'^search/$, 'search'),
)
as described in djangobook.
Related
I’m still learning django and assume this may be easy for some. I’m trying to figure out the best way of simply setting up the API URLs (and so that they all display in the api root and can actually be used in the project - in my case at /api/). I’m using django rest framework, and can’t seem to set up more than one API - it works for just one, but the problem occurs when trying to set up another.
So I have an app called pages and accounts (and core - the default where the main urls.py is). I’ve created another urls.py inside the pages app and another inside the accounts app.
accounts/urls.py:
from . import views
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r"accounts", views.AccountsViewSet, basename="accounts")
urlpatterns = router.urls
pages/urls.py:
from . import views
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r"pages", views.PagesViewSet, basename="pages")
urlpatterns = router.urls
And the core urls.py:
from django.contrib import admin
from django.urls import path, include
from rest_framework import routers
from rest_framework.routers import DefaultRouter
router = routers.DefaultRouter()
urlpatterns = [
path("admin/", admin.site.urls),
path("api/", include("pages.urls")), # works but root only shows pages API
# path("api/", include("pages.urls", "accounts.urls")), # fails with error: “django.core.exceptions.ImproperlyConfigured: Specifying a namespace in include() without providing an app_name is not supported. Set the app_name attribute in the included module, or pass a 2-tuple containing the list of patterns and app_name instead.”
# path("api/", include(router.urls)), # no error but root api is empty
]
I would assume, possibly incorrectly, that just router.urls should include all the apis when visiting the root. The root apis currently looks like this when using just include("pages.urls”):
{
"pages": "http://localhost:8000/api/pages/"
}
How can I get it to correctly show all apis? The only way I could do it was by putting router.register(r"accounts", views.AccountsViewSet, basename="accounts”) in the pages urls.py, which is very undesirable, especially as the project grows even further.
Thank you
Have you tried to use:
path("api/pages/", include("pages.urls")),
path("api/accounts/", include("accounts.urls")),
In your urls.py?
Possibly that would mean your routes would be:
{
"pages": "http://localhost:8000/api/pages/pages/"
"accounts": "http://localhost:8000/api/accounts/accounts/"
}
In that case you could try to use
router.register("", views.AccountsViewSet, basename="accounts")
in accounts/urls.py.
And similarly,
router.register("", views.AccountsViewSet, basename="pages")
in pages/urls.py.
That way, you might achieve to have routes like:
{
"pages": "http://localhost:8000/api/pages/"
"accounts": "http://localhost:8000/api/accounts/"
}
if that is what you want.
I'm very very new to Python 3 and Django and I get to the following problem: I use a standard Template and now how to set it up when there is 1 view. But I don't get the code right for multiple views. I currently run the page locally
At the moment I have tried to change different orders within urlpatterns, and they do work when only 1 url in in there, but I can't get the second one in
views.py
from django.shortcuts import render, render_to_response
# Create your views here.
def index(request):
return render_to_response('index.html')
def store(request):
return render_to_response('store.html')
urls.py
from django.conf.urls import include, url
from django.contrib import admin
from myapp import views as views
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^store/$', views.store, name='store'),
url(r'^admin/', admin.site.urls)
]
urlpatterns += staticfiles_urlpatterns()
I would like the url pattern that lets me go to the index view and the store view
EDIT:
Full code is shared via: https://github.com/lotwij/DjangoTemplate
The error in the comments shows you are going to http:/127.0.0.1:8000/store.html, but your URL pattern url(r'^store/$', ...) does not include the .html, so you should go to http:/127.0.0.1:8000/store/.
The Django URL system uncouples the URL from the name of the template (sometimes the view doesn't even render a template!). You could change the regex to r'^store.html$ if you really want .html in the URL, but I find the URL without the extension is cleaner.
from django.conf.urls import url, patterns, include
from django.contrib import admin
from django.views.generic import TemplateView
from collection import *
#from collection.views import index,thing_detail,edit_thing
urlpatterns = [
url(r'^$', views.index, name='home'),
url(r'^about/$',TemplateView.as_view(template_name='about.html'),name='about'),
url(r'^contact/$',TemplateView.as_view(template_name='contact.html'),name='contact'),
url(r'^things/(?P<slug>[-\w]+)/$', 'views.thing_detail' ,name='thing_detail'),
url(r'^things/(?P<slug>[-\w]+)/edit/$', 'views.edit_thing',name='edit_thing'),
url(r'^admin/', include(admin.site.urls)),
]
After running the server there is an error "NameError: name 'views' is not defined"
Any help ??
You aren't importing your own views.
Try adding this to your urls.py:
from . import views
Or if you are importing them from a specific app, try replacing . with the app name
First thing I notice is the import *, realize that this will/can cause confusion for other Developers reading your scripts. Python has a methodology that insists that explicit is better than implicit. Which in this senario means you should be explicit about what you are importing.
from django.conf.urls import url, patterns, include
from django.contrib import admin
from django.views.generic import TemplateView
from collection import views as collection_views
urlpatterns = [
# Function Based Views
url(r'^$', collection_views.index, name='home'),
url(r'^things/(?P<slug>[-\w]+)/$', collection_views.thing_detail ,name='thing_detail'),
url(r'^things/(?P<slug>[-\w]+)/edit/$', collection_views.edit_thing,name='edit_thing'),
# Class Based Views
url(r'^about/$',TemplateView.as_view(template_name='about.html'),name='about'),
url(r'^contact/$',TemplateView.as_view(template_name='contact.html'),name='contact'),
# Admin
url(r'^admin/', include(admin.site.urls)),
]
Here instead of importing everything from collection I'm importing just your views and assigning them to a variable. Then using that variable in the URL definitions.
Be sure to import your views by
specifying its location and the methods inside the view to be imported on your urls.py.
from . collection import *
(line above means from current location find collection.py and import everything on it)
Happy coding!
It's written in official documentation here that i18n_patterns() is only allowed in your root URLconf.
This is a problem for me because I need those URLs working:
/en/products/
/fr/produits/
/sv/produkt/
/en/products/detail/[my product name]/
/en/produits/detail/[my product name]/
/sv/produkt/detalj/[my product name]/
/sv/produkt/detalj/[my product name]/
Heres my root urls.py:
urlpatterns += i18n_patterns(
url(_(r'^produits/detail/'),
include('produits.urls', namespace="produits")
),
url(_(r'^produits/'),
include('produits.urls', namespace="produits")
),
)
So, for the lastest translation works ok, but the first one doesn't. The translation is ok, but I want to transfer the last part ('detail/') to the app produits that should handle it transparently.
How do I do?
Here's how I've solved the problem. This is not a good solution but it's the only one working for now with Django 1.8.
I've removed my routes from my "produits" application, and added them to the main urls.py which means mixing application configuration with global configuration. I dont like it.
I've also added the name of the application before each route: produits_detail and produits_index. Thus I know the app those routes are for. Once again I dont like mixing "global setting" and specific settings, but it seems I have no choice. Anyway, few lines of code, and it works pretty well.
from django.contrib import admin
from django.conf.urls import include, url
from django.conf.urls.i18n import i18n_patterns
from django.utils.translation import ugettext_lazy as _
from produits import views as p_views
urlpatterns = [
url(r'^i18n/', include('django.conf.urls.i18n')),
url(r'^admin/', include(admin.site.urls)),
]
urlpatterns += i18n_patterns(
url(_(r'^produits/detail/(?P<slug>[a-zA-Z0-9-_]+)/$'),
p_views.DetailView.as_view(), name='produits_detail'),
url(_(r'^produits/'),
p_views.IndexView.as_view(), name='produits_index'),
)
I was reading some tutorials and books about generic views.
In part 4 of the official tutorial, they wrote an example like this
from django.conf.urls import patterns, include, url
from django.views.generic import DetailView, ListView
from polls.models import Poll
urlpatterns = patterns('',
url(r'^$',
ListView.as_view(
queryset=Poll.objects.order_by('-pub_date')[:5],
context_object_name='latest_poll_list',
template_name='polls/index.html')),
url(r'^(?P<pk>\d+)/$',
DetailView.as_view(
model=Poll,
template_name='polls/detail.html')),
url(r'^(?P<pk>\d+)/results/$',
DetailView.as_view(
model=Poll,
template_name='polls/results.html'),
name='poll_results'),
url(r'^(?P<poll_id>\d+)/vote/$', 'polls.views.vote'),
)
I have also been reading The Definitive Guide to Django: Web Development Done Right, Second Edition and when they talked about generic views, they wrote their example like this
from django.conf.urls.defaults import *
from django.views.generic import list_detail
from mysite.books.models import Publisher
publisher_info = {
'queryset': Publisher.objects.all(),
'template_name': 'publisher_list_page.html',
}
urlpatterns = patterns('',
(r'^publishers/$', list_detail.object_list, publisher_info)
)
Should I be using ListView or list_detail? They both come from django.views.generic. If they can both be used, then what's the difference (advantage and disadvantage comparison)?
In case it helps, I'll explain my objective: In my project, I want to list work orders, and then I want a detailed view of each work order that will also contain a list of comments for that order (similar to comments per blog post).
I'm finding Classy useful as an easy way to view an outline of each CBV: http://ccbv.co.uk/projects/Django/1.6/django.views.generic.list/ListView/
It feels like a missing part of the Django docs now.
ListView (class-based) is intended to replace object_list (function-based) because there is limited flexibility to extending a function's behavior.
As the Django (1.4) documentation notes, the function-based generic views are deprecated in favor of the class-based versions. So use ListView, since Django removed object_list.
Either way, I prefer to put all the customizations in views.py to avoid cluttering up urls.py, which tends to be a dumping ground of things.