I am using the built in authenticater by django and have encountered 2 issues:
Despite placing login decorators as such :
class sales_home(View):
#method_decorator(login_required)
def get(self, request, *args, **kwargs):
return render(request, 'sales/home.html')
I am still able to access the home view by typing it into the URL. The login decorator only works when I clear my browser caches, which is not a solution in production.
The second issue with the built-in authenticator is that the request.user.id returns None.
I am currently trying to display data based on the user's own inputs.
Here is my API call :
class ChartData(APIView):
authentication_classes = []
permission_classes = []
def get(self, request, format=None):
current_user = request.user
sales_rev_data = Sales_project.objects.values_list('sales_project_est_rev', flat=True).filter(sales_project_status = 'p4').filter(sales_extras = current_user.id)
labels = Sales_project.objects.values_list('sales_project_closing_date', flat=True).filter(sales_project_status = 'p4')
data = {
"labels1": labels,
"default1": sales_rev_data,
"labels2": labels,
"default2": sales_rev_data,
}
return Response(data)
because current_user.id returns None, I am unable to access the data that corresponds to the user.
Your help will be greatly appreciated!
Related
I am begginer in Djnago and logged in to my app with this code:
class LoginHandler(TemplateView):
def get(self, request, *args, **kwargs):
user = authenticate(request, email='jaxen#gmail.com', password='123456')
login(request, user)
return render(request, "login.html", context={})
But i need to detect logged in user in other app that use DRF.
I don't know how fetch the user.
I tried this code but not worked:
class OtherAppHandler(APIView):
def post(self, request):
print(f"user: {request.user}")
...
Thank you.
I think that api is stateless. In api, you need to pass the authorization token from the front end to call API and then get the user from the request.user inside api.
I think you need to fetch the user. Using get method.
def get(self, request):
user_data = request.GET.get('user', '')
I'm new to Django Class Based Views and I can't get my form to pass through neither form_valid() nor form_invalid().
I have taken most of this code from the Django allauth module, so I extend some mixins (AjaxCapableProcessFormViewMixin & LogoutFunctionalityMixin) that I do not know well.
This form is meant to allow users to change their passwords upon receiving an email. As it is now, users are able to change their password but since the form_valid() function is never triggered, they do no get redirected to the success URL as is intended. Instead the password change is registered but the users stay on the same page.
The functions dispatch(), get_form_kwargs() & get_form_class() are all triggered and behave in the way that they should. Still, it's unclear to me why they execute in the order that they do (dispatch() is triggered first, then get_form_class() and finally get_form_kwargs(). I suppose they implicitely have an order as presented in this documentation: https://ccbv.co.uk/projects/Django/4.0/django.views.generic.edit/FormView/)
I am lacking some intuition about how this works, therefore I don't know if there is a way to redirect to the success URL without passing through form_valid() because that would also solve my problem.
As is mentionned in the title, neither form_valid() nor form_invalid() is triggered after submitting a new password. The last executed bit of code is the return kwargs from the get_form_kwargs() function.
Here is my code:
class PasswordResetFromKeyView(AjaxCapableProcessFormViewMixin, LogoutFunctionalityMixin, FormView):
template_name = "account/password_reset_from_key." + app_settings.TEMPLATE_EXTENSION
form_class = ResetPasswordKeyForm
success_url = '/'
reset_url_key = "set-password"
def get_form_class(self):
return get_form_class(
app_settings.FORMS, "reset_password_from_key", self.form_class
)
def dispatch(self, request, uuid, **kwargs):
self.request = request
token = get_object_or_404(ResetToken, token=uuid)
if token.redeemed == False:
self.reset_user = token.client
self.token = token
response = self.render_to_response(self.get_context_data(token_fail=False))
else:
return super(PasswordResetFromKeyView, self).dispatch(
request, uuid, **kwargs
)
return response
def get_form_kwargs(self, **kwargs):
kwargs = super(PasswordResetFromKeyView, self).get_form_kwargs(**kwargs)
kwargs["user"] = self.reset_user
if len(kwargs) > 3:
try:
if kwargs['data']['password1'] == kwargs['data']['password2']:
self.reset_user.set_password(kwargs['data']['password1'])
self.reset_user.save()
self.token.redeemed = True
self.token.date_redeemed = datetime.now()
self.token.save()
perform_login(
self.request,
self.reset_user,
email_verification=app_settings.EMAIL_VERIFICATION,
)
else:
pass
##passwords dont match
except:
##couldnt change the password
pass
return kwargs
def form_valid(self, form, **kwargs):
form.save()
return super(PasswordResetFromKeyView, self).form_valid(form)
def form_invalid(self, form):
response = super().form_invalid(form)
if self.request.accepts('text/html'):
return response
else:
return JsonResponse(form.errors, status=400)
If both methods are not triggered, it means - you requests.method is never is 'POST'.
The class FormView calls this two methods only if post.method == 'POST':
# code from django.views.generic.edit
...
def post(self, request, *args, **kwargs):
"""
Handle POST requests: instantiate a form instance with the passed
POST variables and then check if it's valid.
"""
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
By the way in dispatch, if token.redeemed == False you should return self.form_invalid().
I have question related with Django .
I am using Knox Token Authentication to generate tokens for every user when he log in on the page.
Now I want to use that token for every request that will send so I can get the corresponding user for the token. Also I am using custom function example def dashboard(request) in Django for every URL route.
I have see on youtube that there are option to get user from token but is not with functions
class UserAPI(generics.RetrieveAPIView):
permission_classes = [
permissions.IsAuthenticated,
]
serializer_class = UserSerializer
def get_object(self):
return self.request.user
So is there a whey to get the corresponding user from a token within a custom function
Great, I figured out in hours that knox doesn't come with full token_key stored in database.
Real token we can get is something like:
a512529e7ffceaa8406ceb616d088b3422ad15811a5eb470e8f4c4896c9aa649
In database token_key is stored by default a512529e. 8 digits.
Filter objects using this:
knox_object = AuthToken.objects.filter(token_key__startswith=token[:8]).first()
Then get user object
knox_object.user.username
Or you can use this, faster
from knox.settings import CONSTANTS
knox_object = AuthToken.objects.filter(token_key=token[:CONSTANTS.TOKEN_KEY_LENGTH]).first()
From the knox source codes
class CONSTANTS:
'''
Constants cannot be changed at runtime
'''
TOKEN_KEY_LENGTH = 8
DIGEST_LENGTH = 128
SALT_LENGTH = 16
def __setattr__(self, *args, **kwargs):
raise Exception('''
Constant values must NEVER be changed at runtime, as they are
integral to the structure of database tables
''')
CONSTANTS = CONSTANTS()
You can see TOKEN_KEY_LENGTH is of 8 digits.
I wrote a simple function to do that
from knox.models import AuthToken
from knox.settings import CONSTANTS
def get_user_from_token(token):
objs = AuthToken.objects.filter(token_key=token[:CONSTANTS.TOKEN_KEY_LENGTH])
if len(objs) == 0:
return None
return objs.first().user
Life be easier now. :)
Yes, I improved it and published it.
You may try my fork. If you just simply want to add #smart_token_user before any GET/POST/PUT/... methods.
https://github.com/xros/django-rest-knox
Just git clone, and pip install ./
I wrote a decorator.
With this,
in our app views.py
we can easily get user object by doing so,#smart_token_user will modify the request handler. We can have a request.user attr only once the token is valid. And all invalid attempts will be thrown out with HTTP 401 Unauthorized response.
Life can be easier with this decorator.
from knox.models import smart_token_user
class CheckUserEmail(generics.RetrieveAPIView):
permission_classes = (IsAuthenticated,)
#smart_token_user
def get(self, request):
return Response({
"username": request.user.username,
"email": request.user.email,
"password": request.user.password,
}, status=status.HTTP_200_OK)
Or use this like original if you want: authentication_classes = (TokenAuthentication,)
class CheckUserEmail(generics.RetrieveAPIView):
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAuthenticated,)
def get(self, request):
return Response({
"username": request.user.username,
"email": request.user.email,
"password": request.user.password,
}, status=status.HTTP_200_OK)
I am using Django-rest for developing the API. In my case, when the user posts the data, I have to process the posted data (It will take 2-3 min). I wrote the Django signal for preprocessing data. My signal.py file looks like this,
#receiver(post_save, sender=ExposureIndex)
def calculate_exposure(instance, created, *args, **kwargs):
ear_table = instance.ear_index.name
haz_dir = instance.hazard_index.file.path
# calling celery task
task = exposure_calculation.delay(ear_table,haz_dir)
return task.id
And my celery calculation function is here,
#shared_task(bind=True)
def exposure_calculation(self, ear_table, haz_dir):
progress_recorder = ProgressRecorder(self)
CalculateExposure(ear_table, haz_dir)
return 'Done'
My django-rest view function is looks like this,
class ExposureIndexViewSet(viewsets.ModelViewSet):
queryset = ExposureIndex.objects.all()
serializer_class = ExposureIndexSerializer
permission_classes = [permissions.IsAuthenticated]
My question is when the user posts the data, I want to return the task.id instead of returning the actual response (I tried to return it from the Django signal but it is not returning in the actual API). Can anyone suggest to me how to return task.id instantly when the user posts the exposureIndexData?
I think you should override the create method in views.py rather than creating the signal instance. Do something like this in views.py file
class ExposureIndexViewSet(viewsets.ModelViewSet):
queryset = ExposureIndex.objects.all()
serializer_class = ExposureIndexSerializer
permission_classes = [permissions.IsAuthenticated]
def create(self, request, *args, **kwargs):
response = super().create(request, *args, **kwargs)
instance = response.data
ear_table = instance['ear_table']
haz_dir = instance['haz_dir']
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
task = exposure_calculation.delay(ear_table,haz_dir)
return Response({'task_id': task.id})
instead of using signals u can simply send response through your view
def post(self,request):
#create database manaully
task=exposure_calculation.delay(ear_table,haz_dir)
return Response({"message",task.id})
I have a Django module which is called from an SSO service. The service has a single signout function which makes a single GET request to a URL given to it during login.
I'm trying to set up an APIView in Django to handle this logout. The origin service never checks the response; it only calls the GET URL once.
I'm trying something like this for the APIView but keep getting session.DoesNotExist exceptions:
class LogoutApi(APIView):
def get(self, request, *args, **kwargs):
s = Session.objects.get(session_key=kwargs.get('sk', ''))
s.delete()
return Response({'result': True})
I know I have a valid session but even when I try iterating through the Session.objects I can't find it.
I also tried pulling the key from the SessionStore:
class LogoutApi(APIView):
def get(self, request, *args, **kwargs):
sk = request.GET.get('sk', '')
try:
s = SessionStore(sk)
del s[sk]
return Response({'result': True})
except:
self.logger.error(sys.exc_info()[0])
return Response({'result': False})
It still wasn't successful. Is there a way I can set up a GET API call to terminate a specific session?
Turns out the issue was that the session engine was set to use signed cookies. After I removed the following line from my configuration, all worked as expected:
SESSION_ENGINE = "django.contrib.sessions.backends.signed_cookies" # Removed this line
For reference, this is the logout code that worked with the above setting:
class LogoutApi(APIView):
def get(self, request, *args, **kwargs):
sk = request.GET.get('sk', '')
if sk:
s = SessionStore(session_key=sk)
s.delete()
return Response({'result': True})
return Response({'result': False})