Django {{ MEDIA_URL }} blank #DEPRECATED - django

I have banged my head over this for the last few hours.
I can not get {{ MEDIA_URL }} to show up
in settings.py
..
MEDIA_URL = 'http://10.10.0.106/ame/'
..
TEMPLATE_CONTEXT_PROCESSORS = (
"django.contrib.auth.context_processors.auth",
"django.core.context_processors.media",
)
..
in my view i have
from django.shortcuts import render_to_response, get_object_or_404
from ame.Question.models import Question
def latest(request):
Question_latest_ten = Question.objects.all().order_by('pub_date')[:10]
p = get_object_or_404(Question_latest_ten)
return render_to_response('Question/latest.html', {'latest': p})
then i have a base.html and Question/latest.html
{% extends 'base.html' %}
<img class="hl" src="{{ MEDIA_URL }}/images/avatar.jpg" /></a>
but MEDIA_URL shows up blank, i thought this is how its suppose to work but maybe I am wrong.
Update
Latest version fixes these problems.

You need to add the RequestContext in your render_to_response for the context processors to be processed.
In your case:
from django.template.context import RequestContext
context = {'latest': p}
render_to_response('Question/latest.html',
context_instance=RequestContext(request, context))
From the docs:
context_instance
The context instance
to render the template with. By
default, the template will be rendered
with a Context instance (filled with
values from dictionary). If you need
to use context processors, render the
template with a RequestContext
instance instead.

Adding media template context processor also gets the job done
TEMPLATE_CONTEXT_PROCESSORS = (
"django.core.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.core.context_processors.media",
"django.core.context_processors.static",
)

You can also use direct_to_template:
from django.views.generic.simple import direct_to_template
...
return direct_to_template(request, 'Question/latest.html', {'latest': p})

In addition to question provided above can suggest you to take a look at photologue application. It could help you to avoid direct links in template files and use objects instead.
F.ex.:
<img src="{{ artist.photo.get_face_photo_url }}" alt="{{ artist.photo.title }}"/>

Update: For Django 1.10 users, the both media and static context processors are already moved in django.template from django.core read the following article for more info: https://docs.djangoproject.com/en/1.10/ref/templates/api/#django-template-context-processors-media

Related

django crispy forms with jinja2

