Django coverage report builder .xls export test - django

Im using coverage to test a view that exports a xls file using report builder code.
This is the view code :
from report_builder.models import Report
from report_utils.mixins import DataExportMixin, generate_filename
import re
from rest_framework import viewsets
from rest_framework.views import APIView
from rest_framework.response import Response
class DownloadFileView(DataExportMixin, View):
#def dispatch(self, *args, **kwargs):
#return super(DownloadFileView, self).dispatch(*args, **kwargs)
def process_report(self, report_id, user_id,
file_type, to_response, queryset=None):
report = get_object_or_404(Report, pk=report_id)
user = User.objects.get(pk=user_id)
if not queryset:
queryset = report.get_query()
display_fields = report.get_good_display_fields()
#import pdb; pbb.set_trace()
objects_list, message = self.report_to_list(
queryset,
display_fields,
user,
preview=False,)
title = re.sub(r'\W+', '', report.name)[:30]
header = []
widths = []
for field in display_fields:
header.append(field.name)
widths.append(field.width)
if to_response:
return self.list_to_xlsx_response(
objects_list, title, header, widths)
def get(self, request, *args, **kwargs):
#report_id = 3
report_id= kwargs["report_id"]
file_type = 'xls'
user_id = 2
return self.process_report(
report_id, user_id, file_type, to_response=True)
And this is the test i wrote for it :
class test_reports_download(TestCase):
fixtures = ['test_data_cost_control_app.json']
def test_reports_select_get(self):
request = HttpRequest()
request.method = 'GET'
DownloadFileView.as_view()(request, report_id = 1, file_type = 'xls', user_id =2)
Coverage marks almost all view code as tested except for this 2 lines:
header.append(field.name)
widths.append(field.width)
Any idea why ?, i appreciate any help.
Thanks in advance

Related

Django Nested formsets for models

I'm writing a program to store analyses for patient and I need to make a form with nested forests with next scheme
Each patient has an analyses results sheet
Each result sheet has date, patient (foreign key) and set of analyses values
Each set of analyses values has strict number and strict types of analyses
Each type of analyse has it's value, name and units
For example I want to create John's analyse result sheet for blood
Patient: John
Date: 10.02.23
Set of values: 'Blood analysis'
Red blood cells: 3,23 10^9
Haemoglobin: 124 g/l
I've made models
patient/models.py
class Patient(models.Model):
hist_number = models.IntegerField(unique=True, verbose_name='Номер истории болезни')
last_name = models.CharField(max_length=32, verbose_name='Фамилия')
analysis/models.py
class PatientAnalysisResultSheet(models.Model):
an_number = models.PositiveBigIntegerField(verbose_name='Номер исследования', unique=True)
date = models.DateField(verbose_name='Дата анализа')
time = models.TimeField(verbose_name='Время')
patient = models.ForeignKey('patient.Patient', verbose_name='Пациент', on_delete=models.CASCADE)
class AnalysisType(models.Model):
name = models.CharField(max_length=256, verbose_name='Исследование', unique=True)
measurement = models.CharField(max_length=10, verbose_name='Единицы измерения')
class PatientAnalysis(models.Model):
sheet = models.ForeignKey(PatientAnalysisResultSheet, on_delete=models.CASCADE)
analysis = models.ForeignKey(AnalysisType, verbose_name='Лабораторный показатель',
on_delete=models.CASCADE)
value = models.FloatField(verbose_name='Значение')
So I googled about formsets and now did next steps:
views.py
from django.contrib import messages
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.views.generic import FormView
# Create your views here.
from django.views.generic.detail import SingleObjectMixin
from analysis.forms import PatientAnSheetFormset
from patient.models import Patient
class PatientAnSheet(SingleObjectMixin, FormView):
model = Patient
template_name = 'analysis/patient_ansheets.html'
def get(self, request, *args, **kwargs):
self.object = self.get_object(queryset=Patient.objects.all())
return super().get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
self.object = self.get_object(queryset=Patient.objects.all())
return super().post(request, *args, **kwargs)
def get_form(self, form_class = None):
return PatientAnSheetFormset(**self.get_form_kwargs(), instance=self.object)
def form_valid(self, form):
form.save()
messages.add_message(
self.request,
messages.SUCCESS,
'Изменения сохранены добавлен!'
)
return HttpResponseRedirect(self.get_success_url())
def get_success_url(self):
return reverse('patient-detail', kwargs={'pk':self.object.pk})
forms.py:
from django.forms import inlineformset_factory
from patient.models import Patient
from analysis.models import PatientAnalysisResultSheet
PatientAnSheetFormset = inlineformset_factory(Patient, PatientAnalysisResultSheet, fields='__all__', extra=1)
But now I'm stuck as I don't know how to create a set of values and how to net it to the form. Appreciate

