How do I change the login form used by django admin (want to add a captcha field)? I am using the cookiecutter template and have followed the suggestions in other SO answers, and guides:
forms.py
class AuthAdminForm(AuthenticationForm):
captcha = ReCaptchaField(widget=ReCaptchaV3)
show_something_different = forms.TextInput()
class Meta(AuthenticationForm):
fields = ('email', 'password', 'show_something_different', 'captcha')
urls.py
from django.contrib import admin
from myapp.forms import AuthAdminForm
admin.autodiscover()
admin.site.login_form = AuthAdminForm
admin.site.login_template = 'admin/login.html'
urlpatterns = [
# Django Admin, use {% url 'admin:index' %}
path(settings.ADMIN_URL, admin.site.urls),
...]
I was able to add admin/login.html to my templates dir and extend it. This works to add the google js to the header (can see it in source). But the captcha field and my dummy extra field don't show up.
I was on the right track, but what caught me out is that the login.html template doesn't render every field present in the form (this is why my dummy test field never showed up). So instead of extending login.html, I copied the entire contents to my own file in templates/admin/login.html, then added the captcha field manually:
<form action="{{ app_path }}" method="post" id="login-form">{% csrf_token %}
<div class="form-row">
{{ form.captcha }}
{{ form.username.errors }}
{{ form.username.label_tag }} {{ form.username }}
</div>
base.html can be extended like this:
{% block extrahead %}
<script async src="https://www.googletagmanager.com/gtag/js?id=G-xxx"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-xxx');
</script>
{% endblock %}
Now, finally, captcha is on my admin login page.
I am creating the option for users to change their passwords, and for this I am using Django auth_views, specifically PasswordChangeView (CBV). Django auth_views by default use the Django admin design template. How can I use my own template with only the form of auth_views?
What I tried:
I'm trying to set a template_name. But the auth_views form won't appear...
Only the template I provide will load.
urls.py
from django.contrib.auth import views as auth_views
urlpatterns = [
path('change-password/', auth_views.PasswordChangeView.as_view(template_name='settings/alterar_passwor
d.html'), name="change-password"),
]
Template
alterar_password.html
{% extends 'settings/settings.html' %}
{% load staticfiles %}
{% block settings %}
Mudar a minha password
{% endblock %}
What I expect:
I'm looking forward to use the form provided from auth_views, with the my own template, so I can avoid Django admin design for users.
You could use this or similiar code in your template. Your view will pass standard "form" in your custom template and you have to render it there.
an example:
<form method="post" >
<fieldset>
<legend>Password change</legend>
{% csrf_token %}
{{form.as_p}}
<button type="submit" class="form-button ">Submit</button>
<button type="reset" class="form-button btn ">Reset</button>
</fieldset>
</form>
I need to edit the "Add Object" action in the admin. It needs to redirect the user to a custom cause the logic required for adding objects is too complex to be managed in the admin. So, how do I make this possible? i.e:
The picture shows a django-suit admin, but the question is the same. How can I make that button redirect to a custom url? Or, how can I create a similar button that redirects to a custom url (I could disable the default create and leave only the custom button).
Override change_list_template html, the block object-tools-items. It's where add button is placed.
class MyModelAdmin(admin.ModelAdmin):
change_list_template = 'change_list.html'
In your change_list.html
{% extends "admin/change_list.html" %}
{% load i18n admin_static admin_list %}
{% block object-tools-items %}
{% if has_add_permission %}
<li>
<a href="your/custom/url" class="addlink">
{% blocktrans with cl.opts.verbose_name as name %}Add {{ name }}{% endblocktrans %}
</a>
</li>
{% endif %}
{% endblock %}
You need to add your new html in any dir that is included on TEMPLATE_DIRS options. But, you should do it inside your model's app.
-app
-templates
-admin
change_list.html
Add above dir in TEMPLATE DIRS paths.
I have a table in my MySQL database named mysite_categories, there are 4 columns but for my purposes I just need two (name, base_url).
I currently have a template '*base_categories.html*' that I use to load the categories manually.
base_categories.html (trimmed down)
{% block content %}
<div class="section" style="float: right;">
<h4 class="gradient">Category List</h4>
<ul>
<li>Art</li>
<li>Biography</li>
<li>Science</li>
</ul>
</div>
{% endblock %}
What I'd like to do is pull the data from the db and use it in a for loop. Something like:
{% block content %}
<div class="section" style="float: right;">
<h4 class="gradient">Category List</h4>
<ul>
{% for category in mysite_categories %}
<li>{{ category.name }}</li>
{% endfor %}
</ul>
</div>
{% endblock %}
This is probably a newbie question but is it possible to something like this without creating an app?
*EDIT 1*
These are my app files, I'll admit this is probably junk, I have tried so many edits from so many different posts I'm sure I've broke it somewhere :P. I was going to remove it and start fresh but I figure I might as well post it to see where I might have gone wrong?
views.py
from django.shortcuts import render_to_response
from categories.models import categoryList
def index(request):
categories = categoryList.objects.all()
extra_context = {"categories": categories}
return render_to_response("myapp/index.html", extra_context)
models.py
from django.db import models
class categoryList(models.Model):
#id = models.IntegerField(unique=True, db_column='ID') # Field name made lowercase.
name = models.CharField(max_length=255L, unique=True)
base_url = models.CharField(max_length=255L, unique=True)
thumb = models.CharField(max_length=1L, unique=True, blank=True)
class Meta:
db_table = 'mysite_categories'
index.html
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<div class="section" style="float: right;">
<h4 class="gradient">Category List</h4>
<ul>
{% for category in categories %}
<li>{{ category.title }}</li>
{% endfor %}
</ul>
</div>
As mentioned, it's probably junk at this point, if any of you can help me straighten this out it would be appreciated!
*EDIT 2*
base_right_panel.html
{% block content %}
<div style="float: right;">
<div id="base_categories" style="margin: 10px; padding-bottom: 10px;">
{% block base_categories %}
{% include "base_categories.html" %}
{% endblock %}
</div>
</div>
{% endblock %}
*Edit 3*
base_categories.html
{% block content %}
<div class="section" style="float: right;">
<h4 class="gradient">Category List</h4>
<ul>
{% if categories %}
{% for category in categories %}
<li>{{ category.title }}</li>
{% endfor %}
{% else %}
<p>no data! {{ categories|length }}</p>
{% endif %}
</ul>
</div>
{% endblock %}
*EDIT 4*
(Application name was changed to CategoryList)
CategoryList/views.py
from django.views.generic import TemplateView
from CategoryList.models import CategorylistCategorylist #<-- Changed to match inspectdb result
class IndexView(TemplateView):
template_name="categorylist.html" #<-- Changed name from index.html for clarity
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context["categories"] = CategorylistCategorylist.objects.all()
return context
CategoryList/models.py
from django.db import models
class CategorylistCategorylist(models.Model): #<-- Changed to match inspectdb
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=255L, unique=True)
base_url = models.CharField(max_length=255L, unique=True)
thumb = models.ImageField(upload_to="dummy", blank=True) #<-- Ignored inspectdb's suggestion for CharField
def __unicode__(self):
return self.name
# Re-added Meta to match inspectdb
class Meta:
db_table = 'categorylist_categorylist'
CategoryList/urls.py
from django.conf.urls.defaults import patterns, url, include
from django.contrib import admin
from django.conf import settings
from CategoryList import views
admin.autodiscover()
urlpatterns = patterns('',
url(r'^$', views.IndexView.as_view(), name='categorylist'),
)
if settings.DEBUG:
urlpatterns = patterns('',
url(r'^media/(?P<path>.*)$', 'django.views.static.serve',
{'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
url(r'', include('django.contrib.staticfiles.urls')),
) + urlpatterns
MySite/urls.py
from django.conf.urls import patterns, include, url
from django.contrib import admin
from django.conf import settings
from home import views as home_view
from CategoryList import views as index_view
admin.autodiscover()
urlpatterns = patterns('',
url(r'^$', home_view.HomeView.as_view(), name="home"),
url(r'^categories/$', index_view.IndexView.as_view(), name='categorylist'),#include('CategoryList.urls')),
url(r'^admin/', include(admin.site.urls)),
#url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
)
if settings.DEBUG:
urlpatterns = patterns('',
url(r'^media/(?P<path>.*)$', 'django.views.static.serve',
{'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
url(r'', include('django.contrib.staticfiles.urls')),
) + urlpatterns
So far I can load the url "localhost:8000/categories" and I will see the list of category names appear on the right side of the screen as expected, but there is no template formatting applied. Inside my "*base_right_panel.html*" file I've tried "{% include "categorylist.html %}" to link directly to the application, which displays the correct template formatting, but displays the "{% else %}" response from "{% if categories %}" instead of the categories? I have tried changing the include to point to "categories/", which works in the browser, but it tells me it cannot find the template?
I'm sooo stumped right now..?
This answer is not meant to disagree with Alasdair's - it's just to add some more information on working with templates.
The core handler of an HTTP request to a Django application is the view. The view receives the HTTP request, as well as any arguments captured from the URL, and is responsible for returning an HttpResponse instance (or an instance of one of its subclasses) which will be returned to the browser.
The view is not bound to use any particular method to create the HttpResponse. Rendering a template to include information derived from the database and from request information or URL arguments is sufficiently common that there's code to support it, like the render shortcut or its mostly obsolete antecedent render_to_response, but this is by no means required. It's perfectly legitimate to have a view directly construct the HttpResponse:
def index(request):
return HttpResponse('This is an index page.')
Or, for very simple HTML:
def index(request):
return HttpResponse('<html><head><title>example</title></head><body>This is an index page.</body></html>')
In practice, I have often created HttpResponse instances directly to return json data or a dynamically created PDF or Excel file.
A simple way to slot information retrieved from the database into your response would be to use Python's built-in string interpolation:
def index(request):
return HttpResponse('Hello, %s' % request.user.email)
Or you could use the advanced string formatting options:
def index(request):
user_names = {}
user_names['first_name'] = request.user.first_name
user_names['last_name'] = request.user.last_name
return HttpResponse('Hello, %(first_name)s %(last_name)s' % user_names)
All this is building up to the point that it doesn't matter how you generate the text contents of your HttpResponse. All that matters is that you return one.
The template system is a powerful and extensible tool for generating text content, but that's all it does. If you look at the template docs about rendering a template, you'll see some examples that are almost exactly the same as the the string interpolation above.
render_to_response was a shortcut that would accept a template and a context and return an HttpResponse with the rendered contents of that template and context. Skipping over its context_instance and content_type parameters for the sake of demonstration, these two code blocks are identical in effect:
def index(request):
t = Template('Hello, {{ first_name }} {{ last_name }}')
c = Context({'first_name': request.user.first_name, 'last_name': request.user.last_name})
response_text = t.render(c)
return HttpResponse(response_text)
Assume a template index.txt exists as defined below, at the top level of an entry in the setting's TEMPLATE_DIRS tuple.
index.txt
Hello, {{ first_name}} {{ last_name}}
Then the view above could be replaced with:
def index(request):
t = get_template('index.html')
c = Context({'first_name': request.user.first_name, 'last_name': request.user.last_name})
response_text = t.render(c)
return HttpResponse(response_text)
Alternatively, you can skip the explicit creation of the context object and rendering of the template into a string thus:
def index(request):
return render_to_response('index.html', {'first_name': request.user.first_name, 'last_name': request.user.last_name})
On more recent versions of Django you should generally use the render shortcut rather than render_to_response - the details are a bit too much to go into if you're still struggling with getting context into your templates.
def index(request):
return render('index.html', {'first_name': request.user.first_name, 'last_name': request.user.last_name})
Of course, part of what makes templates useful is that the rendering engine can perform certain kinds of logic and lookup. I don't actually need to explictly keep looking up first_name and last_name - I can just pass in request as part of my context and look up its attributes in the templates:
index_showing_context.html
Hello, {{ request.user.first_name }} {{ request.user.last_name }}
def index_showing_context(request):
return render('index_showing_context.html', {'request': request})
Even passing in request isn't strictly necessary in that example, because one of the differences between render and render_to_response that I alluded to above is that request is always part of the context for render. But, again, that's an advanced subject.
So for your particular problem, it really doesn't matter where in your templates you render the data you want, as long as you have provided it to your view's context and are rendering the correct template. The template is in effect just a file name used to find and build a string, into which your context will be interpolated.
The {% include %} template tag is one way to mix template fragments into other templates. If I wanted to, I could set mine up like this:
header.html:
<head>
<title>This is a sample title.</title>
</head>
index.html:
<html>
{% include "header.html" %}
<body><p>This is my template body, {{ request.user.first_name }} {{ request.user.last_name }}.</p></body>
</html>
detail.html:
<html>
{% include "header.html" %}
<body><p>This is a detail page, probably for something selected in the context and given the context key 'object'.</p>
<p>{{ object }}</p>
</body>
</html>
That works fine, but it's not the only option. From your question, I see that you're using blocks and template inheritance. A common idiom is to define a base template that all or almost all other templates will inherit from:
base.html
<html>
<head>
<title>{% block title %}Default title{% endblock %}</title>
{% block extra_head_elements %}{% endblock %}
</title>
<body>
{% block body_header %}Standard page header here {% endblock %}
{% block body_content %}{% endblock %}
{% block body_footer %}Standard page footer here {% endblock %}
</body>
</html>
index.html
{% extends "base.html" %}
{% block title %}index {% endblock %}
{% block body_content %}<p>This is my template body, {{ request.user.first_name }} {{ request.user.last_name }}.</p>{% endblock %}
detail.html
{% extends "base.html" %}
{% block title %}detail{% endblock %}
{% block body_content %}<p>This is a detail page, probably for something selected in the context and given the context key 'object'.</p>
<p>{{ object }}</p>
{% endblock %}
So ultimately, I am not quite sure how you should best stitch together your right panel concept because it depends on the way you want your pages to work. If it's going to be present everywhere or almost everywhere, I would recommend putting it into a base template that the rest of your templates will extend. If you want it on exactly one page, just literally include it in that template. If you want it on some but not all pages, a template fragment that you can {% include %} is probably best.
The main thing is to understand how the template engine will compose your {% include %} and {% extends %} tags, and to provide the necessary data to the template's context in your view.
Edit:
If I wanted to have a view and template pair that just retrieved the categories, this is a simple way to lay it out using your example model code and rendering. There are other options.
index.html
<html>
<head><title>Simple category listing</title></head>
<body><p>The categories are:</p>
<ul>
{% for category in categories %}
<li>{{ category.name }}</li>
{% endfor %}
</ul>
</body>
</html>
view:
def index(request):
categories = categoryList.objects.all()
extra_context = {"categories": categories}
return render_to_response("index.html", extra_context)
If I wanted to reuse the category listing on multiple pages, that gets back into the include vs. extends discussion above. Either way, the template will always require your view to pass in categories as a context variable.
You could execute custom SQL directly to fetch categories in your view, and loop through the output in your template. This would not require an app.
If you create a model, you will be able to use the Django queryset api, which is very convenient, e.g.
mysite_categories = Category.objects.all()
This does require you to create an app. However, creating an app is really easy, just use the startapp command.
python manage.py startapp myapp
Once you've created your app, you can use the inspectdb command to inspect your database, and create a model for your mysite_categories table.
I need a link in django template which turns into logout if user is authenticated. (i have already implemented login/logout pages)
tried {% if user.is_authenticated %} {% endif %} and {% if user.is_anonymous %} {% endif %} but didn't work.
Test Code (https://docs.djangoproject.com/en/dev/topics/auth/) -
{% if user.is_authenticated %}
<p>Welcome, {{ user.username }}. Thanks for logging in.</p>
{% else %}
<p>Welcome, new user. Please log in.</p>
{% endif %}
Returns false evan after logged in successfully.
It doesn't look like there is anything wrong with the template code you posted. So I'd check out the associated view. In particular, if you're using a custom-made view (rather than, say, a generic view), remember to supply a RequestContext to your template.
From the Django tutorial, part 4:
from django.template import RequestContext
# ...
def detail(request, poll_id):
p = get_object_or_404(Poll, pk=poll_id)
return render_to_response('polls/detail.html', {'poll': p},
context_instance=RequestContext(request))