I want to use Jinja2 and Django crispy forms together, but when I load crispy_forms_tags in my template and trying to render form with this template tag, I get an error:
Encountered unknown tag 'crispy'. Jinja was looking for the following tags: 'endblock'. The innermost block that needs to be closed is 'block'.
My template code:
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div class="panel-heading"><h3>Registration</h3></div>
{% crispy form %}
{% endblock %}
How can I use this apps together?
Better solution:
templatetags.py
from crispy_forms.utils import render_crispy_form
from django_jinja import library
from jinja2 import contextfunction
#contextfunction
#library.global_function
def crispy(context, form):
return render_crispy_form(form, context=context)
In template:
{{ crispy(form) }}
Well, Geoffrey R.'s answer is a good approach, but the wrong method of jinja2 is used. Instead of render_crispy_form, it should be as_crispy_form. So, from crispy_forms.templatetags.crispy_forms_filters import as_crispy_form should be written at the beginning.
The corrected example jinja2.py file is as follows.
from crispy_forms.templatetags.crispy_forms_filters import as_crispy_form # this line is different
from django.contrib import messages
from django.contrib.staticfiles.storage import staticfiles_storage
from django.urls import reverse
from django.utils import translation
from jinja2 import Environment
def environment(**options):
env = Environment(
extensions=["jinja2.ext.i18n", "jinja2.ext.with_"], **options
)
env.globals.update(
{
"get_messages": messages.get_messages,
"static": staticfiles_storage.url,
"crispy": as_crispy_form, # this line is different
"url": reverse,
}
)
env.install_gettext_translations(translation)
return env
Other steps are same with Geoffrey R.'s answer.
It works for me, with the following pip packages:
Django==3.1.2
django-crispy-forms==1.9.2
Jinja2==2.11.2
By the way, I'm not using the django-jinja pip package.
Thanks Geoffrey R. for his great idea.
I found an easy, but not completed way to "hack in".
use 'django-jinja' package to register new filters;
in the filter file, define a crispy filter, which looks like:
from crispy_forms.templatetags.crispy_forms_filters import as_crispy_form
def crispy(form):
return as_crispy_form(form, 'Bootstrap3', form.helper.label_class, form.helper.field_class)
In the form Jinja template, I have to write more code than direct crispy tag in django template:
<form id='id_form' class="form-horizontal" method='post'>
{% csrf_token %}
{{form.media}}
{{ form|crispy() }}
<div>
<input type="submit" name="submit" value="Submit" class="btn btn-primary" id="submit-id-submit">
</div>
</form>
If anyone finds a more effective way to crispy forms, please let me know.
I have been struggling with this issue of yours and the given answer, although they might be relevant a few years ago, did not satisfy me.
So I went myself building a hack to make crispy forms work with Django 3.0.2 (I did not test the others versions, please let me know guys if there is any issue on any other version).
Install the relevant packages to make crispy forms work with Jinja2 :
pip install django-crispy-forms django-jinja
In your project directory (and NOT your application directory), make sure you have a jinja2.py file with:
from crispy_forms.utils import render_crispy_form
from django.contrib import messages
from django.contrib.staticfiles.storage import staticfiles_storage
from django.urls import reverse
from django.utils import translation
from jinja2 import Environment
def environment(**options):
env = Environment(
extensions=["jinja2.ext.i18n", "jinja2.ext.with_"], **options
)
env.globals.update(
{
"get_messages": messages.get_messages,
"static": staticfiles_storage.url,
"crispy": render_crispy_form, # THIS LINE IS RELEVANT
"url": reverse,
}
)
env.install_gettext_translations(translation)
return env
Make sure that your jinja2 template engine loads this option in your django's settings:
TEMPLATES = [
{
"BACKEND": "django.template.backends.jinja2.Jinja2",
"DIRS": [os.path.join(BASE_DIR, "jinja2")],
"APP_DIRS": True,
"OPTIONS": {"environment": "your_django_project.jinja2.environment"},
},
# ...
Note the "crispy": render_crispy_form, which will help you use crispy forms in your jinja2 templates.
Then, in your template, you can use:
{{ crispy(form) }}

Django csrf token missing or incorrect error

I have been developing a site using Django and am trying to implement a simple form, based off of one of the models inside my app. I have a few issues with getting it to work, but my current major problem is that I keep receiving the following error: CSRF token missing or incorrect.
I am running Django 1.6 with python 2.7.
I have already looked over the following posts to try fix my problem (and various other solutions to which I give contextual reference to where appropriate), but it has not worked for me:
Django: CSRF token missing or incorrect - Basically, passing RequestContext along with my render_to_response return.
CSRF Token missing or incorrect - I have made sure that django.middleware.csrf.CsrfViewMiddleware appears in my settings.py file and I have tried to add the django.core.context_processors.csrf as instructed to my TEMPLATE_CONTEXT_PROCESSORS setting but there is no change. When I check these settings in the shell, I get the following output:
> from django.conf import settings
> settings.TEMPLATE_CONTEXT_PROCESSORS
('django.contrib.auth.context_processors.auth',
'django.core.context_processors.debug', 'django.core.context_processors.i18n',
'django.core.context_processors.media', 'django.core.context_processors.static',
'django.core.context_processors.tz',
'django.contrib.messages.context_processors.messages')
I placed the following code in my settings.py file but I continue to get the 403 CSRF token error:
import django.conf.global_settings as DEFAULT_SETTINGS
TEMPLATE_CONTEXT_PROCESSORS = DEFAULT_SETTINGS.TEMPLATE_CONTEXT_PROCESSORS + (
'django.core.context_processors.csrf',
)
I have also followed the suggestions given in the error message itself, i.e. makign sure I have the {% csrf_token %} tags in place, using RequestContext instead of Context.
from my views.py file:
from django.shortcuts import render
from django.views.decorators.csrf import csrf_protect, csrf_exempt
from django.template import loader, Context
from django.http import HttpResponse
from forms import StudentForm
from django.http import HttpResponseRedirect
from django.core.context_processors import csrf
from django.template import RequestContext
def edit(request):
form = StudentForm(request.POST or None)
if form.is_valid():
form.save()
return Redirect('/myprofile/')
return render(request, 'myprofile.html',{'form':form})
Please not that I have read several other guides to fixing this problem that involve including RequestContext in several different ways: return render_to_response('myprofile.html', RequestContext(request, {})) and return render_to_response('myprofile.html', RequestContext(request)), none of which worked for me.
my settings.py file:
import django.conf.global_settings as DEFAULT_SETTINGS
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myprofile',
)
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
TEMPLATE_CONTEXT_PROCESSORS = DEFAULT_SETTINGS.TEMPLATE_CONTEXT_PROCESSORS + (
'django.core.context_processors.csrf',
)
My html code is as follows:
<form action = "/myprofile/" method = "post"> {% csrf_token %}
<ul>
{{ form.as_ul }}
</ul>
<input type = "submit" name = "Submit" value = "Edit Form">
</form>
Please not that I have also attempted to add the token as a hidden input, but this has not solved my issue. The function that generates this view is also the same function that is referred to by the form's action, <form action = "/myprofile/" ...>.
Any assistance with this issue would be greatly appreciated.
Your problem is here:
return render_to_response('myprofile.html',{},RequestContext(request))
Although you have added the csrf:
c = {}
c.update(csrf(request))
You don't do anything with c. To solve this once and for all, just use the render shortcut:
from django.shortcuts import render, redirect
def edit(request):
form = StudentForm(request.POST or None)
if form.is_valid():
form.save()
return redirect('/myprofile/')
return render(request, 'myprofile.html', {'form': form})
Next, in your template, you only use {% csrf_token %} not both it and {{ csrf_token }}. The tag will render the form field.
{{ csrf_token }} seems to be empty and overrides the hidden input field which is generated by {% csrf_token %}. just remove the hidden input field with {{ csrf_token }} from your template and it should work probably.
Also, as you are using RequestContext you don't have to add the CSRF token manually to the template, so you can remove following code from your view.
c = {}
c.update(csrf(request))
See https://docs.djangoproject.com/en/1.6/ref/contrib/csrf/#how-csrf-works for more information.

