How to create hierarchical urls within django app? - django

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)

Related

Serving static files in Flask production

I have the static folder in my app folder and that's where I have js, css, images etc. folders.
I reference them like this in my templates:
<script src="/static/js/main.js"></script>
and it works locally. But, when the app is published to production, I get a 404 for all static files. I'm new to flask so I guess I'm serving them wrong.
I don't have the static folder set as a designated static files folder anywhere in the app - is it done automatically if it's called 'static' or do I need to set it in code?
My project structure:
app/
├── static/
│ └── js/
| |__ css/
├── templates/
│ └── index.html
└── __init__.py
application.py
application.py:
from app import create_app
application = create_app()
init.py:
from flask import Flask
from config import BaseConfig
def create_app():
server = Flask(__name__)
server.config.from_object(BaseConfig) # this is just for the secret key
return server
Flask automatically adds a static view that takes a path relative to the $YOUR_APP/static directory and serves it.
Typically you would include your js/css files in your templates like so:
{{ url_for('static', filename='main.js') }}
First part of the solution was Bert's answer above which described how to correctly reference assets from the templates.
The other part I was missing was this:
server = Flask(__name__, static_url_path="", static_folder="static")
instead of what I had before:
server = Flask(__name__)
Adding static_url_path and static_folder fixed the issue for me.

Overriding/Adding to Django URLs in settings rather than urls

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.

Same functions in different views - Django

I have started learning Django recently and am following the code examples given in the tutorial of the Django site. Accordingly, I have created a site 'mysite' and an app 'books' in that site. Consequently, there are two 'views.py' files in the resultant directory structure - one in the 'mysite' folder and one in 'books' folder and there's only one 'urls.py' file - in the 'mysite' folder only. My question is the following - how do I avoid name conflicts for the functions that I create in the two 'views.py' files? If there are two functions with the same name in both the files, how does Django resolve which function to call for a given URL pattern in 'urls.py' file?
The following is my directory structure:
C:.
│ manage.py
│
├───books
│ admin.py
│ admin.pyc
│ models.py
│ models.pyc
│ tests.py
│ views.py
│ views.pyc
│ __init__.py
│ __init__.pyc
│
└───mysite
base.html
base_blog.html
base_welcome.html
currdate.html
settings.py
settings.pyc
urls.py
urls.pyc
views.py
views.pyc
wsgi.py
wsgi.pyc
__init__.py
__init__.pyc
An additional and related question - if I have multiple projects (like 'mysite') and different apps in those projects, how do I differentiate the URLs across the projects? I mean, currently, the URL http://127.0.0.1:8000/hello is mapped to a view function in 'mysite' project. What if I now have one more project, say 'mynewsite', how would Django resolve the URL http://127.0.0.1:8000/hello to the view function of 'mynewsite'? I hope my question is clear.
Thanks,
Rakesh.
In python you can import libraries (in this case file like views.py) one of them would be causing name conflicts you are talking about, namely
from books.views import my_view
from mysite.views import my_view
in that case, my_view will simply be overwritten. However, you can also do the following
import books.views
import mysite.views
In that case, to access the imported view, you will have to use full path, i. e. books.views.my_view, therefore there is no name conflict.
As for your other question, consider the following urls.py contents:
urlpatterns = patterns('',
url(r'^$', mysite.views.my_view, name='index'),
You can replace it with
urlpatterns = patterns('',
url(r'^$', books.views.my_view, name='index'),

django not displaying image

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!

ImportError After Moving App to Nested Folder

My application was working fine when I wanted to see whether I could organize my project in a better way. I read through this tutorial on structuring a django project.
Before my project structure was as follows:
camucamu
books
admin.py
models.py
views.py
__init__.py
static
templates
urls.py
views.py
settings.py
wsgi.py
__init__.py
What I wanted to do was move the books app into an apps folder. Thus I did that and changed the project structure to the following:
camucamu
apps
books
admin.py
models.py
views.py
__init__.py
static
templates
urls.py
views.py
settings.py
wsgi.py
__init__.py
I then changed the imports in views.py and admin.py
from books.models to apps.books.models.
I also changed INSTALLED_APPS in settings.py from books to apps.books.
When I then tried to run syncdb, I get the following error:
raise ImproperlyConfigured('ImportError %s: %s' % (app, e.args[0]))
django.core.exceptions.ImproperlyConfigured: ImportError apps.books: No module named apps.books
What am I messing up here so it can't find my app anymore?
Your apps folder does not have an __init__.py file so it cannot be recognized as a python module
I got the same error, following the same guide, as the last point of the following list was not cited. Make sure you performed the following changes:
Create a blank __init__.py file inside the apps folder (needed for python to recognize it as a package)
Update the import statements wherever you refer to an external app:
from projectname.apps.appname.models import YourModel, YourOtherModel
Inside settings.py edit INSTALLED_APPS such that it looks like this:
INSTALLED_APPS = (
...
# apps
'projectname.apps.appname1',
'projectname.apps.appname2',
)
This one is not specified in the guide: In all your urls.py files, update the urlpatterns!
BEFORE:
# client views
urlpatterns += patterns('appname',
...
)
AFTER:
# client views
urlpatterns += patterns('projectname.apps.appname',
...
)
Finally remember to update your changes by calling python manage.py syncdb
Hope that helped.