So I'm trying to confirm the location of a given view during testing. The docs say:
You can also use dictionary syntax on the response object to query the
value of any settings in the HTTP headers. For example, you could
determine the content type of a response using
response['Content-Type'].
However, when I put it to use I'm getting a key error. Help please.
Test:
def test_normal_rewardstore_usage(self):
logged_in = self.client.login(username=self.u1.username, password="psst")
response = self.client.get(reverse('rewards:rewardstore'))
location = "http://testserver%s" % (reverse('rewards:rewardpage', kwargs={'company':self.r1.company.slug, 'slug':self.r1.slug}))
self.assertEqual(response.status_code, 200)
self.assertEqual(response['Location'], location)
Error:
Traceback (most recent call last):
File "/app/rewards/tests/test_views.py", line 58, in test_normal_rewardstore_usage
self.assertEqual(response['Location'], location)
File "/app/.heroku/python/lib/python2.7/site-packages/django/http/response.py", line 189, in __getitem__
return self._headers[header.lower()][1]
KeyError: 'location'
View:
def RewardStore_Index(request, template='rewards/reward-store.html', page_template='rewards/rewards_page.html'):
user = User.objects.get(pk=request.user.pk)
contact = Contact.objects.get(user__pk=request.user.pk, is_active=True)
if request.user.is_authenticated():
a = Member.objects.get(pk=request.user.pk)
a = a.account_verified
rewards = Reward.objects.filter(country__iso=contact.get_country)
else:
a = False
g = GeoIP()
c = g.country(request.user)
c = c['country_code']
rewards = Reward.objects.filter(country__iso=c)
context = {
'targetuser': request.user,
'rewards': rewards,
'page_template': page_template,
'email_authenticated': True if a else False,
'notifications': NotificationMap.objects.filter(user__pk=request.user.pk, read=False).prefetch_related('notification', 'notification__users')
}
if request.is_ajax():
template = page_template
return render_to_response(
template, context, context_instance=RequestContext(request))
The headers made available in the response object will vary depending on the server used (source), so it wouldn't surprise me if the django test runner doesn't send back all the headers that you see in production. Also, Location is generally used with redirecting responses, and you're asserting that you receive a 200 first. Are you sure that you should be expecting a Location header in this circumstance?
Related
I'm getting TypeError log_update() got multiple values for argument 'user' when trying to create an instance in the database.
Constructor
class ChangeLogManager(models.Manager):
use_in_migration = True
def log_update(user, content_type, object_id, content_object, changes, date_of_change):
return self.model.objects.create(
user = user,
content_type = content_type,
object_id = object_id,
content_object = content_object,
changes = changes,
date_of_change = date_of_change,
)
views
def editUser(request, pk):
# Query appropriate user based on pk returned in url
user = User.objects.get(pk = pk)
# Get the EditUserForm and add the user as instance
edit_user_form = EditUserForm(instance = user)
if request.method == 'POST':
# Bind data to the form class, and add the user as instance
edit_user_form = EditUserForm(request.POST, error_class=DivErrorList, instance = user)
old_user_instance = User.objects.get(pk = pk)
# Validate form inputs
if edit_user_form.is_valid():
# Save edits
edit_user_form.save()
# Log change
ChangeLog.change_message(request.user.id, User, old_user_instance)
else:
# error
context = {
'user': user,
'edit_user_form': edit_user_form,
}
# Render request, template and context
return render(request, 'users/backend/user/user_edit.html', context)
method
def change_message(request, obj, old_instance):
new_instance = obj.objects.get(pk = old_instance.pk)
ct = ContentType.objects.get_for_model(new_instance)
for field in obj._meta.get_fields():
if isinstance(field, models.ManyToOneRel):
continue
old_value = getattr(old_instance, field.name)
new_value = getattr(new_instance, field.name)
if old_value != new_value:
change_message = json.dumps({"field": field.name, "old_value": old_value, "new_value": new_value})
ChangeLog.objects.log_update(
user = request,
content_type = ct.pk,
object_id = new_instance.pk,
changes = change_message,
)
The error happens on the line user = request,. I've tried looking at other threads, and adding both self and moving request as the first parameter in the method without luck. I've also read that its best practice to replace the method parameters with **kwargs, but as I'm quite new, I'm not sure how to retrieve the needed parameters in the method itself.
edit - traceback
[28/Dec/2019 20:53:02] "GET /backend/users/1/edit/ HTTP/1.1" 200 30770
Internal Server Error: /backend/users/1/edit/
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/daniel/Projects/proj/Code/puro/users/views.py", line 191, in editUser
ChangeLog.change_message(request.user.id, User, old_user_instance)
File "/Users/daniel/Projects/proj/Code/puro/utils/models.py", line 63, in change_message
ChangeLog.objects.log_update(
TypeError: log_update() got multiple values for argument 'user'
You need to add self as the first argument to the log_update method and you need to pass the other required arguments to the method
ChangeLog.objects.log_update(
user = request,
content_type = ct.pk,
object_id = new_instance.pk,
content_object=new_instance,
changes = change_message,
date_of_change=datetime.datetime.now()
)
I have a requirement to incorporate my existing working openstack horizon with our SSO using python-saml.
Hence i referred to demo docs which is written here:
https://github.com/onelogin/python-saml/blob/master/demo-django/demo/views.py#L113
So here as per the guide, I need to render the page as mentioned.
return render(request, 'auth/login.html', {'errors': errors, 'not_auth_warn': not_auth_warn, 'success_slo': success_slo, 'paint_logout': paint_logout, 'SSO': True})
When I am trying the same I am not getting the expected result on page, to be exact, I am not getting the exact desired page with full details. here is the more detail on the same.
Expected page(This is screenshot of page working fine, before i am enabling saml):
Actual page now(Username and password text box not visible, Because login.html file is not enough to render it, because it need form to fully display, using django_auth_views response object "res" is created for the same):
Code:
def login(request, template_name=None, extra_context=None, **kwargs):
"""Logs a user in using the :class:`~openstack_auth.forms.Login` form."""
if not request.is_ajax():.
if (request.user.is_authenticated() and
auth.REDIRECT_FIELD_NAME not in request.GET and
auth.REDIRECT_FIELD_NAME not in request.POST):
return shortcuts.redirect(settings.LOGIN_REDIRECT_URL)
# Get our initial region for the form.
initial = {}
current_region = request.session.get('region_endpoint', None)
requested_region = request.GET.get('region', None)
regions = dict(getattr(settings, "AVAILABLE_REGIONS", []))
if requested_region in regions and requested_region != current_region:
initial.update({'region': requested_region})
if request.method == "POST":
if django.VERSION >= (1, 6):
form = functional.curry(forms.Login)
else:
form = functional.curry(forms.Login, request)
else:
form = functional.curry(forms.Login, initial=initial)
if extra_context is None:
extra_context = {'redirect_field_name': auth.REDIRECT_FIELD_NAME}
if not template_name:
if request.is_ajax():
template_name = 'auth/_login.html'
extra_context['hide'] = True
else:
template_name = 'auth/login.html'
res = django_auth_views.login(request,
template_name=template_name,
authentication_form=form,
extra_context=extra_context,
**kwargs)
# Save the region in the cookie, this is used as the default
# selected region next time the Login form loads.
if request.method == "POST":
utils.set_response_cookie(res, 'login_region',
request.POST.get('region', ''))
req = prepare_django_request(request)
auth = init_saml_auth(req)
errors = []
not_auth_warn = False
success_slo = False
attributes = False
paint_logout = False
if 'sso' in req['get_data']:
return HttpResponseRedirect(auth.login())
elif 'slo' in req['get_data']:
name_id = None
session_index = None
if 'samlNameId' in request.session:
name_id = request.session['samlNameId']
if 'samlSessionIndex' in request.session:
session_index = request.session['samlSessionIndex']
slo_built_url = auth.logout(name_id=name_id, session_index=session_index)
request.session['LogoutRequestID'] = auth.get_last_request_id()
print ('set logout id'+auth.get_last_request_id())
return HttpResponseRedirect(slo_built_url)
if 'samlUserdata' in request.session:
paint_logout = True
if len(request.session['samlUserdata']) > 0:
attributes = request.session['samlUserdata'].items()
return render(request, 'auth/login.html', {'errors': errors, 'not_auth_warn': not_auth_warn, 'success_slo': success_slo, 'paint_logout': paint_logout, 'SSO': True})
Would like to know what may be the problem here, What can be the fix to overcome this issue.
I have given try as below, tried returning the TemplateResponse object which was created in above mentioned code correct working code was just returning 'res' object from code.
return res
hence I tried to return the object instead of html file. ie: 'res' instead of 'auth/login.html'.
return render(request, res, {'errors': errors, 'not_auth_warn': not_auth_warn, 'success_slo': success_slo, 'paint_logout': paint_logout, 'SSO': True})
It returns error as follow:
Getting an error as follows:
ContentNotRenderedError at /auth/login/
The response content must be rendered before it can be accessed.
During analysis, I can see that template object(res), Which is of type: class 'django.template.response.TemplateResponse'
Someone please drop thoughts to figure out how we can resolve.
I'm using Django and Python 3.7. I have this in my urls.py file
urlpatterns = [
path(r'^ajax/calculate_taxes/$', post, name='calculate_taxes'),
]
However, I'm getting a 404 when I try and invoke the logic in my test_views.py class ...
# Basic test to verify we can get valid return data
def test_calculate_tax(self):
state = 'MN'
gross = 100000
salary = 75000
json_data = json.dumps({'state': state,
'gross': gross,
'salary': salary})
response = self.client.post('/ajax/calculate_taxes/', json_data,
content_type='application/json',
HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 302) # this is OK.
print(response.content)
self.assertEqual(response.content, 2)
The view contains a simple post function
def post(request):
state = request.GET.get('state', None)
gross_income = request.GET.get('gross', None)
owner_salary = request.GET.get('salary', None)
data = {
'sole_pr_taxes': TaxCalculatorService.calc_sole_pr_taxes(state, gross_income),
's_corp_taxes': TaxCalculatorService.calc_s_corp_taxes(state, gross_income, owner_salary),
}
What am I doing wrong that is causing the 404 in my test?
You've used a regex in a path call; it's interpreting the ^ and $ characters literally. It should be just:
path('ajax/calculate_taxes/', post, name='calculate_taxes'),
You have to return a JsonResponse
return JsonResponse(data)
Trying to check if variable 'avail.end_time:' is empty,and if so redirect to a url.
But instead, I get
"The view mysite.views.enter_queue didn't return an HttpResponse object. It returned None instead." ERROR
Endtime variable is being referenced from my Availabilities model where
end_time = models.TimeField(null=False, blank=False)
I know this questions been asked before but none of the solutions given have helped solve the problem.
#login_required
def enter_queue(request):
# get the user from the Django request & map to variable
django_user = request.user
#link user_profile to django users profile model & get user's profile
user_profile = django_user.profile
#user_profile = Profile.objects.get(user=request.user)
#Map user_availabilities variable to profile from Availability model
users_availabilities = Availability.objects.filter(profile=user_profile)
#mapping user_avail to user profile
#creating an array to store all matching sessions
all_matching_sessions = []
# avail is each Availability object
for avail in users_availabilities:
if avail.end_time:
return HttpResponseRedirect(render(request,'mysite/profile.html'))
else:
matching_sessions = Session.objects.filter(end_time__lte=avail.end_time)#looping through all the sessions end times that match to availability
#adding them to the array
all_matching_sessions = all_matching_sessions + matching_sessions
#If no matching sessions are available
if len(all_matching_sessions) == 0:
#create a session
player_session = Session(
game = 'random_game',
start_time = users_availabilities[0].start_time,
end_time = users_availabilities[0].end_time,
)
player_session.save()
return render(request, 'mysite/profile.html')
else:
player_session = Session(
session = all_matching_sessions[0],
profile = user_profile
)
player_session.save()
#return HttpResponse('Waiting in queue')
return render(request, 'mysite/profile.html')
Image of the error for reference
**ERROR*
ValueError at /account/enter_queue/
The view mysite.views.enter_queue didn't return an HttpResponse object. It
returned None instead.
Request Method: GET
Request URL: http://127.0.0.1/account/enter_queue/
Django Version: 2.0.3
Exception Type: ValueError
Exception Value:
The view mysite.views.enter_queue didn't return an HttpResponse object. It
returned None instead.
Exception Location: /usr/local/lib/python3.6/site-
packages/django/core/handlers/base.py in _get_response, line 139
Python Executable: /usr/local/bin/python3.6
Python Version: 3.6.4
Python Path:
['/home/mihir/meshwell/capstone-project/siteroot',
'/usr/local/lib/python36.zip',
'/usr/local/lib/python3.6',
'/usr/local/lib/python3.6/lib-dynload',
'/usr/local/lib/python3.6/site-packages',
'/var/www/CapstoneProject/siteroot',
'/var/www/CapstoneProject/siteroot/mysite']
Server time: Thu, 5 Apr 2018 04:07:23 +0000
Traceback Switch to copy-and-paste view
/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py in
inner
response = get_response(request)
...
▶ Local vars
/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py in _get_response
"returned None instead." % (callback.__module__, view_name)
...
▶ Local vars
HttpResponseRedirect should take a URL instead of a HttpResponse object which you are returning with render()
I'm trying to test the content of messages while processing ModelForms with Django. I've got the following View (assume there's a Thing model with a required name field):
#login_required
def update(request, thing_id):
thing = Thing.objects.get(id=thing_id) # assume this works
if request.method == "POST":
form = ThingModelForm(request.POST, instance=thing)
if form.is_valid():
form.save()
messages.success(request, "Success!")
return redirect("/wherever")
else:
messages.error(request, "Oops!")
else:
form = ThingModelForm(instance=thing)
args = ("myapp/update.html", {"form": form})
kwargs = {"context_instance": RequestContext(request)}
return render_to_response(*args, **kwargs)
Now, I've got two unit tests. The first tests valid data, while the second tests invalid data. (Note that client login happens during setUp):
def test_update_account(self):
url = reverse('update', args=[1]) # assume that's a valid id
resp = self.client.post(url, {"name": "foo"})
self.assertEqual(resp.status_code, 302)
m = resp.cookies.get('messages', '')
self.assertTrue("Success!" in m.output())
And now to test invalid data:
def test_update_account_failure(self):
url = reverse('update', args=[1]) # assume that's a valid id
resp = self.client.post(url, {"name": ""}) # name is required
self.assertEqual(resp.status_code, 200)
# This works:
self.assertTrue("Oops!" in resp.content)
# This fails:
m = resp.cookies.get('messages', '')
self.assertTrue("Oops!" in m.output())
Why would accessing the message's content through the cookie work in one instance but fail in another?
Two things you could check:
When you create the request self.client.post(url, {"name": ""}) is a Thing instance returned here: thing = Thing.objects.get(id=thing_id) If not it will not reach the line of code where you set your error message: messages.error(request, "Oops!") as Thing.objects.get will throw an error.
If there are no results that match the query, get() will raise a
DoesNotExist exception.
If the first thing does return a Thing instance, you could check whether a redirect return redirect("/wherever") after setting the error message messages.error(request, "Oops!") does change anything.