How do i access request.user in self.client.post Testing - python

I have a model called Quote which has a ForeignKey pointing to User.
I want to make a post request to create a Quote but i don't know what data i should give to self.client.post, this is what i got so far i am talking about the test_can_save_a_POST_request:
from django.contrib.auth import get_user_model
from django.test import TestCase
from quotes.models import Quote
from quotes.views import home_page
User = get_user_model()
class HomePageTest(TestCase):
def test_uses_home_template(self):
response = self.client.get('/')
self.assertTemplateUsed(response, 'home.html')
def test_display_all_quotes(self):
user1 = User.objects.create(email="rafik#test.com", password="foo")
Quote.objects.create(text='quote 1', user=user1)
Quote.objects.create(text='quote 2', user=user1)
response = self.client.get('/')
self.assertIn('quote 1', response.content.decode())
self.assertIn('quote 2', response.content.decode())
def test_can_save_a_POST_request(self):
user1 = User.objects.create(email="rafik#test.com", password="foo")
self.client.post('/', data={
'quote_text': 'The first ever quote'
}
)

Related

How to test views with pytest whose views has LoginRequired and some specific user dependencies

I am testing a view and while testing this I am getting this error
self = <django.db.models.fields.AutoField: id>, value = ''
def get_prep_value(self, value):
from django.db.models.expressions import OuterRef
value = super().get_prep_value(value)
if value is None or isinstance(value, OuterRef):
return value
> return int(value)
E ValueError: invalid literal for int() with base 10: ''
/usr/local/lib/python3.6/site-packages/django/db/models/fields/__init__.py:965: ValueError
And I think I am getting this error because of request.user.profile.org cause mixer.blend(User) will pic some User which is not in my database means some User which hasn't a Profile, Org and many things. So, I want to know that how do I test this view, how I give that user some profile and Org(organisation). And also I was doing this like I was taking the info of some User which is in my database and passing it to #test_views.py -> test_dashboard_view()-> request.user which you can check in test_dashboard_view() the lines I have commented.......
views.py
#login_required
def dashboard_view(request):
org = request.user.profile.org
week_responses = day_wise_responses(7, org)
user_org = request.user.profile.org.name
sms_sent = org.sms_counter
email_sent = org.email_counter
today = datetime.today().date()
responses_one_week = number_of_responses(7, org)
responses_two_week = number_of_responses(14, org)
average_rating = org_average_rating(org)
responses_last_week = responses_two_week - responses_one_week
if responses_last_week:
responses_percent_change = (abs(responses_one_week - responses_last_week)/responses_last_week)*100
else:
responses_percent_change = responses_one_week*100
# last n responses
last_5_responses = last_n_responses(5, org)
# print(last_5_responses)
context = {'week_responses': week_responses, 'user_org': user_org, 'today': today,
'responses_one_week': responses_one_week, 'responses_percent_change': responses_percent_change,
'last_5_responses': last_5_responses, 'sms_sent': sms_sent, 'email_sent': email_sent,
'average_rating': average_rating}
return render(request, 'events/dashboard.html', context)
urls.py
path('dashboard/', include('fancy_tsunami.events.urls')),
test_views.py
from events.views import dashboard_view
from django.test import RequestFactory
from django.urls import resolve, reverse
from django import test
import pytest
from django.contrib.auth.models import User, AnonymousUser
#pytest.mark.django_db
class TestViews(test.TestCase):
def test_dashboard_view(self):
path = reverse('event-dashboard')
request = RequestFactory().get(path)
# Org = [{'id': 1, 'name': 'Company', 'logo': None, 'share_google_url': None, 'sharing_destinations_id': None, 'sms_counter': 0, 'email_counter': 0}]
request.user = mixer.blend(User)
# CheckUser = {'id': 3, 'password': 'argon2$argon2i$v=19$m=512,t=2,p=2$bHZkZ3Q0bmE2bEJU$N6x/LFqwI4guA', 'last_login': None, 'is_superuser': True, 'username': 'nitin', 'first_name': '', 'last_name': '', 'email': 'nitin#gmail.com', 'is_staff': True, 'is_active': True, 'date_joined': datetime.datetime(2019, 2, 21, 1, 10, 32, 146)}
# request.user = (CheckUser)
response = dashboard_view(request)
self.assertEqual(response.status_code, 200)
I got my answer actually the main problem was with redirection as #Brachamul suggested me in that question Testing whether a Url is giving 500 error or not in Django , I was being redirected somewhere else which was creating the problem. So the test was not getting passed because of that view. Thanks for giving me your precious time.
Instead of passing the request object directly to the function based views, you can try self.client.get() method which will simulate a real request coming to your views.
Django provides a test Client to simulate a user interacting with the
code at the view level.
from django.test import Client
client = Client()
client.get('/path/to/your/views/')
I know you have found your answer already but for anyone else with this issue, I suggest using Client.force_login()
Here is an example of how it works:
profile_url = reverse("forum:profile")
forum_user = ForumUser.objects.get(username="admin")
profile_data = dict(
user=forum_user
)
self.client.force_login(forum_user)
response = self.client.post(profile_url, data=profile_data)

