In my app I am trying to get the User data using a get request and it works in Postman but the problem occurs when I try to send the data from FrontEnd as we cannot send Body in get Request
URL:
path('user/meta/', UserDetails.as_view()),
Views.py
class UserDetails(APIView):
"""Get basic details of user"""
def get(self, request):
username = request.data["username"]
if User.objects.filter(username = username).exists():
user = User.objects.get(username = username)
print(user)
return Response({
'verified': user.verified,
})
else:
return Response("User doesn't exists", status=status.HTTP_400_BAD_REQUEST)
How should I modify it such that I can get the data from get request?
So, your requesting URL will become /user-info/?username=john
and then, use request.GET
username = request.GET.get("username","default_value")
The good practice is to use query params in such case,
so your url will look like,
/user-info/?username=john
and you modify your code to,
username= self.request.query_params.get('username')
I know this is an old topic and the question is answered, but just to underline that the queried data, you obtained from the user in the API should go through the Serializers (https://www.django-rest-framework.org/tutorial/1-serialization/) to at least somehow protect against unwanted values. This will also avoid you directly querying the database models.
Related
sorry for my english. It is not good.
I work with rest framework django. I want to recover a user with his token. This Token must be sent via a post request
class GetUser(generics.ListCreateAPIView):
serializer_class = serializers.UserBasicSerializer
def get_queryset(self):
return models.Member.objects.filter()
def post(self, request, *args, **kwargs):
user = Token.objects.get(*args, **kwargs).user
i receive this error message
rest_framework.authtoken.models.MultipleObjectsReturned: get() returned more than one Token -- it returned 2!
thanks
Use:
user = Token.objects.filter(*args, **kwargs)
if user.exists():
user = user.last().user
The answer to your question is in the docs. Take a look here: http://www.django-rest-framework.org/api-guide/requests/#user
Basically, you just need to get from request the method user. For example:
def api_name_of_api(request):
user_data = request.user # Get username
user_data = request.user.id # Get user id
...
I am writing some tests for a form on a Django site. I want to test that a logged in user is able to use the form assuming correct input. To that end, I am using a Django request factory. I can't seem to get my test user logged in though. That, or I'm not even making the request correctly. I'm not sure. Relevant code below:
def create_user():
username = 'User '+id_generator()
return User.objects.create(username = username, password = 'password')
def test_can_register_deck(self):
t = create_empty_tourney()
u = create_user()
d = create_deck(u)
rf = RequestFactory()
request = rf.post(reverse('tourney:tourney', args=(t.slug,)),{'deck' : d})
request.user = u
response = self.client.get(reverse('tourney:tourney', args=(t.slug,)), request)
self.assertEqual(response.status_code, 200)
The request has to think the user is logged in, or the rest of the test won't work. This throws no errors, but I'm not even sure my response is utilizing the request correctly. Am I correctly telling the test to "make a post request to the tourney page as this user, and try to submit a deck"?
I think that the RequestFactory and the client are two different ways of testing django views.
The request that is returned from rf.post is meant to be passed directly to a view function. If you were to do that, i think you will find that, the user will be detected as logged in.
I looked at the source, and the documentation, and I don't see where the test client accepts a request. You can log in a user with the test client using:
self.client.login(
username=u.username,
password='password')
The code I'm showing you below its what works for me right now. its not the most secure but does the job but i want to do it using POST method. any ideas how to change it?
I have a serializer.py class
class userLoginSerializer(serializers.ModelSerializer):
class Meta:
model = users
fields = ('nick', 'pass_field')
#api_view(['GET'])
def user_login(request,nick,pass_field):
but when i sent the 2 values nick and passfield it says that the nick already exist and returns 404 because it passes it to serializers.errors. I just need to pass the code using POST and validating if it exist and return a success JSON. The code below works but its not the best implementation.
if request.method == 'GET':
try:
users.objects.get(nick=nick,pass_field=pass_field)
json = {}
json['message'] = 'success'
return Response(json, status=status.HTTP_201_CREATED)
except users.DoesNotExist:
json = {}
json['message'] = 'error'
return Response(json, status=status.HTTP_400_BAD_REQUEST)
The models is users or User? Why don't you use the Django User model?
The class User has already a check_password method and store it with a hash algoritm: https://docs.djangoproject.com/en/dev/ref/contrib/auth/#methods
Never store a password in plain text, it's very insecure.
Using Django User model (or a class that inherits from it) you can simply check if it's valid this way:
try:
user = User.objects.get(username=nick)
if user.check_password(pass_field):
#TODO: Valid password, insert your code here
else:
#TODO: Password not valid, handle it here
pass
except User.DoesNotExist:
#TODO: Your error handler goes here
pass
Another thing you can do is inherits from ApiView and implement your code in post method: http://www.django-rest-framework.org/api-guide/views
I implemented a method for Sign In with JWT and what it does is:
Fetches the email and password that is send with the request and
converts it into a string variable
I check if the email already
exists in the custom user model i made.
If the user already
exists, i convert the object model to dictionary so that i can get
its particular password.
In that i match the password
corresponding to user model and the password that is send with the
post request.
if the email exists in the user model and the password corresponding to that user model matches the password that is sent with the post request i use the pyJWT to make the JWT with my custom data and return the response.
In all other cases the email and password don't match and i return "No Match"
Suppose the request is {"email":"xyz#gmail.com", "password":"12345" }
#api_view(['POST'])
def signin(request):
email = list(request.data.values())[0] #gets email value from post request {"email":"xyz#gmail.com", "password":"123"} -> this xyz#gmail.com
password = list(request.data.values())[1] #gets password value from post request {"email":"xyz#gmail.com", "password":"123"} -> this 123
usr = User.objects.filter(email=email).exists() #checks if email exists
if usr:
dictionary = User.objects.filter(email=email).values()[0] #converts object to dictionary for accessing data like dictionary["password"] dictionary["first_name"] etc
if usr and dictionary["password"] == password: #check if email and its corresponing password stored matches the password that is sent
branch = dictionary["branch"]
id = dictionary["id"]
encoded_jwt = jwt.encode({'email': email,}, 'secret', algorithm='HS256')
return Response({'token':encoded_jwt,'email':email,'branch':branch,'id':id})
else:
return Response({'No Match'})
return Response({'No Match'})
Maybe a stupid question here:
Is Requests(A python HTTP lib) support Django 1.4 ?
I use Requests follow the Official Quick Start like below:
requests.get('http://127.0.0.1:8000/getAllTracks', auth=('myUser', 'myPass'))
but i never get authentication right.(Of course i've checked the url, username, password again and again.)
The above url 'http://127.0.0.1:8000/getAllTracks' matches an url pattern of the url.py of a Django project, and that url pattern's callback is the 'getAllTracks' view of a Django app.
If i comment out the authentication code of the 'getAllTracks' view, then the above code works OK, but if i add those authentication code back for the view, then the above code never get authenticated right.
The authentication code of the view is actually very simple, exactly like below (The second line):
def getAllTracks(request):
if request.user.is_authenticated():
tracks = Tracks.objects.all()
if tracks:
# Do sth. here
Which means if i delete the above second line(with some indents adjustments of course), then the requests.get() operation do the right thing for me, but if not(keep the second line), then it never get it right.
Any help would be appreciated.
In Django authentication works in following way:
There is a SessionMiddleware and AuthenticationMiddleware. The process_request() of both these classes is called before any view is called.
SessionMiddleware uses cookies at a lower level. It checks for a cookie named sessionid and try to associate this cookie with a user.
AuthenticationMiddleware checks if this cookie is associated with an user then sets request.user as that corresponding user. If the cookie sessionid is not found or can't be associated with any user, then request.user is set to an instance of AnonymousUser().
Since Http is a stateless protocol, django maintains session for a particular user using these two middlewares and using cookies at a lower level.
Coming to the code, so that requests can work with django.
You must first call the view where you authenticate and login the user. The response from this view will contain sessionid in cookies.
You should use this cookie and send it in the next request so that django can authenticate this particular user and so that your request.user.is_authenticated() passes.
from django.contrib.auth import authenticate, login
def login_user(request):
user = authenticate(username=request.POST.get('username'), password=request.POST.get('password'))
if user:
login(request, user)
return HttpResponse("Logged In")
return HttpResponse("Not Logged In")
def getAllTracks(request):
if request.user.is_authenticated():
return HttpResponse("Authenticated user")
return HttpResponse("Non Authenticated user")
Making the requests:
import requests
resp = requests.post('http://127.0.0.1:8000/login/', {'username': 'akshar', 'password': 'abc'})
print resp.status_code
200 #output
print resp.content
'Logged In' #output
cookies = dict(sessionid=resp.cookies.get('sessionid'))
print cookies
{'sessionid': '1fe38ea7b22b4d4f8d1b391e1ea816c0'} #output
response_two = requests.get('http://127.0.0.1:8000/getAllTracks/', cookies=cookies)
Notice that we pass cookies using cookies keyword argument
print response_two.status_code
200 #output
print response_two.content
'Authenticated user' #output
So, our request.user.is_authenticated() worked properly.
response_three = requests.get('http://127.0.0.1:8000/hogwarts/getAllTracks/')
Notice we do not pass the cookies here.
print response_three.content
'Non Authenticated user' #output
I guess, auth keyword for Requests enables HTTP Basic authentication which is not what is used in Django. You should make a POST request to login url of your project with username and password provided in POST data, after that your Requests instance will receive a session cookie with saved authentication data and will be able to do successful requests to auth-protected views.
Might be easier for you to just set a cookie on initial authentication, pass that back to the client, and then for future requests expect the client to send back that token in the headers, like so:
r = requests.post('http://127.0.0.1:8000', auth=(UN, PW))
self.token = r.cookies['token']
self.headers = {'token': token}
and then in further calls you could, assuming you're in the same class, just do:
r = requests.post('http://127.0.0.1:8000/getAllTracks', headers=self.headers)
I'm trying to have my form submit to a route which will validate the data then redirect back to the original route.
For example:
User loads the page website.com/post
Form POSTs the data to website.com/post-save
User gets redirected back to website.com/post
Pyramid is giving me some troubles doing this.
Here's my slimmed down views.py
def _get_link_form(post_data):
""" Returns the initialised form object """
return LinkForm(post_data)
def home_page(request):
form = _get_link_form(request.POST)
return {'form' : form}
def save_post(request):
""" form data is submitted here """"
form = _get_link_form(request.POST)
if not form.validate():
return home_page(request, form)
This is the code I've been playing around with. Not only does it not work, it also feels messy and hacked up. Surely there's a simpler way to 'redirect after-POST' in Pyramid?
Your problem is most easily solved by simply POSTing to the same URL that your form is shown at, and simply redirecting the user away from the page when the POST is successful. That way until the form is successfully submitted you do not change URLs.
If you're just dying to POST to a different URL, then you need to save the data using sessions, since you're obviously handling the form data between requests.
Typically if you want to be able to handle errors in your forms you would use a session and flash messages. To do this you simply add a location for flash messages to appear in your base template and setup session support using something like pyramid_beaker.
Assuming your home page is setup at the 'home' named-route:
from pyramid.httpexceptions import HTTPFound
def myview(request):
user = '<default user field value>'
if 'submit' in request.POST:
user = request.POST.get('user')
# validate your form data
if <form validates successfully>:
request.session.flash('Form was submitted successfully.')
url = request.route_url('home')
return HTTPFound(location=url)
return {
# globals for rendering your form
'user': user,
}
Notice how if the form fails to validate you use the same code you did to render the form originally, and only if it is successful do you redirect. This format can also handle populating the form with the values used in the submission, and default values.
You can loop through the flash messages in your template of choice using request.session.peek_flash() and request.session.pop_flash().
route_url supports mutating the query string on the generated url as well, if you want to flag your home page view to check the session data.
You can obviously just pass everything in the query string back to the home page, but that's a pretty big security vulnerability that sessions can help protect against.
The Pyramid documentation has a particularly on-point section with the following example:
from pyramid.httpexceptions import HTTPFound
def myview(request):
return HTTPFound(location='http://example.com')
I do this like so:
from pyramid.httpexceptions import HTTPCreated
response = HTTPCreated()
response.location = self.request.resource_url( newResource )
return response
This sends the HTTP Created code , 201
The Pyramid documentation has content about Redirect, you can see more information in below link :
Pyramid documentation
import pyramid.httpexceptions as exc
raise exc.HTTPFound(request.route_url("section1")) # Redirect
Edited:
Actually you can do that on client side with Javascript, first you should send particular response to client side(either with flashes some data or return Response object):
window.location = '{{ request.route_path("route_name") }}';
Assuming your homepage is the default view of your pyramid web app, you can do:
def _get_link_form(post_data):
""" Returns the initialised form object """
return LinkForm(post_data)
def home_page(request):
form = _get_link_form(request.POST)
return {'form' : form}
def save_post(request):
form = _get_link_form(request.POST)
if not form.validate():
from pyramid.httpexceptions import HTTPFound
return HTTPFound(location=request.application_url)
Basically you need to know how the home_page view was "added" to your Configurator. If your homepage actually lives at /few/levels/deep/homepage then a redirect might look like this:
return HTTPFound(location=request.application_url + '/few/levels/deep/homepage')
A clean way is using the "overload" provided by pyramid for different request types, por example, you can decorate your methods this way:
#action(request_method='GET',
renderer='mypackage:/templates/save.mako',
name='save')
def save(request):
''' Fill the template with default values or leave it blank'''
return {}
#action(request_method='POST',
renderer='mypackage:/templates/save.mako',
name='save')
def save_post(request):
""" form data is submitted here """"
# process form
In the HTML, you must call the action form, like
<form method="POST" id="tform" action="${request.route_url('home', action='save')}">
This way, one method is processed when the method POST is used, and the other when the GET is used. The same name, but two implementations.