How to redirect using a view name in Django, class-based views?

I have to redirect from one class-based View to another class-based View. I did it by:
return redirect('report')
but the suggestion was to redirect by View names. I did try this, but it doesn't work.
views.py:
class UploadView(View):
def get(self, request, *args, **kwargs):
Reservation.objects.all().delete()
template = "ReportApp/upload.html"
return render(request, template)
def post(self, request, *args, **kwargs):
# try:
csv_file = request.FILES['file']
data_set = csv_file.read().decode('UTF-8')
# setup a stream which is when we loop through each line we are able to handle a data in a stream
io_string = io.StringIO(data_set)
next(io_string)
for column in csv.reader(io_string, delimiter=',', quotechar="|"):
_ = Reservation.objects.update_or_create(
reservation_code=column[0],
checkin=column[1],
checkout=column[2],
flat=column[3],
city=column[4],
net_income=column[5],
)
# return redirect('report')
return redirect(ReportView.as_view())
upload_view = UploadView.as_view()
class ReportView(View):
def get(self, request, *args, **kwargs):
urls.py:
from .views import upload_view, report_view, city_commission_view, error_view
from django.urls import path
urlpatterns = [
path('upload', upload_view, name='upload'),
path('report', report_view, name='report'),
path('city_commission', city_commission_view, name='city_commission'),
path('error', error_view, name='error'),
]
any suggestions how to do this?
Not sure what you want to achieve and I do not see the code for class ReportView(View): def get(self, request, *args, **kwargs):
but perhaps you could try something like this:
from django.views.generic import RedirectView
class ReportView(RedirectView):
def get_redirect_url(self, *args, **kwargs):
url_params = self.kwargs
and play with that.

Testcase returning 401 even with force_autenthicate()

I'm trying to test a view of my project with the following TestCase:
def test_jump_story(self):
c = APIClient()
user = User.objects.get(username='test1')
c.login(username=user.username, password='123')
room_id = PokerRoom.objects.get(name='planning').id
room_index = PokerRoom.objects.get(name='planning').index
request = c.post(reverse('jumpstory', kwargs={'pk': room_id, 'index': room_index}))
c.force_authenticate(user=user)
self.assertEqual(200,request.status_code)
but it returns this <Response status_code=401, "application/json"> even using force_authenticate.
The view that i'm testing:
class jumpStory(APIView):
permission_classes = [IsAuthenticated]
def post(self, request, pk, index):
data= self.request.data
index = self.kwargs['index']
pk = self.kwargs['pk']
if PokerRoom.objects.filter(id=pk).exists():
body = {'index':index}
message_socket("JUMP_STORY", pk, body)
return Response({'success':"JUMP_STORY"}, status=200)
else:
return Response({'error':'message not sended'}, status=400)
What is wrong with my test?
Use APITestCase instead of django TestCase. from rest_framework.test import APITestCase.
from rest_framework.test import APITestCase
class MyTests(APITestCase)
def setUp(self):
user = User.objects.create(username=john)
user.set_password("1234")
user.save()
self.client.force_authenticate(user=user)
def test_jump_story(self):
# do your test

Accessing Middleware value for testing a Django DetailView

