django-registration custom registration form (recaptcha field) - django

I try to add a recaptcha field to my registration form and followed Marcos guide:
http://www.marcofucci.com/tumblelog/26/jul/2009/integrating-recaptcha-with-django/
In my registration app, I have a file "forms.py" which looks like this:
from recaptcha import fields as captcha_field
from registration.forms import RegistrationFormUniqueEmail
class RecaptchaRegistrationForm(RegistrationFormUniqueEmail):
recaptcha = captcha_field.ReCaptchaField()
and a urls.py which gets included under /accounts by my solution wide urls.py:
from django.conf.urls.defaults import *
from registration.views import register
from forms import RecaptchaRegistrationForm
urlpatterns = patterns('users.views',
(r'^$', 'profile'),
url(r'^register/$', register, {'form_class': RecaptchaRegistrationForm}, name='registration_register'),
)
Now, when I go to /accounts/register/ I get this error message:
Exception Value: register() takes at least 2 non-keyword arguments (1 given)
I have no idea why.

The first non-keyword argument it's asking for is request, which is gets automatically.
The second non-keyword argument, which it isn't getting, is the authentication backend.
To get going quickly you can just use the default backend that comes with django-registration. I can't easily test this myself, but this should do it:
from django.conf.urls.defaults import *
from registration.views import register
from forms import RecaptchaRegistrationForm
from registration.backends.default import DefaultBackend
urlpatterns = patterns('trackerbase.users.views',
(r'^$', 'profile'),
url(r'^register/$', register, {
'backend': DefaultBackend,
'form_class': RecaptchaRegistrationForm,
}, name='registration_register'),
)
Take a look at the file you link to starting at line 95. Reading over that should tell you all you need to know.

You can use recaptcha-client, For step by step procedure you can follow k0001's
blog it works out of the box.

'backend' isn't an optional argument.
Can you please attach the stack trace of your exception?
It seems like it's trying to use DefaultBackend as a string.

Related

Django: how to route URL requests to django.contrib.admin functions

