I am trying to set a cookie in a Django view. Something like this:
def my_view(request):
response = HttpResponse('Setting a cookie')
if 'my_cookie' in request.COOKIES:
return HttpResponse('Cookie found.')
else:
response.set_cookie('my_cookie', 'value')
return HttpResponse('Cookie set.')
In my mind, how it should work is this: on the first load, the cookie is not found, so its set and 'Cookie set.' is returned. If I reload the page, the cookie should be found, since it has been set already, so 'Cookie found.' is returned.
However, every time I reload, I get 'Cookie set.' for some reason. Any help? Thanks.
EDIT
I edited my code according the first comment:
def my_view(request):
response = HttpResponse('Setting a cookie')
if 'my_cookie' in request.COOKIES:
print 'Cookie found.'
response = HttpResponse(request.COOKIES['my_cookie'])
return response
else:
print 'Cookie set.'
response.set_cookie('my_cookie', 'value')
response = HttpResponse('value')
return response
I am returning the object that is being used to set the cookie. I am only trying to get the value. However, in my console, I always get 'Cookie set.', why is that?
Related
Using Django REST Framework in development, I have the following (previously working) code example, where in one view I set session data, and in another view I use that data.
And like I said, this code used to work, but now for some reason the stored session data can not be accessed anymore.
View for setting session data
#api_view(["POST"])
#permission_classes((AllowAny, ))
def set_session_data(request):
session_data_dict = loads(request.body.decode('utf-8'))
if not isinstance(session_data_dict, dict):
return Response({"message": "Expected a JSON object with key-val pairs to be sent. Key-val pairs to be set to session. Received something else.", status: status.HTTP_400_BAD_REQUEST})
try:
for key, value in session_data_dict.items():
request.session[key] = value
response_data = {"status": rest_status.HTTP_200_OK}
except:
response_data = {"status": rest_status.HTTP_500_INTERNAL_SERVER_ERROR}
return Response(response_data)
View that accesses stored session data:
#api_view(["GET"])
#permission_classes((AllowAny, ))
def check_user_logged_in(request):
try:
data = {"login_token": request.session["login_token"]}
except KeyError:
data = {"login_token": ""}
return Response(data, status=rest_status.HTTP_200_OK)
I have tested a little, and I can access the data in the session in the set_session_data view, after it has been added, like so:
request.session['login_token']
But when I try the same in the check_user_logged_in view, I get a KeyError.
So I tried checking if the sessions for both views are the same session, by checking the value of request.COOKIES[settings.SESSION_COOKIE_NAME] in each view. But in both views that results in the following error:
KeyError: 'sessionid'
Now, I have not touched the session settings, so they are the default settings from django-admin startproject. ('django.contrib.sessions' in INSTALLED_APPS, 'django.contrib.sessions.middleware.SessionMiddleware' in MIDDLEWARE, and nothing added.)
Can anyone explain why this is happening?
I made a TestCase to check if I would get the proper response and page redirection, but It's not working as I thought it would. When I tried a valid form I got the response I expected, but when I made it invalid, I still got the same response.
views.py (I left off the 'GET' 'else:')
def create_employee_profile(request):
if request.POST:
name_form = EmployeeNameForm(request.POST)
if name_form.is_valid():
new_name_form = name_form.save()
return redirect(new_name_form)
else:
return render(request,
'service/create_or_update_profile.html',
{'name_form': name_form}
)
Test.py
class TestCreateEmployeeProfileView(TestCase):
def test_redirect_on_success(self):
response = self.client.post('/service/', {
'first_name': 'Test', # Required
'middile_name': 'Testy', # Optional
'last_name': '', # Required
})
self.assertEqual(response.status_code, 200)
I guess while I am question, I might as well ask how to access the redirect to test that as well.
On success, the new path should be /service/name/1/, the '1' being the 'pk' of the created object.
I know I've seen SimpleTestCase, but I haven't found a good example or tutorial on how to use it.
If you always get a 200, that is because your form is always invalid. Your view redirects on successful save, which is a 302.
The way to test that the form has saved is to check that the new item is indeed in the database:
self.assertTrue(Employee.objects.filter(first_name='Testy').exists())
or whatever.
Here are two scenarios:
Your form is valid, it will be saved and will be redirected to new_name_form that means a successful redirection. Since it is a successful redirection, you will get status code 200.
The same thing will happen when your form is invalid, i.e it will start rendering the create_or_update_profile page. Hence successful rendering and 200 status code.
So in either way, you will get successful redirection.
If you want to check the form, this is the better approach to do:
from form import EmployeeNameForm
class TestCreateEmployeeProfileView(TestCase):
def test_redirect_on_success(self):
form = UserForm(data='first_name': 'Test', # Required
'middile_name': 'Testy', # Optional
'last_name': '',)
self.assertTrue(form.is_valid())
def test_redirect_on_failure(self):
form = UserForm(data='first_name': 'Test', # Required
'middile_name': 'Testy', # Optional
'last_name': '',)
self.assertFalse(form.is_valid())
There will be no need to test the redirection. It surely will work fine, if the form is valid.
Hope that helped.
I am having an issue where after adding SignedCookieSessionFactory to my pyramid configuration, when I attempt to refresh the page in a browser, only a blank page is returned (both head and body tags are empty). The first time I hit that page it renders as expected. A separate session also produces a blank page. In order to get the page to render again, I must restart the server. Refresh worked fine before I added the session factory, but I would lose the state when refreshing (as expected).
Pyramid config:
def main(global_config, **settings):
session_factory = SignedCookieSessionFactory('cossecret')
config = Configurator(settings=settings, session_factory=session_factory)
config.include('pyramid_jinja2')
config.include('.models')
config.include('.routes')
config.registry.games = Games()
config.scan()
return config.make_wsgi_app()
routes.py:
def includeme(config):
config.add_static_view('static', 'static', cache_max_age=3600)
config.add_route('home', '/')
config.add_route('game', '/game/{game}')
view.py:
#view_config(route_name='game', renderer='templates/game.jinja2')
def game_view(request):
""" Returns Game Play page based on ID"""
if "game_id" in request.session:
if request.matchdict['game'] != request.session["game_id"]:
if request.matchdict['game'] in request.registry.games.games:
request.session.invalidate()
request.session["game_id"] = request.matchdict['game']
else:
raise HTTPNotFound
else:
if request.matchdict['game'] in request.registry.games.games:
request.session["game_id"] = request.matchdict['game']
else:
raise HTTPNotFound
response = {}
response['game'] = request.session['game_id']
if "player_id" in request.session:
response['player_id'] = request.session['player_id']
else:
response['player_id'] = "None"
return response
I am pretty new to Pyramid, so any ideas would be appreciated. Stepping through the renderer, I noticed that the renderer scanned the html headers in the template the first time, but completely skipped over them the second time and then ignores everything after the body tag. Not sure if this helps.
So apparently in another of my views that is part of my API, there was this:
json_return = json.dumps(return_data)
response = Response
response.content_type = 'json'
response.body = json_return
return Response(content_type='json', body=json_return)
I don't know why creating two response objects would cause this behavior, but removing the first one in favor of just using the "return" line resolved the issue.
I have the url and corresponding view as follows.
url(r'^(?P<token>.*?)/ack$', views.api_ACK, name='device-api_ack')
def api_ACK(request, token):
"""
Process the ACK request comming from the device
"""
logger.info('-> api_ACK', extra={'request': request, 'token' : token, 'url': request.get_full_path()})
logger.debug(request)
if request.method == 'GET':
# verify the request
action, err_msg = api_verify_request(token=token, action_code=Action.AC_ACKNOWLEDGE)
return api_send_answer(action, err_msg)
I want to call api_ACK function with request method as GET from another view api_send_answer
I am creating one url in /device/LEAB86JFOZ6R7W4F69CBIMVBYB9SFZVC/ack in api_send_answer view as follows..
def api_send_answer(action, err_msg, provisional_answer=None):
last_action = create_action(session,action=Action.AC_ACKNOWLEDGE,token=last_action.next_token,timer=500)
url = ''.join (['/device/',last_action.next_token ,'/',Action.AC_ACKNOWLEDGE])
logger.debug('Request Url')
logger.debug(url)
response = api_ACK(request=url,token=last_action.next_token) # This is wrong
Now from api_send_answer it is redirecting to api_ACK view, but how to call api_ACK with request method as GET?
Please help..Any suggestions would be helpful to me
This line
response = api_ACK(request=url,token=last_action.next_token) is wrong because view expects HttpRequest object and you give him url instead.
if you need to return view response to user, you can use redirect:
def api_send_answer(action, err_msg, provisional_answer=None):
last_action = create_action(session,action=Action.AC_ACKNOWLEDGE,token=last_action.next_token,timer=500)
url = ''.join (['/device/',last_action.next_token ,'/',Action.AC_ACKNOWLEDGE])
logger.debug('Request Url')
logger.debug(url)
return HttpResponseRedirect(url)
if you need to do something else with view response you have to use HttpRequest object not url as parameter.
How can I get the request url in Scrapy's parse() function? I have a lot of urls in start_urls and some of them redirect my spider to homepage and as result I have an empty item. So I need something like item['start_url'] = request.url to store these urls. I'm using the BaseSpider.
The 'response' variable that's passed to parse() has the info you want. You shouldn't need to override anything.
eg. (EDITED)
def parse(self, response):
print "URL: " + response.request.url
The request object is accessible from the response object, therefore you can do the following:
def parse(self, response):
item['start_url'] = response.request.url
Instead of storing requested URL's somewhere and also scrapy processed URL's are not in same sequence as provided in start_urls.
By using below,
response.request.meta['redirect_urls']
will give you the list of redirect happened like ['http://requested_url','https://redirected_url','https://final_redirected_url']
To access first URL from above list, you can use
response.request.meta['redirect_urls'][0]
For more, see doc.scrapy.org mentioned as :
RedirectMiddleware
This middleware handles redirection of requests based on response status.
The urls which the request goes through (while being redirected) can be found in the redirect_urls Request.meta key.
Hope this helps you
You need to override BaseSpider's make_requests_from_url(url) function to assign the start_url to the item and then use the Request.meta special keys to pass that item to the parse function
from scrapy.http import Request
# override method
def make_requests_from_url(self, url):
item = MyItem()
# assign url
item['start_url'] = url
request = Request(url, dont_filter=True)
# set the meta['item'] to use the item in the next call back
request.meta['item'] = item
return request
def parse(self, response):
# access and do something with the item in parse
item = response.meta['item']
item['other_url'] = response.url
return item
Hope that helps.
Python 3.5
Scrapy 1.5.0
from scrapy.http import Request
# override method
def start_requests(self):
for url in self.start_urls:
item = {'start_url': url}
request = Request(url, dont_filter=True)
# set the meta['item'] to use the item in the next call back
request.meta['item'] = item
yield request
# use meta variable
def parse(self, response):
url = response.meta['item']['start_url']