Adapt a view if an app is installed with Django

I have a web app with a project that works alone (it's index, login.. pages).
I would need to change the index page if a new app is installed (e.g: add a link, a table in the template with my app models..). Have it dynamic.
The removal of the app must let the project intact and just remove the link.
How can I do that? Is it possible?
You can use the Django's application registry:
In [1]: from django.apps import apps
In [2]: apps.is_installed("django.contrib.admin")
Out[2]: True
An application can actually be enabled by using a dotted Python path to either its package or the application's configuration class (preferred). Simply checking if "app_name" is in settings.INSTALLED_APPS will fail in the latter case.
def my_view(request):
from django.conf import settings
app_installed = 'app_name' in settings.INSTALLED_APPS
return render_to_response(template_name, {'app_installed': app_installed})
template:
{% if app_installed %}
...
{% endif %}
Or use a custom context processor.
In installed_apps.py
from django.conf import settings
def installed_apps(request):
return {
'app_installed' : 'app_name' in settings.INSTALLED_APPS
}
In settings.py:
TEMPLATE_CONTEXT_PROCESSORS = (
...
'installed_apps.installed_apps'
)
simple_tag version:
The tricky part is that you can't pass arguments to your simple_tag when it's used in a conditional. Therefor, you create a new variable specifically for your installed app with as is_myapp_installed.
In templatetags/my_filters.py:
from django import template
register = template.Library()
#register.simple_tag
def is_app_installed(app):
from django.apps import apps
return apps.is_installed(app)
In template:
{% load my_filters %}
...
{% is_app_installed "myapp" as is_myapp_installed %}
{% if is_myapp_installed %}
...
{% endif %}

Django reset_password_confirm TemplateSyntaxError problem

when I use django.contrib.auth.views.password_reset_confirm without arguments at all it works and I can render the template without any problem, when adding uidb36 and token arguments it fails.
Caught NoReverseMatch while rendering: Reverse for 'django.contrib.auth.views.password_reset_confirm' with arguments '()' and keyword arguments '{'uidb36': '111', 'token': '1111111111111'}' not found.
Most likely it is an issue with your urls.py. You need to setup the right pattern to grab the uidb36 and token values passed as URL parameters. If not, it will throw a similar error to what you see above.
Something like:
(r'^reset/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$', 'django.contrib.auth.views.password_reset_confirm', {'template_name' : 'registration/password_reset.html', 'post_reset_redirect': '/logout/' })
registration/password_reset.html - is my custom template
logout - is my custom logout action
I had this issue in Django 1.3, and wasted a lot of time because the error can mask a number of underlying issues.
I needed to add this to the top of the reset email template:
{% load url from future %}
Also, the example in the Django docs didn't match the sample url:
{{ protocol}}://{{ domain }}{% url 'auth_password_reset_confirm' uidb36=uid token=token %}
So I had to change the auth_password_reset_confirm above to password_reset_confirm.
If you're using Django 1.6+ and run into something like this it could be that you need to update uidb36 to uidb64 in both your template and your urls.
Example url:
url(r'^password/reset/confirm/(?P<uidb64>[0-9A-Za-z]+)-(?P<token>.+)/$',
auth_views.password_reset_confirm
and reset link in template:
{{ protocol}}://{{ domain }}{% url 'django.contrib.auth.views.password_reset_confirm' uidb64=uid token=token %}
For Django 1.8+ users, just copy this URL to your main urls.py file, so that it recognizes the URL name
url(r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
'django.contrib.auth.views.password_reset_confirm',
name='password_reset_confirm'),
And add this mentioned by: #Lunulata to your password_reset_email.html file:
{{ protocol}}://{{ domain }}{% url 'django.contrib.auth.views.password_reset_confirm' uidb64=uid token=token %}
Try adding following to your urls.py
(r'^reset/(?P<uidb36>[0-9A-Za-z]{1,13})-(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', 'django.contrib.auth.views.password_reset_confirm'),
I found this to work, copied from the default url
url(r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
auth_views.password_reset_confirm, name='password_reset_confirm'),
Just add this line to your urls.py:
url('^', include('django.contrib.auth.urls')),
This enables the django reset_password workflow.
Then override your login.html to include the line:
<div class="password-reset-link">
href="{{ password_reset_url }}">{% trans 'Forgotten your password or username?' %}</a></div>
Now you should be able to use the builtin Django PasswordResetView included with Django as long as your email settings are set up.
if you are using app_name in every urls.py
suppose you have an app and in that app in urls.py you have mentioned app_name="accounts"
in order to retrieve the page you need to mention two things
template_name and success_url inside the PasswordResetView(template_name="accounts/password_reset.html" , success_url= reverse_lazy('accounts:password_reset_sent'))
dont forget to import reverse_lazy from django.urls inside urls.py
so your final code of accounts/urls.py should look like
My app name is landing instead of accounts
from django.urls import path
from . import views
from django.contrib.auth import views as auth_views
from django.urls import reverse_lazy
app_name='landing'
urlpatterns = [
path('',views.home,name="home"),
path('terms/',views.terms,name="terms"),
path('login/',views.loginUser,name="login"),
path('signup/',views.signupUser,name="signup"),
path('about/',views.about,name="about"),
path('logout/',views.logoutUser,name="logout"),
path('password_reset/',
auth_views.PasswordResetView.as_view(template_name='landing/password_reset.html',success_url=reverse_lazy('landing:password_reset_done')),
name="password_reset"),
path('password_reset_sent/',
auth_views.PasswordResetDoneView.as_view(template_name='landing/password_reset_sent.html'),
name="password_reset_done"),
path('reset/<uidb64>/<token>/',
auth_views.PasswordResetConfirmView.as_view(template_name='landing/password_reset_form.html',success_url=reverse_lazy('landing:password_reset_complete')),
name="password_reset_confirm"),
path('password_reset_complete/',
auth_views.PasswordResetCompleteView.as_view(template_name='landing/password_reset_done.html'),
name="password_reset_complete"),
]
you have to use app_name: before the name of url you have mentioned it is very important

Using {% url ??? %} in django templates

I have looked a lot on google for answers of how to use the 'url' tag in templates only to find many responses saying 'You just insert it into your template and point it at the view you want the url for'. Well no joy for me :( I have tried every permutation possible and have resorted to posting here as a last resort.
So here it is. My urls.py looks like this:
from django.conf.urls.defaults import *
from login.views import *
from mainapp.views import *
import settings
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
# Example:
# (r'^weclaim/', include('weclaim.foo.urls')),
(r'^login/', login_view),
(r'^logout/', logout_view),
('^$', main_view),
# Uncomment the admin/doc line below and add 'django.contrib.admindocs'
# to INSTALLED_APPS to enable admin documentation:
# (r'^admin/doc/', include('django.contrib.admindocs.urls')),
# Uncomment the next line to enable the admin:
(r'^admin/', include(admin.site.urls)),
#(r'^static/(?P<path>.*)$', 'django.views.static.serve',{'document_root': '/home/arthur/Software/django/weclaim/templates/static'}),
(r'^static/(?P<path>.*)$', 'django.views.static.serve',{'document_root': settings.MEDIA_ROOT}),
)
My 'views.py' in my 'login' directory looks like:
from django.shortcuts import render_to_response, redirect
from django.template import RequestContext
from django.contrib import auth
def login_view(request):
if request.method == 'POST':
uname = request.POST.get('username', '')
psword = request.POST.get('password', '')
user = auth.authenticate(username=uname, password=psword)
# if the user logs in and is active
if user is not None and user.is_active:
auth.login(request, user)
return render_to_response('main/main.html', {}, context_instance=RequestContext(request))
#return redirect(main_view)
else:
return render_to_response('loginpage.html', {'box_width': '402', 'login_failed': '1',}, context_instance=RequestContext(request))
else:
return render_to_response('loginpage.html', {'box_width': '400',}, context_instance=RequestContext(request))
def logout_view(request):
auth.logout(request)
return render_to_response('loginpage.html', {'box_width': '402', 'logged_out': '1',}, context_instance=RequestContext(request))
and finally the main.html to which the login_view points looks like:
<html>
<body>
test! logout
</body>
</html>
So why do I get 'NoReverseMatch' every time?
*(on a slightly different note I had to use 'context_instance=RequestContext(request)' at the end of all my render-to-response's because otherwise it would not recognise {{ MEDIA_URL }} in my templates and I couldn't reference any css or js files. I'm not to sure why this is. Doesn't seem right to me)*
The selected answer is out of date and no others worked for me (Django 1.6 and [apparantly] no registered namespace.)
For Django 1.5 and later (from the docs)
Warning
Don’t forget to put quotes around the function path or pattern name!
With a named URL you could do:
(r'^login/', login_view, name='login'),
...
logout
Just as easy if the view takes another parameter
def login(request, extra_param):
...
login
Instead of importing the logout_view function, you should provide a string in your urls.py file:
So not (r'^login/', login_view),
but (r'^login/', 'login.views.login_view'),
That is the standard way of doing things. Then you can access the URL in your templates using:
{% url login.views.login_view %}
Make sure (django 1.5 and beyond) that you put the url name in quotes, and if your url takes parameters they should be outside of the quotes (I spent hours figuring out this mistake!).
{% url 'namespace:view_name' arg1=value1 arg2=value2 as the_url %}
link_name
The url template tag will pass the parameter as a string and not as a function reference to reverse(). The simplest way to get this working is adding a name to the view:
url(r'^/logout/' , logout_view, name='logout_view')
I run into same problem.
What I found from documentation, we should use namedspace.
in your case {% url login:login_view %}
Judging from your example, shouldn't it be {% url myproject.login.views.login_view %} and end of story? (replace myproject with your actual project name)