I would like Django to return the same response for requests to /myapp/add as /admin/myapp/mymodel/add.
myproject/myapp/models.py defines the model and myapp/admin.py registers with django.contrib.admin.
myproject/myapp/models.py:
from django.db import models
class MyModel(models.Model):
...
myproject/myapp/admin.py:
from django.contrib import admin
from .models import MyModel
admin.site.register(MyModel)
I am stuck on how to route the request to django.contrib.admin in the project's urlpatterns:
myproject/myproject/urls.py:
urlpatterns = [
url(r'^$', views.home_page, name='home'),
url(r'^admin/', admin.site.urls),
url(r'^myapp/add', ??????),
]
From printing the return from resolve('/admin/myapp/mymodel/add/') this looks like part of the answer:
ResolverMatch(func=django.contrib.admin.options.add_view, args=(), kwargs={}, url_name=myapp_mymodel_add, app_names=['admin'], namespaces=['admin'])
Well let me say that seems like a weird thing to do, but anyway:
in the file: django.contrib.admin.options.py we see:
class ModelAdmin(BaseModelAdmin):
we see that the add view returns
_changeform_view()
which uses the template
django/contrib/admin/templates/change_form.html
So you would want to render that template in your view.
but it would be missing a bunch of context items,
so you would basically have to re-implement the django.admin.options._changeform_view
and then copy the template django/contrib/admin/templates/change_form.html to your apps' template directory
def admin_add(request):
# admin.changeform_view code here
return render(request, "myapp/change_form.html", {context{)
ps. I assume the admin site view assumes the user is the "superuser" and not a normal user so you would want to account for that as well..

Django: cannot import name 'url_patterns'

I have a weird edge-case where I need to use the data stored in urls.py within a view, but since the urls.py file imports the view, I am getting a circular import error when I try to import the url data into the view.
cannot import name 'url_patterns'
Does Django have any way of grabbing all the url patterns within a view that could circumvent this error? The fact that the reverse() function exists indicates that it might.
You can solve this typically (well it depends a bit), by importing the urls in your view(s) locally. Like:
# urls.py
import someapp.views
url_patterns = [
url('some_url/', someapp.views.some_view),
]
and then import the urls in the views like:
# views.py
def some_view(request):
from someapp.urls import url_patterns
# ...
# do something with urlpatterns
# return response
pass
We here thus postpone the importing of the urls.py in the views, until the view function is actually called. By that time both the views.py and urls.py are (usually) already loaded. You can however not call the view in the views.py directly, since then the import is done before the urls.py is loaded.
Note that usually you do not have to import url_patterns, and you can use reverse(..) etc. to obtain a URL that corresponds to a view function (even passing parameters into a dictionary, etc.). So I really advice to look for Django tooling to handle URLs.
Found an answer:
from django.urls import get_resolver
url_patterns = set(v[1] for k,v in get_resolver(None).reverse_dict.items())

Custom Django 404 error

I have a 404.html page, but in some cases I want to be able to send a json error message (for 404 and 500, etc.). I read the following page:
https://docs.djangoproject.com/en/dev/topics/http/views/#the-404-page-not-found-view
Is there any sort of example that shows the implementation? I have it in my urls.py but it's not being picked up in the event of an error.
This worked for me:
from django.conf.urls import patterns, include, url
from django.views.static import *
from django.conf import settings
from django.conf.urls.defaults import handler404, handler500
from app.views import error
urlpatterns = patterns('',
# Examples:
# url(r'^$', 'app.views.home', name='home'),
)
handler404 = error.error_handler
handler500 = error.error_handler
You can make it do anything as you wish when going to that controller.
In addition to the previous answer, it is important to say that the views.py should return a HttpResponse with a 404 status in the http header. It is important to inform the search engines that the current page is a 404. Spammers sometimes creates lots of urls that could seem that would lead you to some place, but then serves you another content. They frequently make lots of different addresses serve you almost the exact same content. And because it is not user friendly, most SEO guide lines penalize that. So if you have lots of addresses showing the same pseudo-404 content, it could not look good to the crawling systems from the search websites. Because of that you want to make sure that the page you are serving as a custom 404 has a 404 status. So here it is a good way to go:
Into your application's urls.py add:
# Imports
from django.conf.urls.static import static
from django.conf.urls import handler404
from django.conf.urls import patterns, include, url
from yourapplication import views
##
# Handles the URLS calls
urlpatterns = patterns('',
# url(r'^$', include('app.homepage.urls')),
)
handler404 = views.error404
Into your application's views.py add:
# Imports
from django.shortcuts import render
from django.http import HttpResponse
from django.template import Context, loader
##
# Handle 404 Errors
# #param request WSGIRequest list with all HTTP Request
def error404(request):
# 1. Load models for this view
#from idgsupply.models import My404Method
# 2. Generate Content for this view
template = loader.get_template('404.htm')
context = Context({
'message': 'All: %s' % request,
})
# 3. Return Template for this view + Data
return HttpResponse(content=template.render(context), content_type='text/html; charset=utf-8', status=404)
The secret is in the last line: status=404
Hope it helped!
I look forward to see the community inputs to this approach. =)
Basics:
To define custom view for handling 404 errors, define in the URL config, a view for handler404, like handler404 = 'views.error404'
Apart from the basics, some things to note about (custom 404 views):
It will be enabled only in Debug=False mode.
And more ignored one, across most answers (and this this stuck my brains out).
The 404 view defaults to
django.views.defaults.page_not_found(request, exception, template_name='404.html')
Notice the parameter exception
This was causing a 404 to 500 redirect from within def get_exception_response(self, request, resolver, status_code, exception) function defined in core.handlers.base since it could not find the parameter exception

How can I not use Django's admin login view?

I created my own view for login. However if a user goes directly to /admin it brings them to the admin login page and doesn't use my custom view. How can I make it redirect to the login view used for everything not /admin?
From http://djangosnippets.org/snippets/2127/—wrap the admin login page with login_required. For example, in urls.py:
from django.contrib.auth.decorators import login_required
from django.contrib import admin
admin.autodiscover()
admin.site.login = login_required(admin.site.login)
You probably already have the middle two lines and maybe even the first line; adding that fourth line will cause anything that would have hit the admin.site.login function to redirect to your LOGIN_URL with the appropriate next parameter.
While #Isaac's solution should reject majority of malicious bots, it doesn't provide protection for professional penetrating. As a logged in user gets the following message when trying to login to admin:
We should instead use the admin decorator to reject all non-privileged users:
from django.contrib.admin.views.decorators import staff_member_required
from django.contrib import admin
[ ... ]
admin.site.login = staff_member_required(admin.site.login, login_url=settings.LOGIN_URL)
To the best of my knowledge, the decorator was added in 1.9.
I found that the answer above does not respect the "next" query parameter correctly.
An easy way to solve this problem is to use a simple redirect. In your site's urls file, immediately before including the admin urls, put a line like this:
url(r'^admin/login$', RedirectView.as_view(pattern_name='my_login_page', permanent=True, query_string=True))
Holá
I found a very simple solution.
Just tell django that the url for admin login is handle by your own login view
You just need to modify the urls.py fle of the project (note, not the application one)
In your PROJECT folder locate the file urls.py.
Add this line to the imports section
from your_app_name import views
Locate this line
url(r'^admin/', include(admin.site.urls))
Add above that line the following
url(r'^admin/login/', views.your_login_view),
This is an example
from django.conf.urls import include, url
from django.contrib import admin
from your_app import views
urlpatterns = [
url(r'^your_app_start/', include('your_app.urls',namespace="your_app_name")),
url(r'^admin/login/', views.your_app_login),
url(r'^admin/', include(admin.site.urls)),
]
http://blog.montylounge.com/2009/07/5/customizing-django-admin-branding/
(web archive)
I'm trying to solve exactly this problem and I found the solution at this guys blog. Basically, override the admin template and use your own template. In short, just make a file called login.html in /path-to-project/templates/admin/ and it will replace the admin login page. You can copy the original (django/contrib/admin/templates/login.html) and modify a line or two. If you want to scrap the default login page entirely you can do something like this:
{% extends "my-login-page.html" %}
There it is. One line in one file. Django is amazing.
I had the same issue, tried to use the accepted answer, but has the same issue as pointed in the comment above.
Then I've did something bit different, pasting here if this would be helpful to someone.
def staff_or_404(u):
if u.is_active:
if u.is_staff:
return True
raise Http404()
return False
admin.site.login = user_passes_test(
staff_or_404,
)(admin.site.login)
The idea is that if the user is login, and tried to access the admin, then he gets 404. Otherwise, it will force you to the normal login page (unless you are already logged in)
In your ROOT_URLCONF file (by default, it's urls.py in the project's root folder), is there a line like this:
urlpatterns = patterns('',
...
(r'^admin/', include(admin.site.urls)),
...
)
If so, you'd want to replace include(admin.site.urls) with the custom view you created:
(r'^admin/', 'myapp.views.myloginview'),
or if your app has its own urls.py, you could include it like this:
(r'^admin/', include(myapp.urls)),
This is my solution with custom AdminSite class:
class AdminSite(admin.AdminSite):
def _is_login_redirect(self, response):
if isinstance(response, HttpResponseRedirect):
login_url = reverse('admin:login', current_app=self.name)
response_url = urllib.parse.urlparse(response.url).path
return login_url == response_url
else:
return False
def admin_view(self, view, cacheable=False):
inner = super().admin_view(view, cacheable)
def wrapper(request, *args, **kwargs):
response = inner(request, *args, **kwargs)
if self._is_login_redirect(response):
if request.user.is_authenticated():
return HttpResponseRedirect(settings.LOGIN_REDIRECT_URL)
else:
return redirect_to_login(request.get_full_path(), reverse('accounts_login'))
else:
return response
return wrapper
You can redirect admin login url to the auth login view :
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('', include('your_app.urls')),
path('accounts/', include('django.contrib.auth.urls')),
path('admin/login/', RedirectView.as_view(url='/accounts/login/?next=/admin/', permanent=True)),
path('admin/', admin.site.urls),
]
As of August 2020, django.contrib.admin.sites.AdminSite has a login_template attribute. So you can just subclass AdminSite and specify a custom template i.e.,
class MyAdminSite(AdminSite):
login_template = 'my_login_template.html'
my_admin_site = MyAdminSite()
Then just use my_admin_site everywhere instead of admin.site.

