django-The page isn’t redirecting properly - django

I have a middleware that check user profile. If auth user doesn't have a profile, then redirect to user profile. My browser displays the error The page isn’t redirecting properly.
class Check(MiddlewareMixin):
def process_request(self, request):
if request.user.is_authenticated():
user = request.user
try:
profile = Profile.objects.get(user_id = user)
if profile:
pass
except ObjectDoesNotExist:
return HttpResponseRedirect('/accounts/profile/')
I'm use django-allauth.

It sounds like you might have an infinite redirect loop. Check the request path, and do not redirect if the user is trying to access /accounts/profile/.
class Check(MiddlewareMixin):
def process_request(self, request):
if request.user.is_authenticated() and request.path != '/accounts/profile/':
...

Make sure you are using The Right view, in my case i was using:
view
class Blog_View(View):
model = Blog
template_name = 'blog.html'
instead of
Listview
class Blog_View(ListView):
model = Blog
template_name = 'blog.html'

Check your secret key in setting.py I solved this problem with to remove get_random_secret_key().
Before
SECRET_KEY = env.str("SECRET_KEY", get_random_secret_key())
After
SECRET_KEY = env.str("SECRET_KEY")
Now Im using unique SECRET_KEY and it works fine in prod service.

Related

One login form for two types of accounts and LoginRequiredMixin in django

I have one LoginForm for two types of users, until here all works fine. Issue comes when I do LoginRequiredMixin for any view, I dont know why but is redirecting to the success_url of the login form. Here is my LoginForm:
form_valid method redirect the users depends of the perms he has.
class LoginView(FormView):
form_class = AuthenticationForm
template_name = 'login.html'
def dispatch(self,request,*args,**kwargs):
if request.user.is_authenticated() and request.user.has_perm('users.is_contribuyente'):
return HttpResponseRedirect('/solicitudes-enviadas')
if request.user.is_authenticated() and request.user.has_perm('users.is_professional'):
return HttpResponseRedirect('/panel/inicio')
return super(LoginView,self).dispatch(request,*args,**kwargs)
def form_valid(self,form):
login(self.request,form.get_user())
if self.request.user.has_perm('users.is_contribuyente'):
return redirect('/solicitudes-enviadas')
if self.request.user.has_perm('users.is_professional'):
return redirect('/panel/inicio')
Here my view with a LoginRequiredMixin:
class SendQuoteView(LoginRequiredMixin,VerifiedUserMixin,FormMixin,DetailView):
login_url = '/entrar/'
model = Request
form_class = SendQuoteForm
template_name = 'send_quote.html'
Let's say this is the URL when an not authenticated user is trying to access: http://127.0.0.1:8000/entrar/?next=/panel/detalle-solicitud/declaracion-de-renta. And lets says the user has perm of "is_professional" It supose that have to redirect to /panel/detalle-solicitud/declaracion-de-renta but instead of that is redirecting to /panel/inicio/, the URL of the instrucion of form_valid
New form_valid method only for test to getting next variable:
def form_valid(self, form):
#login(self.request, form.get_user())
next = self.request.GET('next')
print next
return super(LoginView, self).form_valid(form)
How can I achieve that respect the URL of the LoginRequiredMixin?
There is nothing in Django that magically handles ?next=... in the url. You have to fetch the value from request.GET. Note that you should not trust the value from the user - Django has an is_safe_url method that you can use.
from django.http.utils import is_safe_url
next_url = self.request.GET.get('next')
if next_url and is_safe_url(next_url, self.request.get_host()):
# redirect to next
else:
# redirect to fallback
You might find it easier to use the built in login view to handle logins. You can then create a custom view for the LOGIN_REDIRECT_URL setting, and handle the permissions-based redirects there.

Django braces - login and group required