the JSON object must be str, not 'bytes'-django for user validation

I have three different fileds username,password and role if all these three values matches then user will be able to login else he will not be able to login.
import json
from django.db import models
from django.http import HttpResponse
from rest_framework import serializers
def loginemployee(request):
body_unicode = request.body.decode('utf-8')
body = json.loads(body_unicode)
payload = body['username']
passwordcheck = body['password']
rolecheck = body['role']
if payload:
employee=models.Employees.objects.filter(Q(username=payload['username']) & Q(password=passwordcheck['password']) & (Q(role=rolecheck['role']) | Q(backup_role=payload['role'])))
# employees1=models.Employees.objects.filter(Q(email=payload['username']) & Q(role=payload['role']))
# empl=(employee+employees1);
if employee:
emp = serializers.serialize('json', employee)
return HttpResponse(emp,content_type='application/json')
can you help me the fix the issue in the above code.
i am getting error message string indices must be integers

Mocking patched class methods is not working

I'm using Django with DRF and python mock. What I am trying to do is to test my views and mock a serializer and some methods.
This is what I have:
views.py
from gmm_mobile.v1.serializers import RegisterParticipationSerializer
from gmm_mobile.v1.exceptions import GameOrCampaignDoesNotExist
from gmm_util.header import Header
from gmm_util.response import ResponseUtils
from gmm_util.permissions import MobileTokenPermission
from gmm_util.permissions import MobileTokenAuthentication
class ParticipantViewMobile(APIView):
permission_classes = (MobileTokenPermission, )
authentication_classes = (MobileTokenAuthentication, )
def post(self, request, service_id, campaign_id):
try:
environment_info = Header.get_environment_info(request)
request.data[Field.GAME_SERVICE_ID] = service_id
request.data[Field.CAMPAIGN] = campaign_id
request.data[Field.LOCATION] = environment_info
participation_serializer = RegisterParticipationSerializer(data=request.data)
participation_serializer.is_valid(raise_exception=True)
participation_serializer.save()
return ResponseUtils.created()
except Http404:
raise GameOrCampaignDoesNotExist()
serializers.py
class RegisterParticipationSerializer(serializers.ModelSerializer):
location = LocationSerializer(many=False)
campaign = serializers.IntegerField()
game_service_id = serializers.CharField(max_length=254)
class Meta:
model = Participation
fields = (Field.PK, Field.EMAIL, Field.GPG_ID, Field.DATE, Field.LOCATION, Field.INFO, Field.CAMPAIGN,
Field.GAME_SERVICE_ID, Field.GCM_ID)
read_only_fields = (Field.GCM_ID,)
test_views.py
from mock import patch
from django.core.urlresolvers import reverse
from rest_framework.test import APITestCase, APIRequestFactory
from rest_framework import status
from rest_framework.exceptions import ValidationError
from gmm_mobile.v1.views import ParticipantViewMobile
from gmm_mobile.v1.urls import CONSULT_PARTICIPANT
from gmm_push.environment_configuration import EnvironmentConfiguration
from gmm_util.util_test import JsonObjects
class ParticipantViewMobileTests(APITestCase):
factory = APIRequestFactory()
url = reverse(PARTICIPANT_MOBILE, kwargs={'service_id': 1, 'campaign_id': 1})
def setUp(self):
self.view = ParticipantViewMobile.as_view()
#patch('gmm_mobile.v1.views.RegisterParticipationSerializer')
def test__post__invalid_data__status_400(self, mock_serializer):
# Arrange
mock_serializer.is_valid.side_effect = ValidationError({})
request = self.factory.post(
self.url,
{},
HTTP_X_ENV=JsonObjects.environment_info_1(),
HTTP_X_TOKEN=EnvironmentConfiguration.get_token(False),
format='json')
# Act
response = self.view(request, 1, 1)
# Assert
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
But when I run the test, the side_effect is not working. When I change the .is_valid in the test it has no effect on ParticipantViewMobile.post.
If I do #patch('gmm_mobile.v1.views.RegisterParticipationSerializer.is_valid') and mock_serializer.side_effect = ValidationError({}) it works, but I don't want that because there will be cases that I will need to mock more than one method, like .save and .is_valid.
I also tried to change the import styles views.py and test_views.py but it still didn't work.
Am I doind something wrong or missing anything?
EDIT 1:
I've put prints on the view to try to understand what was happening:
def post(self, request, service_id, campaign_id):
try:
environment_info = Header.get_environment_info(request)
request.data[Field.GAME_SERVICE_ID] = service_id
request.data[Field.CAMPAIGN] = campaign_id
request.data[Field.LOCATION] = environment_info
participation_serializer = RegisterParticipationSerializer(data=request.data)
print RegisterParticipationSerializer.is_valid.side_effect
print participation_serializer.is_valid.side_effect
participation_serializer.is_valid(raise_exception=True)
participation_serializer.save()
return ResponseUtils.created()
except Http404:
raise GameOrCampaignDoesNotExist()
And the output:
{}
None
So, when I create an instance of RegisterParticipationSerializer, I lost the mocked methods. How to avoid this?
Your mock doesn't work because you're mocking the class and not the instance being generated from the class. Try this:
mock_instance = Mock()
mock_instance.is_valid.side_effect = ValidationError({})
mock_serializer.return_value = mock_instance