The included urlconf manager.urls doesn't have any patterns in it

A solution: Found the following django snippet that seems to work fine
(http://djangosnippets.org/snippets/2445/)
from django.utils.functional import lazy
from django.core.urlresolvers import reverse
#Workaround for using reverse with success_url in class based generic views
#because direct usage of it throws an exception.
reverse_lazy = lambda name=None, *args : lazy(reverse, str)(name, args=args)
Apparently, there is now a reverse_lazy function in django trunk.
Update: This error has something to do with me making a call to reverse inside a generic view:
class AddObjView(CreateView):
form_class = ObjForm
template_name = 'manager/obj_add.html'
success_url = reverse('manager-personal_objs')
Is this not valid?
If I instead of generic write something like this, it works:
def add_obj(request, pk):
a=reverse('manager-personal-objs')
return HttpResponse(a)
I have a project with 2 apps in it. Each app has its urls and views. They both work fine, but on the manager app, as soon as I reference the reverse function in the views(any view), I get the following error:
Exception Type: ImproperlyConfigured
Exception Value: The included urlconf manager.urls doesn't have any patterns in it
The urls file:
urlpatterns = patterns('',
url(r'^$', ObjView.as_view(), name='manager-obj'),
url(r'^add/$', AddObjView.as_view(), name='manager-add_obj'),
url(r'^personal/$', PersonalObjsView.as_view(), name='manager-personal_objs'),
)
Exception Location: ...site-packages\django\core\urlresolvers.py in _get_url_patterns, line 283
I get this error in the entire site(edit: this apparently happens because an attempt to import the manager.urls will result in the error). If I remove the include manager.urls, everything goes back to work; if I remove the call to reverse, everything is fine; if I try to rewrite manager.urls to a simpler version, it continues with the error.
I've been over this many times, can't seem to find anything wrong.
edit:root urls.py
# coding=utf8
from django.conf.urls.defaults import patterns, include, url
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from django.views.generic.simple import direct_to_template
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
# Uncomment the admin/doc line below to enable admin documentation:
url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
# Uncomment the next line to enable the admin:
url(r'^admin/', include(admin.site.urls)),
# Home Page
url(r'^$', direct_to_template, {'template': 'home.html'}, name="home"),
# manager
url(r'^manager/', include('manager.urls')),
# writing
url(r'^writing/', include('writing.urls')),
)
urlpatterns += staticfiles_urlpatterns()
edit2: Should also be noted that the url template tag works fine in the manager app and the reverse call works if I do it on the other app.
Also, every url has a written working view.
The problem is that your URLConf hasn't finished loading before your class based view attempts to reverse the URL (AddObjView.success_url). You have two options if you want to continue using reverse in your class based views:
a) You can create a get_success_url() method to your class and do the reverse from there
class AddObjView(CreateView):
form_class = ObjForm
template_name = 'manager/obj_add.html'
def get_success_url():
return reverse('manager-personal_objs')
b) If you are running on the trunk/dev version of Django, then you can use reverse_lazy https://docs.djangoproject.com/en/dev/topics/http/urls/#reverse-lazy
from django.core.urlresolvers import reverse_lazy
class AddObjView(CreateView):
form_class = ObjForm
template_name = 'manager/obj_add.html'
success_url = reverse_lazy('manager-personal_objs')
Option "b" is the preferred method of doing this in future versions of Django.