Starting with the following view:
from braces.views import GroupRequiredMixin, LoginRequiredMixin
class AddAttributeView(LoginRequiredMixin, GroupRequiredMixin, FormView):
group_required = "SchemaAdmin"
...
I want to achieve the following:
If the user is not logged in -> redirect the user to login page
If the user is logged in and has no permissions: throw 403
With the configuration above, the user is always redirected to the login page (even if he is logged in but simply not in the group)
On the other hand, if I set raise_exception = True , the application always throws a 403 , even if the user is not logged in.
Is there a possibility to achieve the above without setting raise_exception = my_function and implementing the whole logic in my_function?
The django-braces docs for the LoginRequiredMixin suggest you should set raise_exception = True so that an exception is raised for logged in users, and redirect_unauthenticated_users = True so that unauthenticated users are redirected to the login page.
class AddAttributeView(LoginRequiredMixin, GroupRequiredMixin, FormView):
group_required = "SchemaAdmin"
raise_exception = True
redirect_unauthenticated_users = True
That doesn't seem to be working at the moment because of this issue. As a work around, I suggest writing a short callable for raise_exception.
from django.shortcuts import redirect
def raise_unless_unauthenticated(request):
if not request.user.is_authenticated():
return redirect('login')
# returning None means PermissionDenied will be raised
return None
class AddAttributeView(LoginRequiredMixin, GroupRequiredMixin, FormView):
group_required = "SchemaAdmin"
raise_exception = raise_unless_unauthenticated

How can I create a django url specific to a user?

I am interested in making my urls customised for each user, something like
username.mysite.com/home but I am not sure how to do this with django.
I am also curious if this might work in development (so as to have username.localhost:8000/home) or not.
Thank you.
There is another way as well. What you can do is have Middleware that gets the url, parses the subdomain and then renders a user profile page.
This is assuming you are using a custom profile page and not the default profile page.
#in yourapp.middleware
from django.contrib.auth.models import User
import logging
import yourapp.views as yourappviews
logger = logging.getLogger(__name__)
class AccountMiddleware(object):
def process_request(self, request):
path = request.META['PATH_INFO']
domain = request.META['HTTP_HOST']
pieces = domain.split('.')
username = pieces[0]
try:
user = User.objects.get(username=username)
if path in ["/home","/home/"]:
return yourappviews.user_profile(request, user.id)
#In yourapp.views.py
def user_profile(request,id):
user = User.objects.get(id=id)
return render(request, "user_profile.html", {"user": user})
#In settings.py
MIDDLEWARE_CLASSES = (
#... other imports here
'yourapp.middleware.AccountMiddleware'
)

Django Tastypie Import Error on resources

I have something strange going on that I can't seem to crack. I'm building an API with Tastypie and when I issue this call in my browser against localserver, it works fine: localserver/api/v1/userfavorite/?user__username=testowner
However, in my code, I'm getting an error: "int() argument must be a string or a number, not 'SimpleLazyObject'". I realize it has to do with the user being treated as a request.user object, but I can't figure out where/why. I'm very confused why it works when issuing the API call in the browser, but in the code it is not working.
Here is my code:
# views.py
#login_required
def favorites(request):
'''
display a list of posts that a user has marked as favorite
'''
user = request.user
favorites_url = settings.BASE_URL + "/api/v1/userfavorite/?user__username=" + user.username
favorites = get_json(favorites_url)
return render(request, "maincontent/favorites.html", {'favorites':favorites})
# resources.py
class UserFavoriteResource(ModelResource):
'''
manage post favorites by a user. Users can use a favorites list
to easily view posts that they have liked or deemed important.
'''
user = fields.ForeignKey(UserResource, 'user')
post = fields.ForeignKey('blog.api.resources.PostResource', 'post', full=True)
class Meta:
queryset = UserFavorite.objects.all()
allowed_methods = ['get', 'post', 'delete']
authentication = Authentication()
authorization = Authorization()
filtering = {
'user':ALL_WITH_RELATIONS
}
def hydrate_user(self, bundle):
# build the current user to save for the favorite instance
bundle.data['user'] = bundle.request.user
return bundle
def get_object_list(self, request):
# filter results to the current user
return super(UserFavoriteResource, self).get_object_list(request)\
.filter(user=request.user)
# utils.py
def get_json(url):
# return the raw json from a request without any extraction
data = requests.get(url).json()
return data
Some notes:
1. I have the post method working to create the UserFavorite item
2. I can verify that the favorites_url is being generated correctly
3. I have tried hardcoding the favorites_url as well, same error.
EDIT: 4. I am logged in while doing this, and have verified that request.user returns the user
This doesn't work because there is Anonymous user in your request.user. You are using Authentication it does not require user to be logged in. So if you perform requests call that request is not authenticated and request.user is AnonymousUser and that error occurs when you try to save Anonymous user to db. Tastypie documentation advices to not using browsers to testing things up, just curl instead. Browsers stores a lot of data and yours one probably remembered you have been logged to admin panel in localhost:8000 on another tab that's why it worked in browser.
I would prefer something like this:
def hydrate_user(self, bundle):
"""\
Currently logged user is default.
"""
if bundle.request.method in ['POST', 'PUT']:
if not bundle.request.user.is_authenticated():
raise ValidationError('Must be logged in')
bundle.obj.user = bundle.request.user
bundle.data['user'] = \
'/api/v1/userauth/user/{}'.format(bundle.request.user.pk)
return bundle

