Django unable to split views

607 Views Asked by At

I have recently started adopting Python and the Django framework. There are numerous things that are awesome about it and also numerous things that I really hate. One of those things is having one views.py file per Django app, which I find just really unpractical. So I decided to split my views into multiple files. It has proven to be much more difficult than I originally thought.

I followed lot of questions and tutorials but none of them work. I should add that I am using Python 3.4 on ArchLinux and Django 1.8.

My original setup (I have simplified it, there actually are more view functions):

views.py

def entries(request):
    ...

def delete_entry(request, id):
    ...

def categories(request):
    ...

def delete_category(request, id):
    ...

urls.py

from django.conf.urls import patterns, url
from transactions import views

urlpatterns = patterns('',
    url(r'^entries$', views.entries, name='entries'),
    url(r'^delete_entry(?:/(?P<id>[0-9]+)/)?$', views.delete_entry, name='delete_entry'),

    url(r'^categories$', views.categories, name='categories'),
    url(r'^delete_category(?:/(?P<id>[0-9]+)/)?$', views.delete_category, name='delete_category'),
)

My desired state is:

views folder containing entries.py and categories.py:

Edit: There is an init.py file in the views folder.

entries.py

def entries(request):
    ...

def delete_entry(request, id):
    ...

categories.py

same logic as above

urls.py that I am using with this setup:

from transactions.views import entries, categories
from django.conf.urls import patterns, url

urlpatterns = patterns('',
    url(r'^entries$', entries.entries, name='entries'),
    url(r'^delete_entry(?:/(?P<id>[0-9]+)/)?$', entries.delete_entry, name='delete_entry'),

    url(r'^categories$', categories.categories, name='categories'),
    url(r'^delete_category(?:/(?P<id>[0-9]+)/)?$', categories.delete_category, name='delete_category'),
)

when I try to manage.py runserver, an ViewDoesNotExists error is raised with Could not import 'transactions.views.entries'. View is not callable. message. When I try to dump entries.entries in urls.py, it actually is a function, same as with the original setup.

So far I have tried numerous suggestions from this question such as import variants, hacking __init.py__ in views folder, using views folder without __init__.py, but the results are pretty much the same or there are import errors.

3

There are 3 best solutions below

0
j0hny On BEST ANSWER

I figured it out after some time and found out that the fault is between my keyboard and chair :-). The problem is not with the urls.py in my transactions app, but in the "main" app django creates for you where you import the urls.py from other apps. I have left there one url for transactions.views.entries and forgot it there, so it was complaining for this file and I haven't seen it.

For anyone having similar issues - check yout main urls.py too!

Thanks everyone for their answers and comments.

2
zxzak On

There is nothing like "one views.py file per Django app". The startapp command simply creates a views.py file for you, just for the sake of putting the code somewhere. A view function can live anywhere as long as it is on your Python path. What this means is that it has to be importable so as the comments suggest you might be missing __init__.py in your views folder.

Writing views

A view function, or view for short, is simply a Python function that takes a Web request and returns a Web response. This response can be the HTML contents of a Web page, or a redirect, or a 404 error, or an XML document, or an image . . . or anything, really. The view itself contains whatever arbitrary logic is necessary to return that response. This code can live anywhere you want, as long as it’s on your Python path. There’s no other requirement–no “magic,” so to speak. For the sake of putting the code somewhere, the convention is to put views in a file called views.py, placed in your project or application directory.

2
JRajan On

Instead of importing the views into the urls.py, you could try something like this.

from django.conf.urls import patterns, url

urlpatterns = patterns('',
    url(r'^entries$', 'transactions.views.entries.entries', name='entries'),
    url(r'^delete_entry(?:/(?P<id>[0-9]+)/)?$', 'transactions.views.entries.delete_entry', name='delete_entry'),

    url(r'^categories$', 'transactions.views.categories.categories', name='categories'),
    url(r'^delete_category(?:/(?P<id>[0-9]+)/)?$', 'transactions.views.categories.delete_category', name='delete_category'),
)