like exposed here, one can set a MEDIA_URL in settings.py (for example i'm pointing to Amazon S3) and serve the files in the view via {{ MEDIA_URL }}. Since MEDIA_URL is not automatically in the context, one have to manually add it to the context, so, for example, the following works:
#views.py
from django.shortcuts import render_to_response
from django.template import RequestContext
def test(request):
return render_to_response('test.html', {}, context_instance=RequestContext(request))
This means that in each view.py file i have to add from django.template import RequestContext and in each response i have to explicitly specify context_instance=RequestContext(request).
Is there a way to automatically (DRY) add MEDIA_URL to the default context? Thanks in advance.
There is a generic view for this use :
direct_to_template(request, template, extra_context=None, mimetype=None, **kwargs)
It is not well documented (in my opinion : it doesn't tell that it uses a RequestContext), so I advise you to check out the implementation :
http://code.djangoproject.com/browser/django/trunk/django/views/generic/simple.py
I think it is what you are looking for ...
Add "django.core.context_processors.media" to your TEMPLATE_CONTEXT_PROCESSORS in the settings file.
Related
I am brand new to Django and following along with the tutorial. I'm hoping this is just an obvious mistake, but I am unable to get my web browser to render anything written in the Django template language and I can't figure out why.
Here is my directory structure for some context: https://imgur.com/dGNIiDa
project/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('budget/', include('budget.urls')),
path('admin/', admin.site.urls)
]
budget/urls.py:
from django.urls import path
from . import views
urlpatterns = [
path('<int:account_id>/', views.get_account, name='detail'),
]
budget/views.py:
from django.shortcuts import render
from django.http import HttpResponse
from budget.models import Account, Transaction
def get_account(request, account_id):
accts = Account.objects.filter(pk=account_id)
context = {"test": accts}
return render(request, 'budget/detail.html', context)
budget/templates/budget/detail.html:
<p>This is a {{ context.test }}</p>
When I visit localhost:8000/budget/1 in my browser this is all that is rendered: https://imgur.com/j2Vh0yb
Clearly Django is finding the template file and sending it to the browser, but anything that is written inside of {} does not get recognized or rendered at all. I've followed along exactly with the tutorial and I have no idea why it's not working. Any ideas?
You don't need context in the expression in the template; all that you put in the context are "globals" in the template, so try
<p>This is a {{ test }}</p>
instead.
Django's template engine has the unfortunate property of being silent about nonexisting properties, so it's hard to debug stuff like this.
I'm learning Django on my own and I can't seem to get a clue of where I implement a regular Python class. What I mean is, I don't know where do the Python classes I write go. Like they go in a separate file and then are imported to the views.py or are the classes implemented inside the views.py file?
Example I want to implement a Class Alphabet, should I do this in a separate file inside the module or just implement the functions inside the views.py file?
I don't know where do the Python classes I write go. Like they go in
a separate file and then are imported to the views.py.
Example I want to implement a Class Alphabet.
It's just a matter of getting your import statement correct:
django_proj1/
django_proj1/
myapp/
myclasses.py
views.py
Then in your view:
#myapp/views.py:
from myapp.myclasses import Alphabet
Or, you could do it like this:
django_proj1/
django_proj1/
myclasses.py
myapp/
views.py
And in your view:
#myapp/views.py:
from django_proj1.myclasses import Alphabet
Response to comment:
And after I successfully imported my class, how do I pass the
attributes to an HTML template?
The following is straight from the official django tutorial.
myapp/views.py:
from django.shortcuts import render
from django.http import HttpResponse
from myapp.myclasses import Alphabet #<*** Import your class.
from django.template import RequestContext, loader #<*** Import stuff for the template.
# Create your views here.
def index(request):
alph = Alphabet()
result = alph.change('hello') #Your class produces some result here.
template = loader.get_template("myapp/index.html")
context = RequestContext(request, {
'x' : result #<*** Make a variable named x available in your template.
})
return HttpResponse(template.render(context))
The directory structure looks like this:
django_proj1/
django_proj1/
myapp/
myclasses.py
views.py
templates/ <***Create this directory
myapp/ <***Create this directory
index.html <***Create this file
myapp/templates/myapp/index.html:
{% if x %}
<div>The result you requested was: {{x}}</div>
{% else %}
<div>Sorry, couldn't get the result.</div>
{% endif %}
myapp/myclasses.py:
class Alphabet:
def change(self, word):
return word + 'Z'
Start the server:
.../my_django_projects/django_proj1$ python manage.py runserver
url in your browser:
http://localhost:8000/myapp/
You should see:
The result you requested was: helloZ
If you comment out the following line in myapp/views.py:
context = RequestContext(request, {
#'x' : result #<*** Make a variable named x available in your template.
})
Then the template will send the else portion of index.html to the browser:
Sorry, couldn't get the result.
django_proj1/django_proj1/urls.py:
from django.conf.urls import patterns, include, url
from django.contrib import admin
from . import views
urlpatterns = patterns('',
# Examples:
# url(r'^$', 'dj1.views.home', name='home'),
# url(r'^blog/', include('blog.urls')),
url(r'^admin/', include(admin.site.urls)),
url(r'^myapp/', include('myapp.urls')),
)
django_proj1/myapp/urls.py:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
]
Django is just Python at the end of the day.
You can create new modules anywhere in your project, and import them into your views, models, urls, etc. This is often how you'd organize general utils (utils.py).
You can deliver data to your views in a few ways, for instance:
from your_module import some_object
class MyView(TemplateView):
template_name = 'some_template.html'
def get_context_data(self, **kwargs):
context = super(MyView, self).get_context_data(**kwargs)
context['my_data'] = some_object.some_method()
return context
And in some_template.html: {{ my_data }}
It depends on the scope of the Alphabet class. If it is a utility class then I would suggest to put in a utils.py file, for example. But it is perfectly fine to have classes in the views.py file, mainly those dealing with UI processing. Up to you.
Distinct to similar frameworks, you can put your Python code anywhere in your project, provided you can reference them later by their import path (model classes are partially an exception, though):
Applications are referenced by their import path (or an AppConfig import path). Although there's some magic involving test.py and models.py, most of the times the import / reference is quite explicit.
Views are referenced by urls.py files, but imported as regular python import path.
Middlewares are referenced by strings which denote an import path ending with their class name.
Other settings you normally don't configure are also full import paths.
The exception to this explicitness is:
models.py, test.py, admin.py : They have special purposes and may not exist, providing:
You will not need any model in your app, and will provide an AppConfig (instead of just the app name) in your INSTALLED_APPS.
You will not rely on autodiscovery for admin classes in your app.
You don't want to make tests on your app, or will specify a non-default path for your app-specific test command run.
templates and static files: your project will rely on per-app loaders for your static files and for your templates files, and ultimately there's a brute-force search in each of your apps: their inner static/ and templates/ directories, if exist, are searched for those files.
Everything else is just normal python code and, if you need to import them from any view, you just do a normal import sentence for them (since view code is imported with the normal Python import mechanism).
I have a function in my view which has a decorator login_required. When the user is not authenticated redirects me automatically to
babylon/?next=prot/ats2
but it should be:
babylon/prot/?next=prot/ats2
since babylon/prot is the root from my project (it is set up like that in my apache config).
LOGIN_URL seems not to apply for this problem.
How can I solve this?
Thanks in advance
As of Django 1.5, you can LOGIN_URL can be the name of the url pattern. So if you have a url pattern named 'login', you should be able to do:
LOGIN_URL = 'login'
If you're using Django 1.4, you can use reverse_lazy
from django.core.urlresolvers import reverse_lazy
LOGIN_URL = reverse_lazy('login')
If that doesn't work, you're probably going to have to update your question to include the relevant part of your apache config.
From Django documentation:
from django.contrib.auth.decorators import login_required
def my_view(request):
# ...
my_view = login_required(redirect_field_name='redirect_to')(my_view)
Or you can also use:
settings.py
LOGIN_URL = '/where/'
In documentation we can read that:
LOGIN_URL
Default: '/accounts/login/'
The URL where requests are redirected for login, especially when using the login_required() decorator.
I have no idea what it is not working.
When I set DEBUG=False in my settings file in django 1.5, I no longer have access to the STATIC_URL or any of the other variables that should be loaded by my TEMPLATE_CONTEXT_PROCESSORS in my django templates. Oddly, everything works when DEBUG=True. For what its worth, I definitely have 'django.core.context_processors.static' in my TEMPLATE_CONTEXT_PROCESSORS so that is not the issue. I have also checked a few other variables in my template context and none of the other nothing seems to be there. MEDIA_URL? nope. request? nope. See this example on github (which has been updated with solution), but these are the important pieces that correctly work when DEBUG=True and throw a 500 error when DEBUG=False:
# settings.py
from django.conf.global_settings import *
# ...
TEMPLATE_CONTEXT_PROCESSORS += (
'django.core.context_processors.request',
)
# believe it or not, 'django.core.context_processors.static' is in there
print TEMPLATE_CONTEXT_PROCESSORS
# views.py
from django.template import RequestContext
from django.shortcuts import render_to_response
def wtf(request):
return render_to_response(
"wtf.html", {},
context_instance=RequestContext(request)
)
Does something special happen in django 1.5 when you turn off debug mode? Any suggestions for fixing and/or debugging the problem would be greatly appreciated!
Looks like there was a change between Django 1.2 and 1.3.
You now have to include django.core.context_processors.static in your TEMPLATE_CONTEXT_PROCESSORS if you want the STATIC_URL available to your template outside of debug mode.
You also need to ensure you're using a RequestContext instance when rendering the template.
This can be fixed by editing the ALLOWED_HOSTS variable in your settings.py. See this answer for more details.
To get this to work on localhost, for example, set ALLOWED_HOSTS = ['localhost'].
I'm following a tutorial where my urlpatterns are:
urlpatterns = patterns('',
url(r'^passwords/$', PasswordListView.as_view(), name='passwords_api_root'),
url(r'^passwords/(?P<id>[0-9]+)$', PasswordInstanceView.as_view(), name='passwords_api_instance'),
...other urls here...,
)
The PasswordListView and PasswordInstanceView are supposed to be class based views.
I could not figure out the meaning of the name parameter. Is it a default parameter passed to the view?
No. It is just that django gives you the option to name your views in case you need to refer to them from your code, or your templates. This is useful and good practice because you avoid hardcoding urls on your code or inside your templates. Even if you change the actual url, you don't have to change anything else, since you will refer to them by name.
e.x with views:
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse #this is deprecated in django 2.0+
from django.urls import reverse #use this for django 2.0+
def myview(request):
passwords_url = reverse('passwords_api_root') # this returns the string `/passwords/`
return HttpResponseRedirect(passwords_url)
More here.
e.x. in templates
<p>Please go here</p>
More here.