django braces UserPassesTestMixin redirects to 'accounts/profile/'

I'm adding django-braces to a system to ensure only certain users can perform certain actions. As a background, I've got some users who login and potentially have other users associated with their account, like a team leader.
Those team leaders are able to edit the details of their team so I've got a UserPassesTestMixin on that edit view and a LoginRequiredMixin on the dashboard view once they login.
Here are my views;
class Dashboard(DetailView, LoginRequiredMixin):
template_name = 'online_entry/entrant/dashboard.html'
model = FreeCycleEntrant
http_method_names = ['get']
class UpdateEntrantWizard(SignupWizard, UserPassesTestMixin):
template_name = 'online_entry/entrant/wizard_form.html'
form_list = [EditTeamMember]
model = Entrant
instance = None
def get_instance_obj(self):
if self.instance is None and 'pk' in self.kwargs:
self.instance = get_object_or_404(
Entrant, pk=self.kwargs['pk']
)
return self.instance
def test_func(self, user):
parent = Entrant.objects.get(user=user)
return self.get_instance_obj().user_has_access(user, parent=parent)
And the test function on my Entrant model is quite straightforward;
def user_has_access(self, user, parent=None):
"""
Indicates whether or not a user can edit this user. The passed in user
is the logged in user.
:type self: object
"""
if self.user == user:
return True
if isinstance(user, AnonymousUser):
return False
if parent and self.parent_entrant == parent:
return True
return False
So when I'm logged in as one of these users, and from the Dashboard attempt to go to that UpdateEntrantWizard view I'm redirected to /accounts/profile/ before the tests are hit (using breakpoints).
Am I missing something in my implementation of braces? It looks like you really only need to add the test & the mixin to get things working.
UserPassesTestMixin inherits from AccessMixin, which includes the login_url property. Simply set:
login_url = "/your_url/"
and it will redirect to a url of your choice.
As far as testing is concerned you can use the django Client. The example below from an app of mine should give the idea here. Obviously the user 'Claire' in this test should be created where the ellipses are, and with the permissions needed to pass the test.
def test_home_url_allows_authenticated_user(self):
c = Client()
...
c.login(username='Claire', password='pass')
content = c.get('/travel/')
self.assertEqual(content.status_code, 200)
Finally you may want to add a message in your login page along these lines:
{% if user.is_authenticated %}
<h2>You're logged in, but you might not have permission to view the page you requested.</h2>
{% else %}
...
Because that's where users will end up if they don't have the right permissions.
Try switching
class UpdateEntrantWizard(SignupWizard, UserPassesTestMixin):
To
class UpdateEntrantWizard(UserPassesTestMixin, SignupWizard):
When using something like :
class SomeProtectedView(views.LoginRequiredMixin,
views.PermissionRequiredMixin,
TemplateView):
the order in which you call the mixins matter. In this example it will check if user is logged in before checking permissions. And, if you were to put TemplateView first it would bypass the mixins altogether.