'function' object has no attribute 'get' error in django - python

greetings dear django experts,
i am having an issue with my website i am using the defualt login view in django from
from django.contrib.auth import views as auth_views
the code is working
like this inside the urls.py file :
from django.contrib.auth import views as auth_views
path('login/',auth_views.LoginView.as_view(template_name='website/login.html'), name='login-page'),
but using this methode i don't have a view inside my views.py file. the problem is i need to define a view inside my viwes.py to record logs for any one accessing this page the problem is when i tried the following code i get the error "'function' object has no attribute 'get'"
the code that gives me the error is as the following:
views.py
from django.contrib.auth import views as auth_views
def login(request):
ip = get_client_ip(request)
logger.info(f'user access: {request.user} via ip:{ip}')
return auth_views.LoginView.as_view(template_name='website/login.html')
urls.py
path('login/',views.login, name='login-page'),

.LoginView.as_view() does not process the request, it simply returns a function that will dispatch the request, you thus need to call the function that is the result of .as_view(…) with the request as parameter:
from django.contrib.auth import views as auth_views
def login(request):
ip = get_client_ip(request)
logger.info(f'user access: {request.user} via ip:{ip}')
return auth_views.LoginView.as_view(template_name='website/login.html')(request)
That being said, it looks a bit odd to do this. Why not just subclass the LoginView and register that view?
You thus can do this with:
# appname/views.py
from django.contrib.auth.views import LoginView
class MyLoginView(LoginView):
template_name='website/login.html'
def setup(self, request, *args, **kwargs):
super().setup(request, *args, **kwargs)
ip = get_client_ip(request)
logger.info(f'user access: {request.user} via ip:{ip}')
and then register your MyLoginView instead:
from appname.views import MyLoginView
path('login/', MyLoginView.as_view(), name='login-page'),

Related

Testing redirects to parameterized URLs when creating object

I have a view for creating blog posts which redirects the user to a form to fill the blog post content like this:
from django.views import View
from app.models import BlogPost
class CreateBlogPost(View):
def post():
new_post = BlogPost.objects.create()
return redirect(reverse('post_edit'), args=[new_post.id])
class EditBlogPost(View):
...
And my urls are the following:
from django.urls import path
from app.views import CreateBlogPost
urlpatterns = [
path('post', CreateBlogPost.as_view(), name='post_create'),
path('post/<int:pk>/edit', EditBlogPost.as_view(), name='post_edit')
]
I would like to: test the CreateBlogPost by asserting that it redirects to post/<some_id>/edit.
I've tried: using the method assertRedirects from django's SimpleTestCase, but couldn't find a way to make this work.
I'm also using pytest-django, in case that's relevant.

class httpresponse results in 405 - django

I am new to django and I am trying to understand class views.
In urls.py (main) I have:
from django.conf.urls import url, include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^', include('webapp.urls')),
]
in webapp folder I have:
urls.py (webapp):
from django.conf.urls import url
from webapp.views import Firstapp
urlpatterns = [
url(r'^whatever$', Firstapp.as_view()),
]
views.py (webapp):
from django.shortcuts import render
from django.views import View
from django.http import HttpResponse
class Firstapp(View):
def something(self):
return HttpResponse('Yes it works!')
As I have said, I am trying to use class views and I would appreciate if you could help me understand why class returns 405 error. Thank you. CMD returns 0 problems.
Because you are subclassing View and the only method you define is called something.
View expects you to define a method for each valid http verb. (GET, POST, HEAD etc). Since Firstapp has no such method, View.dispatch will return a response with http status 405 (Method not allowed).
dispatch(request, *args, **kwargs)
The view part of the view – the
method that accepts a request argument plus arguments, and returns a HTTP response.
The default implementation will inspect the HTTP method and attempt to delegate to a method that matches the HTTP method; a GET will be delegated to get(), a POST to post(), and so on.
By default, a HEAD request will be delegated to get(). If you need to handle HEAD requests in a different way than GET, you can override the head() method. See Supporting other HTTP methods for an example.
To fix this, change your something method:
def get(self, request):
return HttpResponse('Yes it works!')

django error HomePageView' object has no attribute 'META' windows 7