I am writing a test for a DetailView that queries get_object() by accessing a value set in a Middleware. This is for a Companies application and Company Model. Each user is in a Company.
To access the company throughout the project, I set the current user's Company.uuid on the request via a custom middleware.
Middleware
from django.utils.deprecation import MiddlewareMixin
class DynamicCompanyUUIDMiddleware(MiddlewareMixin):
""" Adds the current organization's UUID from the current user."""
def process_request(self, request):
try:
company_uuid = request.user.company_uuid
except:
company_uuid = None
request.company_uuid = company_uuid
That is used in the CompanyDetailView's get_object() method via a Mixin that I use for the other Company Views.
Mixin
class CompanyMixin(LoginRequiredMixin, SetHeadlineMixin):
model = Company
def get_object(self):
return get_object_or_404(
self.model,
uuid=self.request.user.company_uuid)
Test
The test that I'm trying to write is:
from django.test import RequestFactory
from django.urls import reverse, resolve
from test_plus.test import TestCase
from ..models import Company
from ..views import CompanyDetailView
class BaseCompanyTestCase(TestCase):
def setUp(self):
self.user = self.make_user()
self.object = Company.objects.create(owner=self.user, name="testcompany")
self.user.company_uuid = self.object.uuid
self.factory = RequestFactory()
class TestCompanyDetailView(BaseCompanyTestCase):
def setUp(self):
super(TestCompanyDetailView, self).setUp()
self.client.login(username="testuser", password="password")
self.view = CompanyDetailView()
self.view.object = self.object
request = self.factory.get(reverse('companies:detail'))
request.user = self.user
request.company_uuid = self.user.company_uuid
response = CompanyDetailView.as_view()(request)
self.assertEqual(response.status_code, 200)
def test_get_headline(self):
self.assertEqual(
self.view.get_headline(),
'%s Members' % self.object.name
Result
This results in a 404 with the testuser's company not being found.
Walking through it:
I create the user
Create the company for this new testuser
Set the user.company_uuid
This should allow the mixin to access the company_uuid
Therefore return the user's company in the request
However I'm not returning the company as the 404 shows.
Question
Where am I going wrong on this? Thanks in advance for your help.
Answer
I was mixing Django's Client & RequestFactory. I have corrected the code above which is correct.
I was mixing Django's Client & RequestFactory. After stepping away, I figured it out below -
from django.test import RequestFactory
from django.urls import reverse, resolve
from test_plus.test import TestCase
from ..models import Company
from ..views import CompanyDetailView
class BaseCompanyTestCase(TestCase):
def setUp(self):
self.user = self.make_user()
self.object = Company.objects.create(owner=self.user, name="testcompany")
self.user.company_uuid = self.object.uuid
self.factory = RequestFactory()
class TestCompanyDetailView(BaseCompanyTestCase):
def setUp(self):
super(TestCompanyDetailView, self).setUp()
self.client.login(username="testuser", password="password")
self.view = CompanyDetailView()
self.view.object = self.object
request = self.factory.get(reverse('companies:detail'))
request.user = self.user
request.company_uuid = self.user.company_uuid
response = CompanyDetailView.as_view()(request)
self.assertEqual(response.status_code, 200)
def test_get_headline(self):
self.assertEqual(
self.view.get_headline(),
'%s Members' % self.object.name

Get the logged in user when there is request is not defined

I am having trouble to find a way to make it work;
I need to get the queryset with a list of the team created by the current logged in user.
My form look the following :
from django import forms
from django.contrib.auth.models import User
from registration.models import MyUser
from .models import Project, Team
from django.contrib.auth import get_user_model
User = get_user_model()
class EditSelectTeam(forms.Form):
team_choice = forms.ModelChoiceField(widget=forms.RadioSelect, queryset=Team.objects.all().filter(team_hr_admin=request.User))
#team_id = forms.ChoiceField(queryset = Team.objects.filter(team_hr_admin= MyUser))
def team_select(self):
data = self.cleaned_data['team_choice']
return data
views.py:
def TeamSelect(request):
if request.method == "POST":
select_form = EditSelectTeam(request.POST)
print('sucess')
else:
select_form = EditSelectTeam(request)
return render(request,'link_project.html',
{'select_form':select_form })
I get the error that request is not define
you can pass the request using init method like:
class EditSelectTeam(forms.Form):
team_choice = forms.ModelChoiceField(widget=forms.RadioSelect, queryset=None)
def __init__(self, request, *args, **kwargs):
super(EditSelecTeam, self).__init__(*args, **kwargs)
self.fields['team_choice'].queryset = Team.objects.all().filter(team_hr_admin=request.User))
def team_select(self):
data = self.cleaned_data['team_choice']
return data
Remember pass in your form the request like:
form = your_form(request)