Django - split views into separate files while maintaining views.py - django

Hopefully this is a simple noob question. I'm working on my first large(ish) Django project. The first engineer on the project was following the default Django code layout. As things have grown we've recently split out models into their own directory with one file per model.
It's time to start doing the same for views. However, I don't want/need to do it all in one go. I'd like to just start moving things out of the default views.py one by one as I work on them. However, I'm having difficulty getting urls.py to work with both a views directory and views.py
Is this just going to cause a naming collision when I try to import 'views' in my urls.py file? Is the simple answer just to call "views" something else while I make the transition? Or just bite the bullet and do it all at once?

The direct answer is yes, you have a python naming collision. See for example Python Import Class With Same Name as Directory
You don't need to do it all as once though -- you can simply rename / move your views.py file or your new views directory. Moving the new directory would likely be easiest, then you won't have change your existing url routes.
There's nothing special about views.py files, as long as your urls.py points to the appropriate function, you can place them anywhere, and call them anything.

I recommend creating feature sub-directories within your app folder on your Django project. Then, simply import them from the new directory using the app.views namespace by using the from ... import * incantation. This will import any views without the module name prepended (e.g. what would normally be referenced by app_name.views.feature_one.view_class becomes app_name.views.view_class like you want). See below:
# app_name/views.py
from feature_one.views import *
from feature_two.views import *
# ... copy views from here
# new file: app_name/feature_one/views.py
# ... paste some views here
# new file: app_name/feature_two/views.py
# ... paste some other views here
# new file: app_name/feature_one/__init__.py
# ... this file can be blank. required for importing "feature_one" like a module
# new file: app_name/feature_two/__init__.py
# ... this file can be blank. required for importing "feature_two" like a module
Now, while your views will be spread across sub-directories, they are all imported with the same names into app_name.views so you can still reference the same names in urls.py despite having moved some views to other files.

Since you have divided models into their sub-apps, you can define urls specific to these sub-apps in the created sub directories and set up a url hierarchy. This is how your default urls.py will look like:
from django.conf.urls import include, patterns, url
urlpatterns = patterns('',
# ... snip ...
url(r'^comments/', include('your_website.comments.urls')),
url(r'^community/', include('your_website.community.urls')),
url(r'^contact/', include('your_website.contact.urls')),
# ... snip ...
)
where comments, community and contact are your newly created sub-apps/sub-directories. More info on how the url dispatcher works, here

Related

Django views and urls - can't runserver

I'm learning django and having issues with implementing this code below:
from django.urls import path
from . import views
urlpatterns = [
path('members/', views.members, name='members'),
]
The code above is stored in a urls.py file I created in an app folder as directed by the tutorial guide. However when I try to run it on the browser I get this message:
The included URLconf '<module 'members.urls' from 'C:\Users\Chinasaokwu\Desktop\storefront\try-django\my_app\members\urls.py'>' does not appear to have any patterns in it. If you see the 'urlpatterns' variable with valid patterns in the file then the issue is probably caused by a circular import.
I don't know what to do here. I'm new to django.
It's w3schools.com that I am using as a guide
I'm still learning how views and urls work since I'm new to django but I understand that views are functions that take and return https requests/response, and that urls are used to implement views.

Why can you import UpdateView in "multiple ways"

Why do both of the following ways of importing UpdateView work?:
1. from django.views.generic import UpdateView
2. from django.views.generic.edit import UpdateView
I was assuming 2. was the correct way, and 1. would not work, but from testing both work.
What you see here is quite common (at least in some Python packages). If you define a .py file, that acts as a module. For example the django.views.generic.edit module maps on the django/views/generic/edit.py file [GitHub].
A directory is a Python module as well (due to the __init__.py file), but it does not contain any elements by default, hence that would mean that django.views.generic would be empty.
If we take a look at the django/views/generic/__init__.py file [GitHub], we see:
from django.views.generic.base import RedirectView, TemplateView, View
# ...
from django.views.generic.edit import (
CreateView, DeleteView, FormView, UpdateView,
)
# ...
__all__ = [
'View', 'TemplateView', 'RedirectView', 'ArchiveIndexView',
'YearArchiveView', 'MonthArchiveView', 'WeekArchiveView', 'DayArchiveView',
'TodayArchiveView', 'DateDetailView', 'DetailView', 'FormView',
'CreateView', 'UpdateView', 'DeleteView', 'ListView', 'GenericViewError',
]
# ...
This thus imports the UpdateView from the generic.py file, and re-exports the class.
You thus can reference to the class in two ways: through the module defined by the generic.py file, or through the re-export of the module of the directory, specified through the __init__.py file.
This is typically done to export a portion of the items that are defined in the files, export these under a more convenient name, or provide some extra classes at the module level (for example the __init__.py file defines the GenericViewError error).
This directory-level module thus "groups" interesting views together. For example the FormMixin is not exported at this level. The __init__.py here groups (popular) class-based views together, whereas the mixins, that are typically used to define such generic views, are still specific to a file.