Error log:
error HomePageView' object has no attribute 'META'
urls.py
from django.conf.urls import url
from hello.views import HomePageView
urlpatterns = (
url(r'^$', HomePageView.as_view(), name='home'),
)
views.py
import textwrap
from django.shortcuts import render
from django.utils import timezone
from django.http import HttpResponse
from django.views.generic.base import View
class HomePageView(View):
def dispatch(request, *args, **kwargs):
c = {}
return render(request, 'welcome.html', c)
welcome.html
<html>
<head>
<title>Greetings to Django</title>
</head>
<body>
<h1 style="color:green;" align="center">Greetings to the world of Django Web Framework </h1>
</body>
</html>
The first parameter to dispatch, like all instance methods, should be self. request is passed as a keyword argument.
Note however that you should not be overriding dispatch. By doing so you are negating all the benefits of using class based views; you might as well use a standalone function. Instead, subclass TemplateView, set template_name as a class attribute, and define get_context_data when you actually need to pass some data to the template.
As already you are called view by name then It would be much better you can simply import all views like :
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$',HomePageView.as_view(), name='home'),
]
and mostly we use camelcase to define view name as: homePageView()
please go through it. https://docs.djangoproject.com/en/1.10/intro/tutorial01/#url-argument-name
In your views.py file, in a class function you need to use self as an argument.
Change this line def dispatch(request, *args, **kwargs): to def dispatch(self, request, *args, **kwargs):
class HomePageView(View):
def dispatch(self, request, *args, **kwargs):
c = {}
return render(request, 'welcome.html', c)

Login restriction in django

This is a very basic question cause I´m new using django. I made a login form that works just fine with the users i have in the database. The problem is that if i enter, for example, "localhost:8000/Exi/index" it does go to the main 'Home' page, the problem, obviously, is that i want users to see this page only if they are logged in. I tried with the
class LoginRequiredMixin(object):
#classmethod
def as_view(cls):
return login_required(super(LoginRequiredMixin, cls).as_view())
class Index (LoginRequiredMixin,TemplateView):
template_name = 'index.html'
But that doesn´t work for me. Maybe im not seeing something cause i looked around a couple of similar questions here and everyone seemed to have fix this in their projects.
This is my urls for this page:
url(r'^$', views.LoginView.as_view(), name='login'),
url(r'^index$', views.Index.as_view(), name='index')
Thank you in advance.
For class-based views I encourage you to use django-braces's LoginRequiredMixin
from django.views.generic import TemplateView
from braces.views import LoginRequiredMixin
class YourSecuredView(LoginRequiredMixin, TemplateView):
template_name = "yourtemplate.html"
Notice that LoginRequiredMixin has to be the left-most mixin.
Please refer to the documentation of Django: The login-required decorator
Example from the docs for simple views:
from django.contrib.auth.decorators import login_required
#login_required(login_url='/accounts/login/')
def my_view(request):
...
For class-based views, you can use the decorator in two different ways, as described in the docs: Decorating class-based views
First way, in the url routing definition:
from django.contrib.auth.decorators import login_required, permission_required
from django.views.generic import TemplateView
from .views import VoteView
urlpatterns = patterns('',
(r'^about/', login_required(TemplateView.as_view(template_name="secret.html"))),
(r'^vote/', permission_required('polls.can_vote')(VoteView.as_view())),
)
Second way, in the view itself:
class ProtectedView(TemplateView):
template_name = 'secret.html'
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(ProtectedView, self).dispatch(*args, **kwargs)
If it's site-wide login restrictions you need give https://github.com/mgrouchy/django-stronghold#stronghold a try.

Django, redirect all non-authenticated users to landing page