Flask-appbuilder problems when try to redirect a form

I'm having fun with flask and flask-appbuilder module and I have one problem which I can't resolve. I have this piece of code in my views.py:
from flask.ext.appbuilder import AppBuilder, BaseView, expose, has_access, SimpleFormView
from flask_appbuilder._compat import as_unicode
from app import appbuilder
from wtforms import Form, StringField, BooleanField, TextField, SelectMultipleField
from wtforms.validators import DataRequired
from flask_appbuilder.fieldwidgets import BS3TextFieldWidget, DatePickerWidget
from flask.ext.appbuilder.forms import DynamicForm
from flask.ext.babelpkg import lazy_gettext as _
from wtforms.fields.html5 import DateField
from flask import flash, send_file, redirect, url_for
from scripts.create_excel import excelstuff
class MyView(BaseView):
default_view = 'method1'
#expose('/method1/')
#has_access
def method1(self):
# do something with param1
# and return to previous page or index
return 'Hello'
#expose('/method2/<string:param1>')
#has_access
def method2(self, param1):
# do something with param1
# and render template with param
param1 = 'Goodbye %s' % (param1)
return param1
#expose('/method3/<string:param1>')
#has_access
def method3(self, param1):
# do something with param1
# and render template with param
param1 = 'Goodbye %s' % (param1)
self.update_redirect()
return self.render_template('method3.html',
param1=param1)
#expose('/download/<string:filename>')
#has_access
def download(filename):
return send_file(appbuilder.app.config['UPLOAD_FOLDER'] + filename,
as_attachment=True)
# Forms
class MyForm(DynamicForm):
field1 = StringField(('Field1'),
description=('Your field number one!'),
validators=[DataRequired()], widget=BS3TextFieldWidget())
field2 = StringField(('Field2'),
description=('Your field number two!'), widget=BS3TextFieldWidget())
start = DateField('Start Date', format='%Y-%m-%d', validators=[DataRequired()], widget=DatePickerWidget())
end = DateField('Start Date', format='%Y-%m-%d', validators=[DataRequired()], widget=DatePickerWidget())
project1 = SelectMultipleField('Projects', choices=[('1', 'Choice1'), ('2', 'Choice2'), ('3', 'Choice3')],
coerce=unicode, validators=[DataRequired()])
username = StringField('Username', validators=[DataRequired()], widget=BS3TextFieldWidget())
class MyFormView(SimpleFormView):
default_view = 'this_form_get'
form = MyForm
form_title = 'This is my first form view'
message = 'My form submitted'
def form_post(self, form):
# process form
flash(as_unicode(form.field1.data), 'info')
excelstuff(as_unicode(form.field1.data))
return redirect(url_for('myview.download', filename='demo.xlsx'))
appbuilder.add_view(MyFormView, "My form View", icon="fa-group", label=_('My form View'),
category="My Forms", category_icon="fa-cogs")
appbuilder.add_view(MyView, "Method1", category='My View')
appbuilder.add_link("Method2", href='/myview/method2/john', category='My View')
appbuilder.add_link("Method3", href='/myview/method3/john', category='My View')
I sending my form and I executing another python function which creates an xls file with content sent by the form, but I don't know how can I do to redirect to this xls file and download it, this is the specific piece of code:
def form_post(self, form):
# process form
flash(as_unicode(form.field1.data), 'info')
excelstuff(as_unicode(form.field1.data))
return redirect(url_for('myview.download', filename='demo.xlsx'))
You have two problems.
1 - url_for is casesensitive, so do it like this:
return redirect(url_for('MyView.download', filename='demo.xlsx'))
2 - SimpleFormView.form_post is just for form processing the answer is made by the framework, so in this case you should override 'this_form_post'
#expose("/form", methods=['POST'])
#has_access
def this_form_post(self):
self._init_vars()
form = self.form.refresh()
if form.validate_on_submit():
flash(as_unicode(form.field1.data), 'info')
excelstuff(as_unicode(form.field1.data))
return redirect(url_for('MyView.download', filename='demo.xlsx'))
else:
widgets = self._get_edit_widget(form=form)
return self.render_template(
self.form_template,
title=self.form_title,
widgets=widgets,
appbuilder=self.appbuilder
)
I Have not tested it, tell me if it worked.

