It seems that the latest Django debug toolbar module has changed to middleware now and requires explicit URL setup to work. With my Django projects I always try to keep settings organised based on environment and not have if settings.DEBUG littered all over the settings files and project.
My settings layout is a general:
common.py (everything in here)
development.py (dev only things here)
production.py (prod only things here)
Is there a way in Django 1.10 I can add to the URLs in the development.py file so that I can keep away from if settings.DEBUG. Or will we be forced to use this method if wanting to use the new version of the debug toolbar?
I just find the below a bit of an anti-pattern
if settings.DEBUG:
import debug_toolbar
urlpatterns += [
url(r'^__debug__/', include(debug_toolbar.urls)),
]
If you do not feel like testing for the value of settings.DEBUG in your URL configuration, you may manage your URLs with a pattern similar to the one you are using for your settings.
Instead of a urls.py file, you would have a urls package with this structure:
urls
├── __init__.py
├── common.py
├── local.py
└── production.py
In your different settings files you would specify which URL conf file to use this way:
# settings/local.py
ROOT_URLCONF = 'urls.local'
# settings/production.py
ROOT_URLCONF = 'urls.production'
The urls/common.py file will expose a urlpattern member containing all the URL patterns common to all configurations which you will import and use in urls/local.py and urls/production.py.
For example:
# urls/common.py
urlpatterns = [
# Put all common URL patterns here
]
# urls/local.py
from .common.py import urlpatterns as common_urlpatterns
urlpatterns = common_urlpatterns + [
url(r'^__debug__/', include(debug_toolbar.urls)),
]
If you want my opinion, this solution feels like overkill given that, as opposed to settings, URL configurations should not differ much between environments.
Related
I know this has been asked multiply times before, but I still don't get it.
How can I create a href-link in one Django app that sends the user to a 2nd app?
This is my setup:
myproject/
manage.py
myproject/
__init__.py
settings.py
urls.py
asgi.py
wsgi.py
app1/
migrations/
templates/
app1/
app1.html
__init__.py
admin.py
apps.py
models.py
tests.py
views.py
app2/
migrations/
templates/
app2/
app2.html
__init__.py
admin.py
apps.py
models.py
tests.py
views.py
myproject/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('app1/', include('app1.urls'), name='app1'),
path('app2/', include('app2.urls'), name='app2'),
]
myproject/settings.py
INSTALLED_APPS = [
'app1.apps.App1Config',
'app2.apps.App2Config',
'django.contrib.admin',
...
]
app1/urls.py (analogous for app2)
from django.urls import path
from . import views
urlpatterns = [
path('', views.app1, name='app1'),
]
app1/views.py (analogous for app2)
from django.template import loader
from django.http import HttpResponse
def app1(request):
template = loader.get_template('app1/app1.html')
return HttpResponse(template.render())
app1/templates/app1/app1.html (analogous for app2)
<p>This is the template of app1.</p>
Go to App2 # doesn't work
Go to App2 # doesn't work
Go to App2 # doesn't work
My problem is that this sends me to the address 127.0.0.1:8000/app1/app2/ which gives me a 404 error. However, I can access app2 via 127.0.0.1:8000/app2/ without a problem.
Edit:
Thanks everyone for your feedback. After going through your suggestions, I made the following changes:
myproject/urls.py:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('app1/', include('app1.urls', namespace='app1')), # ADDED NAMESPACE
path('app2/', include('app2.urls', namespace='app2')), # ADDED NAMESPACE
]
myproject/settings.py: no changes
app1/urls.py: (analogous for app2)
from django.urls import path
from . import views
app_name = 'app1' # THIS WAS MISSING
urlpatterns = [
path('', views.app1, name='app1'),
]
app1/views.py: no changes
app1/templates/app1/app1.html: (analogous for app2)
<p>This is the template of app1.</p>
Go to App2 # AS SUGGESTED BY seif
Now it works.
in your template and views try not to hardcode the url of href instead use the {%url ''%}
which will be {%url 'namespace:urlname'%}
<p>This is the template of app1.</p>
Go to App2
this give you flexibility to change the path in your urls and not to worry about changing it at all your templates and views you can read more here https://docs.djangoproject.com/en/3.1/topics/http/urls/#reverse-resolution-of-urls
your href link doesn't go to the .html file in templates, templates are just for UI, and barely have a say in how you project gets routed, infact it depends on you to configure. instead it should go to the url specified in your url file,
so say your bases url is
path('app1/', include('app1.urls'), name='app1')
for one of your app it will be
App 1
if you have other links under app1 url file, it will then be
A link under App 1
example.com here, could be localhost:8000 or just localhost with any port, depending on the port your django project runs one.
then as for this,
from django.template import loader
from django.http import HttpResponse
def app1(request):
template = loader.get_template('app1/app1.html')
return HttpResponse(template.render())
I will suggest you do something like this instead
from django.shortcuts import render
from django.http import HttpResponse, HttpRequest
def app1(request,slug=None):
return render(request,'app1/app1.html',{})
#path to the template folder, under templates, depends on your configuration though
Kindly read more on templates configuration and routing in Django,but this should give a jumpstart.
Cheers
When you input "127.0.0.1:8000/app1/app2/", django will recieve "app1/app2/" and work like below(not accurate):
1.compare app1/ to every element in urlpatterns of myproject/urls.py
so, app1/ will be found.
2.compare app2/ to every element in urlpatterns of app1.urls
there's nothing will be found, because there is only a "" in urlpatterns of app1.urls.
so you get a 404 page.
if you input "127.0.0.1:8000/app2/", in step 2, "" equals to "",
fuction views.app2 executes, and you get a correct page.
I suggest you read the django's tutorials in official site.
https://docs.djangoproject.com/en/3.1/intro/tutorial01/
I have multiple app based django project and within some apps url scheme getting complicated due to number of models. Hence I'm looking a way to make a hierarchical url structure within the app.
In my project's urls file I do the following.
from order import urls as order_urls
In the order app I have urls.py and urls directory which contains separate url patterns for each model as follows.
In the app's urls.py file I import the model's urls as follows.
from urls import rental as rental_urls
urlpatterns = [
url(r'^rental-request/', include(rental_urls)),
]
This gives me the error: ModuleNotFoundError: No module named 'urls'
If I put __init__.py it gives me circular import error.
I'm not sure this is the correct way/possible for my requirement. Anyone could explain the correct way to achieve it?
Having a folder called urls (with an __init__.py file) as well as a file urls.py in the same folder will probably cause trouble to load the module order.urls from anywhere in your project. How does Python will know which file must be loaded ?
Consider this structure:
├── main.py
├── urls
│ └── __init__.py
└── urls.py
And this content for each file:
# urls/__init__.py
urlpatterns = "I'm in folder"
# urls.py
urlpatterns = "I'm in file"
# main.py
import urls
print(urls.urlpatterns)
When you run main.py, the result is:
% python main.py
I'm in folder
Possible solutions :
You may delete the urls.py and move its content to urls/__init__.py, or rename the folder urls to avoid conflicts and updates imports accordingly (in urls.py)
I started with a django app and tried displaying an image in the home page. But the image is not getting displayed.
My settings.py:
MEDIA_ROOT = os.path.join(BASE_DIR,"media")
MEDIA_URL = "/media/"
My urls.py:
urlpatterns = patterns('',
# Examples:
# url(r'^$', 'myapp.views.home', name='home'),
# url(r'^blog/', include('blog.urls')),
url(r'^admin/', include(admin.site.urls)),
url(r'',include('users.urls')),
)
urlpatterns += staticfiles_urlpatterns()
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
My home.html:
<html>
<head>
<title>MY SITE</title>
</head>
<body>
<img src="/media/image/myimage.jpg" alt="my image"/>
Welcome to my site
</body>
</html>
I get the text my image displayed instead of the image
ok, so I set up a simple 'paired-down' working example of this so no moving pieces were missing. Some Notes:
I used django 1.6
If you want to use a 'scale-able' delivery of static images you will want to follow
the django-1.6 staticfiles documentation which is what this example provides.
This means that you need to hack-n-slash your MEDIA references. ( MEDIA is really meant for file upload's) and you dont need to fool with the staticfiles_urlpatterns in your urls.py file. As you get this behavior out-of-the box when you add 'django.contrib.staticfiles' to your settings.py
Overview: Here is what your file tree-layout will look like in django 1.6, and the file structure that I am referencing in this answer.
├── djproj
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ ├── wsgi.py
├── manage.py
└─── myapp
├── admin.py
├── __init__.py
├── models.py
├── static
│ └── myapp
│ └── myimage.jpg
├── templates
│ └── index.html
├── tests.py
└── views.py
Step 1: Make sure that django.contrib.staticfiles is included in your INSTALLED_APPS.
Step 2: In your settings file, define STATIC_URL, for example:
STATIC_URL = '/static/'
Step 3: change your home.html to look like this ( I used index.html in my example )
[ PROJECT_HOME/myapp/templates/index.html ]
<html>
<head>
<title>MY SITE</title>
</head>
<body>
{% load staticfiles %}
<img src="{% static "myapp/myimage.jpg" %}" alt="My image"/>
Welcome to my site
</body>
</html>
Make sure to read the django-1.6 staticfiles documentation related to STATICFILES_STORAGE so you understand what these template tags are buying you. Hint: python manage.py collectstatic
Step 4: ( you may have already done this, but I did not see it) Make sure that TEMPLETE_DIRS is defined in your settings.py and includes your home.html ( key here is that django's template engine needs to be serving this as we will be using some template tags)
[ PROJECT_HOME/djproj/settings.py ]
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
BASE_DIR + '../myapp/templates',
)
Step 5: build a view that renders your home.html page.
[ PROJECT_HOME/myapp/views.py ]
from django.shortcuts import render_to_response
def index( request ):
return render_to_response('index.html')
Since this is a bit convoluted, and there are several moving pieces here: here is a changeset that shows the complete 'changes'
You can of-coarse pull the entire github project if any of this is confusing.
django-staticfiles-setupexample
Final Note: STATIC files were not always handled this way in django. The MEDIA dir used to be the settings attr you were after. So this answer is for Django 1.6 ( staticfiles were added in django version 1.3)( the directory layout was changed in django 1.5).
You can ( as you were trying to do) hardwire your media dirs to the STATIC defines. Altho I do-not recommend this. Which is why I did not describe how to do it this way.
You are adding the media urls too late in the list. Django will try to match each urlpattern in succession, stopping when it gets to the first one. In this case, it matches on r'' and doesn't get to the static files or the media urls.
You may be able to put each pattern in the single call to patterns(), instead of using +=. That would be the cleanest, but I can't test it here. A sure-fire way to do it would be to pull the "users.urls" line out and add it later, like so:
urlpatterns = patterns('',
url(r'^admin/', include(admin.site.urls)),
)
urlpatterns += staticfiles_urlpatterns()
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += url(r'',include('users.urls'))
I'd recommend you set DEBUG = TEMPLATE_DEBUG = True and request the image URL directly.
You'll get Django debug output either showing that the URL can't be matched or the file path it's actually looking for.
The settings look generally correct although you've not shared BASE_DIR which is important in this case.
I had been struggling with the issue for like an entire day yesterday... I finally gave up and moved on creating my site without worrying about the images. Then today I decided to check the responsiveness of the site. I found out that my URLs were okay since I had strictly been following the documentation and best practices. The chrome console was saying:
Failed to load resource: net::ERR_BLOCKED_BY_CLIENT
The issue was with HTTP Referral Policy. Check them out. So after doing some research, this helped a lot, I found out that AdBlock was blocking my referred images. Apparently, my /media/ path was flagged in one of their regex patterns, deciding that my images were redirections to Ads. The ironic thing is that my website is about ads... so it must have heavily factored in, as my site has words like 'ad' in its url patterns. Long story short, I disabled AdBlock and my images now render. So I think it might be worth considering that even with best practices in your Django code, such an error could be caused by something with your browser!
Im certain that this is something simply that Im overlooking but Im too irritated to figure it out alone so thanks in advance.
Project Directory Structure
*UPDATED*
myproject/
manage.py
myproject/
apps/
geo/
urls.py
settings.py
urls.py
urls.py
from django.conf import settings
from django.conf.urls.defaults import *
from django.views.generic.simple import direct_to_template
from django.contrib.gis import admin
admin.autodiscover()
from pinax.apps.account.openid_consumer import PinaxConsumer
handler500 = "pinax.views.server_error"
urlpatterns = patterns("",
url(r"^$", direct_to_template, {'template' : 'home.html' }, name="home"),
url(r"^admin/invite_user/$", "pinax.apps.signup_codes.views.admin_invite_user", name="admin_invite_user"),
url(r"^admin/", include(admin.site.urls)),
url(r"^about/", include("apps.about.urls")),
url(r"^account/", include("pinax.apps.account.urls")),
url(r"^openid/", include(PinaxConsumer().urls)),
url(r"^profiles/", include("idios.urls")),
url(r"^notices/", include("notification.urls")),
url(r"^announcements/", include("announcements.urls")),
url(r"^products/", include("products.urls")),
url(r"^locate/", include("geo.urls")),
url(r"^sectors/", include("sectors.urls")),
)
if settings.SERVE_MEDIA:
urlpatterns += patterns("",
url(r"", include("staticfiles.urls")),
)
settings.py
INSTALLED_APPS = [
# project
"tulsa-site.apps.about",
"tulsa-site.apps.profiles",
"tulsa-site.apps.geo",
"tulsa-site.apps.sectors",
]
When I go to the url path "http://127.0.0.1:8000/locate/" is receive the error message: I recieve the exception value "No module named geo.urls." What am I missing?
include("geo.urls") tells Django to look for geo.urls relative to the manage.py file. So its essentially looking for this file:
myproject/
manage.py
myproject/
apps/
settings.py
urls.py
geo/
urls.py <- this file
That is sort of the new directory structure starting with Django 1.4 which encourages to have apps independent of the Django project. However if you still follow the old layout where the apps folders are within the project folder, then you have to change your imports to reflect that:
include("myproject.geo.urls")
EDIT
Following your updated layout:
include("myproject.apps.geo.urls")
url(r"^locate/", include("tulsa-site.apps.geo.urls"))
I am working on a django project which will contain several apps. Each app will have their own set of models and views.
Should each app also define their own url's with a urls.py or maybe a function. What is the best practice for defining urls of apps within a django project, and integrating these urls with the main urls.py (root url conf) ?
It depends. If you're dealing with a tiny website with one app, you can keep all the expressions in the same urls.py.
However, when you're dealing with a more complicated site with truly separate apps, I prefer the following structure:
myapp
admin.py
forms.py
models.py
urls.py
views.py
manage.py
settings.py
urls.py
Don't forget each folder needs it's own __ init__.py
# urls.py
from django.conf.urls.defaults import *
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
# Notice the expression does not end in $,
# that happens at the myapp/url.py level
(r'^myapp/', include('myproject.myapp.urls')),
)
# myapp/urls.py
from django.conf.urls.defaults import *
urlpatterns = patterns('myproject.myapp.views',
(r'^$', 'default_view',
(r'^something/$', 'something_view',
)
You also may want to look at Class-based Generic Views
If your app is going to display anything to the user with its own url pattern, it should probably have its own urls.py file. So in your base urls file, you'd have something in your urlpatterns like url(r'', include('path.to.app.urls')). Then your app's urls.py file would have a pattern like url(r'^$', 'path.to.app.views.view').
If the app is mostly self-contained and having its own place in the URL hierarchy makes sense, then it should have its own urls.py. But even if it does exist, it's still only a guideline to the project developer unless include() is used to graft it into the project URLconf.