I'm new to Django and working my way through "The Django Book" by Holovaty and Kaplan-Moss. I have a project called "mysite" that contains two applications called "books" and "contact." Each has its own view.py file. In my urls.py file I have the following:
from books import views
from contact import views
...
urlpatterns = patterns('',
...
(r'^search/$', views.search),
(r'^contact/$', views.contact),
...
When I run my code I get this error:
NameError at /search/
...
Exception value: 'module' object has no attribute 'search'
What I believe is happening is that since views from contact was imported last, Django is looking at contact's view which does not contain search (search is in books' view).
What is the proper way to import the views.py file from two distinct applications within a Django urls file?
Thanks for your help!
Disclaimer: Not a Django answer
The problem is with these two lines:
from books import views
from contact import views
The second import is shadowing the first one, so when you use views later you're only using the views from contact.
One solution might be to just:
import books
import contact
urlpatterns = patterns('',
...
(r'^search/$', books.views.search),
(r'^contact/$', contact.views.contact),
...
I'm not sure, but I also think that you don't actually need to import anything and can just use strings in your pattern, something like: 'books.views.search'.
Another possiblity is to follow Simon Visser suggestion:
from books.views import search
from contact.views import contact
from books import views
from contact import views
You are overwriting the name views. You need to import them as different names or as absolute names.
import books.views
import contact.views
... or ...
from books import views as books_views
from contact import views as contact_views
Then use the correct name when defining your URLs. (books.views.search or books_views.search depending on the method you choose)
The reason I’m answering this question is because it was answered years ago and those answers are not correct or useful anymore for newer Django versions, or there is a better practice you should know about.
So, if you have more than one app in your Django project then you should use a new urls.py file for every one of your apps. It means that if you start a new app then you have to manually create a new file called urls.py in the subfolder of your new app. Many beginners first do not understand why this is good, but this is a good practice if you plan creating more apps in one Django project.
When you start a project, the urls.py file automatically created in your project folder, but if you create/start a new app in Django, then it is a good practice if you create a separate urls.py for that app in its own folder. (And that way you will never have the "importing different app's views into urls.py" problem in the first place).
After you created the urls.py file for your app, then you have to include that app’s urls.py file in your project’s urls.py file in the following way:
Let’s see an example when you create a new app called ‘my_new_app’.
This is how your project’s main urls.py file should look like:
from django.conf.urls import url, include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^my_new_app/', include('my_new_app.urls')),
]
In your project’s urls.py file you have to import the ‘include’ method, then you can include your my_new_app urls.py file in your project’s main urls.py file. In your my_new_app folder you have to manually create a urls.py file as I stated above. Then you have to use that file for all of your urlpatterns of your my_new_app. Then of course this way it’s going to be automatically included in your project’s main urls.py file.
So this is then how your my_new_app own urls.py file should look like:
from django.conf.urls import url
from my_new_app import views
urlpatterns = [
url(r'^$', views.index, name = "index"),
]
Assuming that you also created a first view called ‘index’ in your ‘my_new_app/views.py file.
my_new_app/views.py file look like this:
from django.shortcuts import render
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello World!")
And you can check your my_new_app in your browser at:
http://localhost:8000/my_new_app
(Of course you can give any url to your my_new_app in your project's urls.py file.)
Now, you can create another app, in your Django project, called my_second_app and you should repeat the above steps for that app too. This way you will not have any problem importing views from different apps into urls.py files. This would be a very basic “good practice solution” for this problem in 2017 in Django 1.11.
The URLconfs documentation gives an example of the same situation
You can skip the imports and separate the urls by app as such:
urlpatterns = patterns('books.views',
(r'^/book/search/$', 'search'), #calls books.views.search
)
urlpatterns += patterns('contact.views', #make note of the '+='
(r'^/contact/search/$', 'search'), #calls contact.views.search
)
Heres the approach i took for different view/API versions:
from django.urls import path
from my_app import views as api_v1
from my_app import views_v2 as api_v2
urlpatterns = [
path('view_one', api_v1.ViewOne.as_view()),
path('view_two', api_v2.ViewTwo.as_view()),
]
Related
I just started learning django and running the tutorial part 3, decided to see if I understood the mapping from urls.py to views.py.
I got views and urls to work in the polls app, but then I wanted to make views in the project folder, so I made a views.py file in the project folder (see code below), with a view/function , which I named 'home'.
I then edited the urls.py in the project-folder(see below). run the server, It worked! visiting the url: http://localhost:8000/
it responded:
Hello, world. You're at the HOME PAGE.
BUT.. when I tried to make another view in same views.py called: morn, and adding the url for it, then error (see below),
http://localhost:8000/morn
returning:
localhost refused to connect.
I DID IT EXACTLY THE SAME WAY, so just when I thought I understood it, I didnt get it at all?!?!
The difference between the two views are just their name and path, why doesnt it work then?
on a linux manjaro
Python 3.8.1
Django 3.0.3
#
#this is my urls.py (which I made myself), in the project folder
from django.urls import include, path
from django.contrib import admin
from . import views
#from views import morn
admin.autodiscover()
urlpatterns = [
#lager en index-side
path('', views.home, name='home'),
path('morn/', views.morn, name='morn'),
path('admin/', admin.site.urls, name='admin'),
path('polls/', include('polls.urls')),
]
#
#this is the views.py in myproject folder, same folder as
from django.http import HttpResponse
def home(request):
output = 'Hello, world. You\'re at the HOME PAGE.'
return HttpResponse(output)
def morn(request):
output = 'Hello, world. Youre at the morn-path.'
return HttpResponse(output)
ERROR from konsole running the morn-view:
File "/home/nr1/dev/django/myproject/myproject/urls.py", line 29, in <module>
path('morn/', views.morn, name='morn'),
AttributeError: module 'myproject.views' has no attribute 'morn'
Oh no... I just got it! :)
I have put the views.py file in both of the myproject-folders and the urls.py is just in the inner myproject-folder. I was then updating just the outer views.py-file, when I thought I was in the inner views.py, so, ofcourse, the urls.py couldnt find the new function, it was searching the wrong views.py (outer one).
a lot of frustration for nothing.. but I learnt, I learnt!
I'm changing view of homepage with app names pages.
I've added pages to settings. this is how directory look like:
- trydjango
- src/
- pages/
- __init__
- views
- products
- trydjango/
- __init__
- settings
- urls
- manage
views' code:
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
def home_view(*args, **kwargs):
return HttpResponse("<h1>Hello Again</h1>")
urls code
from django.contrib import admin
from django.urls import path
from src.pages.views import home_view
urlpatterns = [
path('admin/', admin.site.urls),
path('', home_view, name='home'),
]
and I see this error when I run server
ModuleNotFoundError: No module named 'src'
First you need to understand what an app in Django is compared to a project.
When you register an app django will look in the project root folder when you try to import it.
Your project root is where your manage.py file is. In your case the src folder.
So when you want to import your views module you need to state
from pages.views
rather than
from src.pages.views
I suggest that you read through and follow (by coding it yourself) the Django tutorial to learn more about project structure and creating your own apps with models, urls etc.
I got the same problem, IDE may use red underline but this code is still correct:
from pages.views
I have a begin.html file that I'm trying to access at localhost:8000/begin, but I get the DjangoTemplateDoesNotExist error when trying to access it.
The only thing in that template is
<h1>welcome to my app !</h1>
and it's in the app/template directory.
In the same app directory is my views.py file, which contains
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.shortcuts import render
# Create your views here.
def begin(request):
print("DEBUG STATEMENT")
return render(request, "template/begin.html", {})
The return statement in begin is reached, as both the print statement and the traceback tell me, but Django can't find the template after.
If it's relevant, my urls.py file is
from django.conf.urls import url
from django.contrib import admin
from app.views import begin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^begin/$', begin, name = 'begin')
]
in the project directory.
Since you have not provided the information, i take it as you mean urls.py inside your app. If you have two urls.py you need to redirect from the first urls where django looks to the other one.
from django.conf.urls import include
urlpatterns = [
url(r'^', include('YOURAPPNAME.urls'))
]
In your appdirectory in urls.py write
from . import views //importing views from current directory
urlpatterns = [
url(r'^begin/$' views.begin, name=begin)
]
Another tip, consider using render_to_response when you are using a http response, i know render is newer but since you're using a response i would go with render_to_response in your case, and skip the context.
return render_to_response('YOURAPPNAME'/begin.html)
Check if your template structure like this,
your_app_name
--> **templates**
--> **your_app_name**
--> **'begin.html'**
--> static
--> models.py
--> ........
Then, change your views, like this,
return render(request, "your_app_name/begin.html", {})
Django as default check for the directory under the name "templates", in your app_directory.
When accommodating multiple apps, for easiness templates are kept under the directory with app_name.
From the docs,
It’s possible – and preferable – to organize templates in subdirectories inside each directory containing templates. The convention is to make a subdirectory for each Django app, with subdirectories within those subdirectories as needed.
Do this for your own sanity. Storing all templates in the root level of a single directory gets messy.
When APP_DIRS is True, DjangoTemplates engines look for templates in the templates subdirectory of installed applications. This generic name was kept for backwards-compatibility.
I'm just working through the DjangoBook Chapter7 tutorial on creating forms.
My issue is that I can only import one views.py file from either my books or contact directories. As a result I am only able to see the pages created by whichever views.py file is imported at the time.
I believe I need someway of differentiating between the two directories so that Django does not get confused (due to my likely bad implementation). I have also included an image of my project directory which might be useful to understand the problem.
Contact import working
from mysite.views import hello, current_datetime, hours_ahead, display_meta
from contact import views
#from books import views
urlpatterns = patterns('',
...
#url(r'^search-form/$', views.search_form),
#url(r'^search/$', views.search),
url(r'^contact_form/$', views.contact),
)
Books import working
from mysite.views import hello, current_datetime, hours_ahead, display_meta
#from contact import views
from books import views
urlpatterns = patterns('',
....
url(r'^search-form/$', views.search_form),
url(r'^search/$', views.search),
#url(r'^contact_form/$', views.contact),
)
My Project structure. I am working in Eclipse with Pydev.
Both contact and books import implemented give the below error
AttributeError at /search/
'module' object has no attribute 'search_form'
Any help is as always much appreciated.
you can use an as statement:
from contact import views as contact_views
from books import views as books_views
and the call view:
url(r'^search-form/$', books_views.search_form),
url(r'^search/$', books_views.search),
url(r'^contact_form/$', contact_views.contact),
You should put the urls.py in your application, as detailed in part 3 of the tutorial.
In your application directory create a urls.py,
contact
- __init__.py
- views.py
- models.py
- urls.py
books
- __init__.py
- views.py
- models.py
- urls.py
In book/urls.py, add the following:
from django.conf.urls import patterns, url
from .views import search, search_form
urlpatterns = patterns('',
url(r'search-form/$', search_form, name='search_form'),
)
Then in your main urls.py, add the following:
url(r'^books/', include('book.urls')),
Please go through the official tutorial as the django book website is out dated.
Following the django-rest tutorial
app/urls.py:
from django.conf.urls import url, include
from rest_framework import routers
from app.abbr import views
router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'groups', views.GroupViewSet)
# Wire up our API using automatic URL routing.
# Additionally, we include login URLs for the browsable API.
urlpatterns = [
url(r'^', include(router.urls)),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
Directory structure:
Error:
File "..../app/app/urls.py", line 3, in
from app.abbr import views
ImportError: No module named 'app.abbr'
So, sigh...
It would have been useful if you pointed to the tutorial that showed you to do this.
You should not import from app; that refers to the inner directory containing your urls.py. Just import from abbr.
from abbr import views
And what if you change import like this?
from app.app.abbr import views?
I am considering that you are using django 1.9 +
Try this
from . import views
The root directory folder named App in your case is named after your project name by default when you start a new project via the django-admin startproject command.
you can rename your root directory folder to whatever you want and it won't affect your project.
when in your code are importing from app, it is actually looking inside the 'app' folder containig the 'settings.py' file.
the django-rest tutorial you are following contains an error when they are doing from tutorial.quickstart import views which should be from quickstart import views
so the same goes for you, you should do from abbr import views