Is it possible to write my views in multiple files in Django? - django

The file "views.py" of my Django application has over 4000 lines of code right now, and it is difficult to scroll down every time to a specific view in my text editor.
I would like to divide this file up into multiple ones.
Is this feasible? I imagine that my "urls.py" would change accordingly. Would I still need to keep my "views.py" file?

Unlike models.py, there's nothing magical about the views.py file in Django. A view is simply a function referred to by a URLconf, and that can be in any module at all. Just make sure you refer to it properly, either by giving the full module as text, using the prefix, or importing it:
urls = patterns('',
(r'url1', 'app.views1.my_view1'),
(r'url2', 'app.views2.my_view2')
...
or
from app import views1, views2
urls = patterns('',
(r'url1', views1.my_view1),
(r'url2', views2.my_view2)
...
or even:
urls = patterns('app.views1',
(r'url1', 'my_view1'),
urls += patterns('app.views2',
(r'url2', 'my_view2'),

Sure, you can separate your views. You don't have to change your urls either. Just import the other file, and your original views file will inherit everything in the other file.
#views.py
from app.other_view import *
def your_view(request):
#your code here
#other_view.py
def your_view(request):
#your code here

There's ways to break up the default views.py, models.py, etc. files into modules of their own within the app, but I've found this usually ends up creating more problems than it solves.
In general, if you find the files too weighty, it's probably a better use of your time to refactor your code, instead. Do you really need all those views? Is there any way to simplify the logic? Would you benefit from breaking functionality out into an entirely separate app? These are the questions you should ask.

Related

How to capture a blank slug value in a django url pattern?

I know I can do this with re_path, but is there a way to make a slug optional in a URL? Something like:
path("issues/<int:pk>/<optional-slug:slug>/")
I'm working on upgrading to Django 2.0, and trying to remove as many of my old-style, regex-based url patterns as possible.
The way to do this is to register a "converter". There are some docs about it here:
https://docs.djangoproject.com/en/3.1/topics/http/urls/#registering-custom-path-converters
In this instance, you put something like this in your root urls.py file (not necessarily the one where you want to use it):
from myproject.lib.converters import BlankSlugConverter
register_converter(BlankSlugConverter, "blank-slug")
Then in converters.py, you put:
from django.urls.converters import StringConverter
class BlankSlugConverter(StringConverter):
"""A slug converter that allows blank values
This just swapped out the plus sign in the SlugConverter for an asterisk.
"""
regex = "[-a-zA-Z0-9_]*"
And in your urls.py pattern, you can do:
path("issues/<int:pk>/<blank-slug:slug>/")
And that's it! No need for an additional import or anything in that urls.py file. The register_converter call makes it available everywhere.

Is it possible to give external URLs names in django

I have just started naming my URL patterns in Django, so that if I want to change the URL pattern, I just have to change it in one place. e.g:
url(r'^$', HomeListView.as_view(), name='home'),
And referencing it in my templates like this:
{% url home %}
Is this possible with external links in case they change or I change the a Facebook page link for example. How would this look?
Thanks
One way to do this could be to write an external_url template tag, and have an ExternalURL model that stores them.
This would give you the advantage of being able to have the urls editable without redeploying changed code.
The disadvantage is that there will be database lookups to see those urls. Also, you would need to {% load external_urls %} in templates you want to use it in.
# models.py pseudo-code
class ExternalURL(models.Model):
name = models.CharField(unique=True)
url = models.URLField()
Your template tag might look something like:
# app/templatetags/external_url.py
#library.register()
def external_url(name):
try:
return ExternalURL.objects.get(name=name).url
except ExternalURL.DoesNotExist:
return ''
Another alternative could be to have a Context Processor that stores them all in the context, allowing you to not have to pass them explicitly into views: would be useful if you had several external urls that were used in many places within your system.
def external_urls(request):
return {
'google': 'http://www.google.com/',
# more here
}
The advantages of this is no database lookup, no requirement to load the template tag, but you will need to add it to your settings.CONTEXT_PROCESSORS. Also, you could inspect request to see if the current user may see all the urls.
If its external links, and possibility of the change then you should define it in settings or separate static url file and pass those variable with request context.
urls.py should be recommended to use only for your app specific urls.
In this SO thread you can see how to approach defining constant

What is reverse()?

When I read Django code sometimes, I see in some templates reverse(). I am not quite sure what this is but it is used together with HttpResponseRedirect. How and when is this reverse() supposed to be used?
reverse() | Django documentation
Let's suppose that in your urls.py you have defined this:
url(r'^foo$', some_view, name='url_name'),
In a template you can then refer to this url as:
<!-- django <= 1.4 -->
link which calls some_view
<!-- django >= 1.5 or with {% load url from future %} in your template -->
link which calls some_view
This will be rendered as:
link which calls some_view
Now say you want to do something similar in your views.py - e.g. you are handling some other URL (not /foo/) in some other view (not some_view) and you want to redirect the user to /foo/ (often the case on successful form submission).
You could just do:
return HttpResponseRedirect('/foo/')
But what if you want to change the URL in the future? You'd have to update your urls.py and all references to it in your code. This violates the DRY (Don't Repeat Yourself) principle and the whole idea of editing in one place only - which is something to strive for.
Instead, you can say:
from django.http import HttpResponseRedirect
from django.urls import reverse
return HttpResponseRedirect(reverse('url_name'))
This looks through all URLs defined in your project for the URL defined with the name url_name and returns the actual URL /foo/.
This means that you refer to the URL only by its name attribute - if you want to change the URL itself or the view it refers to you can do this by editing one place only - urls.py.
The existing answers are quite clear. Just in case you do not know why it is called reverse: It takes an input of a url name and gives the actual url, which is reverse to having a url first and then give it a name.
Existing answers did a great job at explaining the what of this reverse() function in Django.
However, I'd hoped that my answer shed a different light at the why: why use reverse() in place of other more straightforward, arguably more pythonic approaches in template-view binding, and what are some legitimate reasons for the popularity of this "redirect via reverse() pattern" in Django routing logic.
One key benefit is the reverse construction of a url, as others have mentioned. Just like how you would use {% url "profile" profile.id %} to generate the url from your app's url configuration file: e.g. path('<int:profile.id>/profile', views.profile, name="profile").
But as the OP have noted, the use of reverse() is also commonly combined with the use of HttpResponseRedirect. But why?
I am not quite sure what this is but it is used together with HttpResponseRedirect. How and when is this reverse() supposed to be used?
Consider the following views.py:
from django.http import HttpResponseRedirect
from django.urls import reverse
def vote(request, question_id):
question = get_object_or_404(Question, pk=question_id)
try:
selected = question.choice_set.get(pk=request.POST['choice'])
except KeyError:
# handle exception
pass
else:
selected.votes += 1
selected.save()
return HttpResponseRedirect(reverse('polls:polls-results',
args=(question.id)
))
And our minimal urls.py:
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
path('<int:question_id>/results/', views.results, name='polls-results'),
path('<int:question_id>/vote/', views.vote, name='polls-vote')
]
In the vote() function, the code in our else block uses reverse along with HttpResponseRedirect in the following pattern:
HttpResponseRedirect(reverse('polls:polls-results',
args=(question.id)
This first and foremost, means we don't have to hardcode the URL (consistent with the DRY principle) but more crucially, reverse() provides an elegant way to construct URL strings by handling values unpacked from the arguments (args=(question.id) is handled by URLConfig). Supposed question has an attribute id which contains the value 5, the URL constructed from the reverse() would then be:
'/polls/5/results/'
In normal template-view binding code, we use HttpResponse() or render() as they typically involve less abstraction: one view function returning one template:
def index(request):
return render(request, 'polls/index.html')
But in many legitimate cases of redirection, we typically care about constructing the URL from a list of parameters. These include cases such as:
HTML form submission through POST request
User login post-validation
Reset password through JSON web tokens
Most of these involve some form of redirection, and a URL constructed through a set of parameters. Hope this adds to the already helpful thread of answers!
This is an old question, but here is something that might help someone.
From the official docs:
Django provides tools for performing URL reversing that match the
different layers where URLs are needed: In templates: Using the url
template tag. In Python code: Using the reverse() function. In higher
level code related to handling of URLs of Django model instances: The
get_absolute_url() method.
Eg. in templates (url tag)
2012 Archive
Eg. in python code (using the reverse function)
return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))
The function supports the dry principle - ensuring that you don't hard code urls throughout your app. A url should be defined in one place, and only one place - your url conf. After that you're really just referencing that info.
Use reverse() to give you the url of a page, given either the path to the view, or the page_name parameter from your url conf. You would use it in cases where it doesn't make sense to do it in the template with {% url 'my-page' %}.
There are lots of possible places you might use this functionality. One place I've found I use it is when redirecting users in a view (often after the successful processing of a form)-
return HttpResponseRedirect(reverse('thanks-we-got-your-form-page'))
You might also use it when writing template tags.
Another time I used reverse() was with model inheritance. I had a ListView on a parent model, but wanted to get from any one of those parent objects to the DetailView of it's associated child object. I attached a get__child_url() function to the parent which identified the existence of a child and returned the url of it's DetailView using reverse().
There is a doc for that
https://docs.djangoproject.com/en/dev/topics/http/urls/#reverse-resolution-of-urls
it can be used to generate an URL for a given view
main advantage is that you do not hard code routes in your code.
The reverse() is used to adhere the django DRY principle i.e if you change the url in future then you can reference that url using reverse(urlname).

django urlpatterns from sql

I am trying to create urlpatterns with sql query, but this will work only for those things that already was in sql table at the moment of server start. If it possible to make django to check for new urls dynamically from database?
I know, this can be done with regular expressions, but they are too greedy, I mean, that i need to make this at root level of my site and regexp will "eat" all matching names and this regexp must be the last of urlpatterns list.
Going on your comment to pyeleven's answer, it seems you have understood the point of urlpatterns. You don't need or want to specify the choices of your section in the urlconf. What you do is grab the value of each section of the url, and pass that as a parameter to the view. So, for example:
(r'^?P<section>\w+)/$', 'my_view')
This will grab urls like /name1/ and /name2/, and pass name1 and name2 to the view as the section parameter. So there's no need to change the code whenever you add a section.
Although this is the nastiest, most un-django-esque thing imaginable, you can get your urls from the db, if you really, really want to:
models.py:
from django.db import models
class Url(models.Model):
name = models.CharField(max_length=20)
urls.py:
from my_app.models import Url
urls = []
for url_object in Url.objects.all():
urls.append(url(url_object.name, 'my_view'))
urlpatterns = patterns('my_app.views', *urls)
VoilĂ . It actually works. Url patterns directly from the db. Please don't do this.
I'm going to go take a shower now.
Have you checked django flatpages?
http://docs.djangoproject.com/en/dev/ref/contrib/flatpages/?from=olddocs
Dynamic url might not be such a good idea, for example a bad url line added dynamically might make the server stop functioning.
Can you elaborate on your goals?

Breaking Django views into seperate directories and files

I'm quite new to Django and I'm enjoying it a lot. I have broken my app's views into different files and placed them in a directory called app/views/(view files).
I have made an __init__.py file in the views directory this has caused me to have to use myproj.app.views.views in my site code. Which of coarse not very digestible.
Any ideas around this. Or is renaming my views directory to something else the way forward.
Thanks.
Just import the views from the other modules in __init__.py.
My user profile app account has three views files: views.py, views_login.py, and views_profile.py. Maybe it's not the cleanest, but it separates the three parts of account pretty well for my needs. My apps/account/urls.py therefore looks like this:
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^foo1$', 'apps.account.views.foo1'),
(r'^foo2$', 'apps.account.views.foo2'),
(r'^bar1$', 'apps.account.views_login.bar1'),
(r'^bar2$', 'apps.account.views_login.bar2'),
(r'^baz1$', 'apps.account.views_profile.baz1'),
(r'^baz2$', 'apps.account.views_profile.baz2'),
)