Links in django_facebook app result in Bad Request: missing signed_request

I'm using the django_facebook library installed on pythonanywhere.
When I click a link from one view to another, I get an error message:
400 Bad Request
Missing signed_request.
Could someone give me the brief on how links work in a facebook app?
Removing the #canvas_only decorator doesn't solve the problem, because I need access to the graph api.
Here's the code:
views.py:
from django.shortcuts import render
from django_facebook.decorators import canvas_only
#from django_facebook.decorators import facebook_required
#from django.utils.decorators import method_decorator
from models import Poem, Share
from django import forms
from django.views.generic import View
class PoemEntryForm(forms.Form):
words = forms.CharField( widget=forms.widgets.Textarea(), initial='ENTER\nPOEM\nHERE\nONE\nWORD\nPER\nLINE' )
#canvas_only
def home(request):
me = request.facebook.graph.get_object('me')
my_username = me['username']
request.session['username'] = my_username
try:
poems = Poem.objects.filter(user=my_username)
except Poem.DoesNotExist:
poems = []
# convert poems into tuples of information relevant to the home page
# sort them in reverse chronological order
# ie: title and created
poems = [(poem.title(), poem.created) for poem in sorted(poems, key=lambda poem: poem.created, reverse=True)]
try:
shared = Share.objects.filter(shared_to=my_username)
except Share.DoesNotExist:
shared = []
shared = [(poem.title(), poem.user, poem.created) for poem in sorted(shared, key=lambda poem: poem.created, reverse=True)]
return render(request, 'home.html', {
'me': me,
'my_poems': poems,
'shared': shared,
})
class Create(View):
##method_decorator(canvas_only)
def get(self, request, *args, **kwargs):
#self.me = request.facebook.graph.get_object('me')
form = PoemEntryForm(request.GET)
return render(request, 'create.html', {
'form': form,
'debug': request.session['username']
})
##method_decorator(canvas_only)
def post(self, request, *args, **kwargs):
if request.session['username']:
form = PoemEntryForm(request.POST)
poem = Poem()
poem.user = request.session['username']
poem.text = request.POST['words']
poem.save()
return render(request, 'submitted.html', {})
else:
return render(request, 'error_submitting.html', {})
submitted.html:
<html>
<body>
<h3>You submitted a poem</h3>
Home
</body>
</html>
So the deal is this.
When the django, or whatever is doing the replying replies with: missing signed_request., what it really means is that the session doesn't contain an entry of key 'signed_request'. You can find this request in the POST data of the initial request. Save it in the session, and you're good to go.

Categories

Resources