I have a django website with many urls and views. Now I have asked to redirect all non-authenticated users to a certain landing page. So, all views must check if user.is_authenticated() and return to a new set of landing pages.
Can it be done in a pretty way, instead of messing with my views.py/urls.py that much?
There is a simpler way to do this, just add the "login_url" parameter to #login_required and if the user is not login he will be redirected to the login page. You can find it here
from django.contrib.auth.decorators import login_required
#login_required(login_url='/accounts/login/')
def my_view(request):
...
You can use Middleware.
Something like this will check user auth every request:
class AuthRequiredMiddleware(object):
def process_request(self, request):
if not request.user.is_authenticated():
return HttpResponseRedirect(reverse('landing_page')) # or http response
return None
Docs: process_request
Also, don't forget to enable it in settings.py
MIDDLEWARE_CLASSES = (
...
'path.to.your.AuthRequiredMiddleware',
)
see the docs for login required decorator
from django.contrib.auth.decorators import login_required
#login_required
def my_view(request):
...
another option is to add it to your urls.py patterns, see this answer
urlpatterns = patterns('',
(r'^foo/$', login_required(direct_to_template), {'template': 'foo_index.html'}),
)
As of Django 1.10, the custom middleware classes must implement the new style syntax. You can use the following class to verify that the user is logged in while trying to access any views.
from django.shortcuts import HttpResponseRedirect
class AuthRequiredMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# Code to be executed for each request before
# the view (and later middleware) are called.
response = self.get_response(request)
if not request.user.is_authenticated: # in Django > 3 this is a boolean
return HttpResponseRedirect('login')
# Code to be executed for each request/response after
# the view is called.
return response
You can avoid specifying login_url by setting LOGIN_URL.
Therefore, in settings.py add:
LOGIN_URL = '<some_url>'
And in your views.py annotate relevant functions with only #login_required:
#login_required
def some_view_function(request):
If you need to redirect within a view function, you can do so with:
return redirect_to_login(request.get_full_path())
This can be done with middleware.
I've found a really nifty djangosnippet that does exactly what you are asking for. You can find it here, and it looks like:
from django.http import HttpResponseRedirect
from django.conf import settings
from re import compile
EXEMPT_URLS = [compile(settings.LOGIN_URL.lstrip('/'))]
if hasattr(settings, 'LOGIN_EXEMPT_URLS'):
EXEMPT_URLS += [compile(expr) for expr in settings.LOGIN_EXEMPT_URLS]
class LoginRequiredMiddleware:
"""
Middleware that requires a user to be authenticated to view any page other
than LOGIN_URL. Exemptions to this requirement can optionally be specified
in settings via a list of regular expressions in LOGIN_EXEMPT_URLS (which
you can copy from your urls.py).
Requires authentication middleware and template context processors to be
loaded. You'll get an error if they aren't.
"""
def process_request(self, request):
assert hasattr(request, 'user'), "The Login Required middleware\
requires authentication middleware to be installed. Edit your\
MIDDLEWARE_CLASSES setting to insert\
'django.contrib.auth.middlware.AuthenticationMiddleware'. If that doesn't\
work, ensure your TEMPLATE_CONTEXT_PROCESSORS setting includes\
'django.core.context_processors.auth'."
if not request.user.is_authenticated():
path = request.path_info.lstrip('/')
if not any(m.match(path) for m in EXEMPT_URLS):
return HttpResponseRedirect(settings.LOGIN_URL)
All you have to do is to save the file as middleware.py and include the class in you're settings.py, i.e.
MIDDLEWARE_CLASSES += ('projectname.common.middleware.RequireLoginMiddleware',)
You can also define a LOGIN_URL in settings.py, so that you'll be redirected to your custom login page. The default LOGIN_URL is '/accounts/login/'.
Maybe too late but in django 1.9+ it's too easy.
Django introduced Login Required mixin for generic classes and this a great example
here by William S. Vincent
simply in your view add LoginRequiredMixin as parent class
from django.contrib.auth.mixins import LoginRequiredMixin
class BlogUpdateView(LoginRequiredMixin, UpdateView):
model = Post
template_name = 'post_edit.html'
fields = ['title', 'body']
Also you can use login_required decorator for method request
from django.contrib.auth.decorators import login_required
#login_required(login_url='/login/')
def home(request):
return render(request, "home.html")
It's showing like this: http://127.0.0.1:1235/login/?next=/home/
I'm using class based views and I couldn't get any of these solutions to work for what I needed so I'll post my working solution here.
class ManagementPageView(TemplateView):
# Make a dispatch method to handle authentication
def dispatch(self, *args, **kwargs):
# Check if user is authenticated
if not self.request.user.is_authenticated:
# Redirect them to the home page if not
return redirect('home')
# Render the template if they are
return render(self.request, 'management.html')

Categories

Resources