Universally usable files for django project - Django

I am making a django project and within the project I have 3 different apps. registration, users, groups. I dont want to have to print all of the import statements in the views.py file for each app. I also dont want to have to retype any of the methods for functions in each of the views.py file for small functions like generatingRandomNumbers. Is there a way to create a single file within the project directory that has all of the import statements or all of the methods that i can call at the beginning of each views.py file....
Also where would i put the file if possible, and how can i call the fill with all of the import statements at the top of each of the views.py file so i dont have to keep retyping all of it...
Here is my current directory:
Another question is how can i setup the urls in a way that i can redirect to any url within the project no matter which app it is localated in... Django documentation does not explain any of this at all...
an example would be a view in the registration app redirects to a url in the users app.. Here is what i have:
registration -> urls.py
urlpatterns = [
url(r'^$', views.Signup, name='user_signup'),
url(r'^setup_profile/$', views.ProfileSetup, name='profile_setup'),
]
users -> urls.py
urlpatterns = [
url(r'^home/$', views.UserHome, name='home_page'),
]
redirect statement from the registrations -> views.py file:
return redirect('user_home')

How to change default URL in Django Photologue

Is it possible to change default URL in Photologue? For example this URL
url(r'^photo/(?P<slug>[\-\d\w]+)/$', PhotoDetailView.as_view(), name='pl-photo')
I want to change on
url(r'^pictures/(?P<slug>[\-\d\w]+)/$', PhotoDetailView.as_view(), name='pl-photo')
In documentation I find only example how to override URL.
This is not a very elegant solution, but it will work:
In your project's urls.py file, you have already included Photologue's urls:
url(r'^photologue/', include('photologue.urls', namespace='photologue')),
What you can do is write a custom urls.py file, in which you copy-and-paste Photologue's urls.py file - but then you change 'photo' to be pictures.
Note: remember to change the import at the top to from photologue.views import ....
Then include your custom urls.py file in place of including the standard Photologue urls.py file.
Note: it's not a very elegant solution because you are duplicating code - and if you ever upgrade the Photologue version used in your project, you will need to check if the urls.py file has changed.

Why are the Django project URLs not all available to the Django test client?

I've been trying to add the django-lean app to my project.
The django-lean app is not located in the project I'm working on, it is on the PYTHONPATH.
I have not been able to get the django-lean tests to pass.
It seems the issue is that the TestCase defines a value for urls:
urls = 'django_lean.experiments.tests.urls'
As best as I can tell, the tests are only getting the urls located # 'django_lean.experiments.tests.urls', but not
the urls from the rest of the project.
This is causing error messages like:
NoReverseMatch: Reverse for 'index' with arguments '()' and keyword arguments '{}' not found.
These are triggered by {% url %} template tags in the project.
How can I make sure that the all the urls of the project are available for the tests?
EDIT:
Someone showed me a script to print the visible URLs:
import urls
def show_urls(urllist, depth=0):
for entry in urllist:
print " " * depth, entry.regex.pattern
if hasattr(entry, 'url_patterns'):
show_urls(entry.url_patterns, depth + 1)
I called this script from ipdb, this was the output:
ipdb> import urls
ipdb> show_urls(urls.urlpatterns)
^test-experiment/(?P<experiment_name>.*)$
^test-clientsideexperiment/(?P<experiment_name>.*)$
^admin/
^(?P<experiment_name>.+)/$
^$
^main-app/
^goal/(?P<goal_name>.*)$
^confirm_human/$
This corresponds to the urls located # 'django_lean.experiments.tests.urls'
urlpatterns = patterns('django_lean.experiments.tests.views',
url(r'^test-experiment/(?P<experiment_name>.*)$', 'experiment_test'),
url(r'^test-clientsideexperiment/(?P<experiment_name>.*)$', 'clientsideexperiment_test'))
urlpatterns += patterns('',
url(r'^admin/', include('django_lean.experiments.admin_urls')),
url(r'^main-app/', include('django_lean.experiments.urls')),
The issue that I'm having is that my tests all fail because of the named urls from other apps in the project are called by URL template tags are not accessible to the tests.
I'm running Python 2.7 with Django 1.2.1
The solution was pretty simple. Just import the URLs from the main project into the urls.py for the app.
from forum.urls import urlpatterns
or for a more generic solution:
from settings import ROOT_URLCONF as project_urls
urlpatterns = __import__('forum.urls').urls.urlpatterns
To list all the url patterns your django knows you can use the answer suggested here.
Run this from your tests and print/log the output.
Just note that its better to explicitly state where to import the urls from like
from myproject import urls
because you probably have some other modules containing urls files.