django add() takes exactly 2 arguments (3 given) - django

models.py
#!/usr/bin/env python
from django.db import models
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import os
import json
import sys
import tempfile
import traceback
import re
import psycopg2
SUCCESS = 1
ERR_BAD_CREDENTIALS = -1
ERR_USER_EXISTS = -2
ERR_BAD_USERNAME = -3
ERR_BAD_PASSWORD = -4
class UsersModel(models.Model):
user = models.CharField(primary_key=True, max_length=128)
password = models.CharField(max_length=128)
count = models.IntegerField()
def login(user1, password1):
try:
con = psycopg2.connect(database='test', user='jeffrey')
cur = con.cursor()
cur.execute('SELECT user FROM UsersModel WHERE user1=user AND password1=password;')
rows = cur.fetchall()
print rows
if len(rows) == 1:
#on success update the count and return the count
cur.execute('UPDATE UsersModel SET count=count+1 WHERE user1=user AND password1=password;')
cur.execute('SELECT count FROM UsersModel WHERE user1=user AND password1=password;')
return cur.fetchone()[0]
else:
return ERR_BAD_CREDENTIALS
except psycopg2.DatabaseError, e:
print 'Error %s' % e
sys.exit(1)
def add(user1, password1):
try:
if user1=='' or len(user1)>128:
return ERR_BAD_USERNAME
elif len(password1)>128:
return ERR_BAD_PASSWORD
con = psycopg2.connect(database='test', user='jeffrey')
cur = con.cursor()
cur.execute('SELECT user FROM login_UsersModel WHERE user1=user;')
rows = cur.fetchall()
if len(row) == 1:
return ERR_USER_EXIST
else:
cur.execute('INSERT INTO login_UsersModel VALUES (user1, password1, 1);')
cur.execute('SELECT count FROM login_UsersModel WHERE user1=user AND password1=password;')
return cur.fetchone()[0]
except psycopg2.DatabaseError, e:
print 'Error %s' % e
sys.exit(1)
def TESTAPI_resetFixture(request):
con = psycopg2.connect(database='test', user='jeffrey')
cur = con.cursor()
cur.execute('DELETE FROM login_UsersModel')
return SUCCESS
views.py
from django.shortcuts import render
from django.http import HttpResponse
from login.models import UsersModel
from django.utils import simplejson
import os
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
def loginx(request):
data = simplejson.loads(request.body)
name = data['user']
pw = data['password']
x = UsersModel()
code = x.login(name, pw)
if code > 0:
response_data = {'errCode':1, 'count':code}
return HttpResponse(simplejson.dumps(response_data), content_type="application/json")
else:
response_data = {'errCode':code}
return HttpResponse(simplejson.dumps(response_data), content_type="application/json")
#csrf_exempt
def addx(request):
data = simplejson.loads(request.body)
name = data['user']
pw = data['password']
x = UsersModel()
code = x.add(name, pw)
if code > 0:
response_data = {'errCode':1, 'count':code}
return HttpResponse(simplejson.dumps(response_data), content_type="application/json")
else:
response_data = {'errCode':code}
return HttpResponse(simplejson.dumps(response_data), content_type="application/json")
#csrf_exempt
def TESTAPI_resetFixturex(request):
x = UsersModel()
code = x.TESTAPI_resetFixture()
response_data = {'errCode': code}
return HttpResponse(simplejson.dumps(response_data), content_type="application/json")
#csrf_exempt
def unitTests(request):
os.system("make func_tests TEST_SERVER=localhost:8000")
return
url.py
from django.conf.urls import patterns, include, url
from django.contrib import admin
from login.views import loginx
from login.views import addx
from login.views import TESTAPI_resetFixturex
admin.autodiscover()
urlpatterns = patterns('',
# Examples:
# url(r'^$', 'mysite.views.home', name='home'),
# url(r'^blog/', include('blog.urls')),
#url(r'^admin/', include(admin.site.urls)),rs
url(r'^users/login', loginx),
url(r'^users/add', addx),
url(r'^TESTAPI/resetFixture', TESTAPI_resetFixturex)
#url(r'^TESTAPI/unitTests', unitTests)
)
ive seen similar questions been asked before on stackoverflow, but their solutions were not able to help me and lead me to other errors. so yea i dont understand how 3 arguments can be given to add when i only put users and password as my argument in view. can someone help me. btw i am only testing the add function right now in view using:
curl -H "Content-Type: application/json" -H "Accept: application/json" -X POST -d '{"user":"test", "password":"test"}' localhost:8000/users/add -o test.html

The instance (conventionally referenced by self) is passed to each instance method of a class. This question explains some more about what self is and repreesnts. In addition there are a great number of high quality oop python tutorials.
I am assuming add is method of UsersModel (if it is please correct indentation, as it matters immensely`)
in which case your function definition should look like:
def add(self, user1, password1):
Additionally, i think it would be a great help to do the django tutorial. Django has created an ORM to allow you to interact with a database without writing any sql!:) It is extremely easy to use. Also django has a built in User model that provides authentication and user creation out of the box

Related

Django redirecting

I can't figure out why my redirection after paying doesn't work.
I'm trying to display the thank_you template once the user has paid via Paypal. My code all works other than the final render of the thank_you template (I receive the email and see the 'Made it' print statement).
Urls:
from django.urls import path
from . import views
app_name = 'checkout'
urlpatterns = [
path('', views.checkout, name='checkout'),
path('thank_you', views.thank_you, name='thank_you'),
path('order_success', views.order_success, name='order_success'),
]
Views.py:
import json
from django.shortcuts import render, redirect, reverse, HttpResponseRedirect
from django.http import JsonResponse
from django.contrib import messages
from django.urls import reverse
from profiles.models import UserProfile
from products.models import Product
from django.views.decorators.http import require_POST
from .models import Order, OrderDetail
from django.core.mail import send_mail
from the_rescuers.settings import DEFAULT_FROM_EMAIL
from templated_email import send_templated_mail
from .forms import OrderForm
def checkout(request):
bag = request.session.get('bag', {})
if not bag:
messages.error(request, "There's nothing in your bag at the moment")
return redirect(reverse('products:products_list'))
order_form = OrderForm()
bag_products = []
for item_id, quantity in bag.items():
product = Product.objects.get(pk=item_id)
name = product.name
id = product.id
bag_products.append({'name': name, 'id': id, 'quantity': quantity})
bag_products = json.dumps(bag_products)
# Attempt to prefill the form with any info the user maintains in
# their profile
if request.user.is_authenticated:
profile = UserProfile.objects.get(user=request.user)
order_form = OrderForm(initial={
'first_name': profile.default_first_name,
'last_name': profile.default_last_name,
'email': profile.default_email,
'phone_number': profile.default_phone_number,
'country': profile.default_country,
'postcode': profile.default_postcode,
'city': profile.default_city,
'street_address_1': profile.default_street_address_1,
'street_address_2': profile.default_street_address_2,
'county': profile.default_county,
})
template = 'checkout/checkout.html'
success_url = '/checkout/order_success'
thank_you = '/checkout/thank_you'
context = {
'order_form': order_form,
'success_url': success_url,
'bag_products': bag_products,
'thank_you': thank_you,
}
return render(request, template, context)
def order_success(request):
"""
View that creates a new object with the JSON data, then redirects to the
thankyou page.
"""
# Take the request, decode it, split it into bag_contents and order_data
# and use this data to create a new order
request2 = request.body
my_json = request2.decode('utf8').replace("'", '"')
json_data = json.loads(my_json)
bag_contents = json_data.get('bagContents')
bag_contents = json.loads(bag_contents)
order_data = json_data.get('jsonData')
order_data = json.loads(order_data)
# Manually fill the user_id field with the user's id
order_data["user_id"] = request.user.id
# Remove the csrf token from the data
order_data.pop("csrfmiddlewaretoken", None)
# Create a new instance of the Order model using the order_data received
order = Order.objects.create(**order_data)
order.save()
# Loop through the bag_contents and save the details in OrderDetail model
for item in bag_contents:
product = Product.objects.get(pk=item['id'])
order_detail = OrderDetail(order=order, product=product,
quantity=item['quantity'])
order_detail.save()
order.update_total()
# Create a value to check in the thank_you view
request.session['redirected_from_order_success'] = True
print("Original: ", request.session)
# Send email to the provided email address
send_templated_mail(
template_name='order_confirmation',
from_email=DEFAULT_FROM_EMAIL,
recipient_list=[order.email],
context={'name': order.first_name,
'order_number': order.order_number,
'order_total': order.order_total,
},
)
return HttpResponseRedirect(reverse('checkout:thank_you'))
def thank_you(request):
"""
View that displays the thankyou page after processing an order.
"""
# Redirect to the custom 404 page if trying to access the page without
# making an order
if request.session.get('redirected_from_order_success'):
# Clear the bag and redirection token now that the order has been
# created
request.session.pop('bag', None)
request.session['redirected_from_order_success'] = False
print("Made it: ", request.session)
return render(request, 'checkout/thank_you.html')
else:
print("Diverted it: ", request.session)
return render(request, "404.html")
Relevant Checkout.html Javascript:
function completeOrder(){
let url = '{{ success_url }}'
const request= fetch(url, {
method: 'POST',
headers:{
'Content-type':'application/json',
'X-CSRFToken': csrftoken,
},
body:JSON.stringify({"bagContents": bagContents, "jsonData": jsonData} )
})
}
onApprove: (data, actions) => {
return actions.order.capture().then(function (orderData) {
const transaction = orderData.purchase_units[0].payments.captures[0];
return completeOrder()})
}
What's confusing is that the GET request for the thank_you template is made and gives a 200, it just doesn't move from the checkout page?
[24/Jan/2023 08:43:02] "POST /checkout/order_success HTTP/1.1" 302 0
Made it: <django.contrib.sessions.backends.db.SessionStore object at 0x7f75867dcb50>
[24/Jan/2023 08:43:03] "GET /checkout/thank_you HTTP/1.1" 200 6287
Any help would be much appreciated!

AssertionError: No templates used to render the response

I solved the problem while writing this question but I wanted to post it so maybe someone needs this answer
Hello my friends.
i am new to django testing.
while i'm testing my views i faced this error in some views.
This is my views.py:
def all_programs(request):
programs = Program.objects.all()
return render(request, 'orders/all_programs.html', {'programs': programs})
def checkout(request, slug):
if request.method == 'POST':
# get data from form and save it
program = get_object_or_404(Program, slug=slug)
dates = ProgramDate.objects.filter(program=program)
return render(request, 'orders/checkout.html', {'program': program, 'dates': dates})
This is urls.py:
from django.urls import path
from django.views.generic import RedirectView
from .views import *
app_name = 'orders'
urlpatterns = [
path('', RedirectView.as_view(url='https://www.another-website.net')),
path('tests/', all_programs, name='all_programs'),
path('checkout/<str:slug>/', checkout, name='checkout'),
path('checkout/return_page/', ReturnPage.as_view(), name='return_page'),
]
And this is test_views.py:
from django.test import TestCase
from django.shortcuts import reverse
class TestViews(TestCase):
def test_all_programs(self):
response = self.client.get(reverse('orders:all_programs'))
self.assertTemplateUsed(response, 'orders/all_programs.html')
def test_checkout(self): # error id here
response = self.client.get(reverse('orders:all_programs', kwargs={'slug': 'test'})) # I tried this
# response = self.client.get('http://127.0.0.1:8000/checkout/test/') #and this
self.assertTemplateUsed(response, 'orders/checkout.html')
The solution in this case is:
The test in Django does not use the default database but rather creates its own database that does not have any records (I completely forgot that), so you must create records before you start tests that relate to the database.
in this case i must create new program before test:
class TestViews(TestCase):
_program = {
'name': 'test_program',
'price': 1000,
'abbreviation': 'test',
'description': 'test_program',
'slug': 'test_program',
'id_from_zoho': 1000,
}
def test_checkout(self):
program = Program(**self._program)
program.save()
response = self.client.get(reverse('orders:checkout', kwargs={'slug': program.slug}))
self.assertTemplateUsed(response, 'orders/checkout.html')

forking django-oscar views shows an error

I forked customer app , to add a tab in http://oscar/accounts/...(example products)
to edit/show catalogue Views (Dashboard>Catalogue)
Error that I get to use that view is
django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.
I used views with the same method for payment checkout, but this one runs into errors.
# yourappsfolder.customer.apps.py
import oscar.apps.customer.apps as apps
from oscar.apps.dashboard.catalogue import apps as dapps
from django.views import generic
from django.conf.urls import url
from oscar.core.loading import get_class
from .views import ProductListView
class CustomerConfig(apps.CustomerConfig):
name = 'yourappsfolder.customer'
def ready(self):
super().ready()
self.extra_view =ProductListView
def get_urls(self):
urls = super().get_urls()
urls += [
url(r'products/',self.extra_view.as_view(),name='Products'),
]
return self.post_process_urls(urls)
This is the view I copied from oscar.apps.dashboard.catalogue
# yourappsfolder.customer.views
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
from django.views import generic
from oscar.apps.dashboard.catalogue.views import ProductListView as UserProductListView
class ProductListView(UserProductListView):
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['form'] = self.form
ctx['productclass_form'] = self.productclass_form_class()
return ctx
def get_description(self, form):
if form.is_valid() and any(form.cleaned_data.values()):
return _('Product search results')
return _('Products')
def get_table(self, **kwargs):
if 'recently_edited' in self.request.GET:
kwargs.update(dict(orderable=False))
table = super().get_table(**kwargs)
table.caption = self.get_description(self.form)
return table
def get_table_pagination(self, table):
return dict(per_page=20)
def filter_queryset(self, queryset):
"""
Apply any filters to restrict the products that appear on the list
"""
return filter_products(queryset, self.request.user)
def get_queryset(self):
"""
Build the queryset for this list
"""
queryset = Product.objects.browsable_dashboard().base_queryset()
queryset = self.filter_queryset(queryset)
queryset = self.apply_search(queryset)
return queryset
def apply_search(self, queryset):
"""
Search through the filtered queryset.
We must make sure that we don't return search results that the user is not allowed
to see (see filter_queryset).
"""
self.form = self.form_class(self.request.GET)
if not self.form.is_valid():
return queryset
data = self.form.cleaned_data
if data.get('upc'):
# Filter the queryset by upc
# For usability reasons, we first look at exact matches and only return
# them if there are any. Otherwise we return all results
# that contain the UPC.
# Look up all matches (child products, products not allowed to access) ...
matches_upc = Product.objects.filter(upc__iexact=data['upc'])
# ... and use that to pick all standalone or parent products that the user is
# allowed to access.
qs_match = queryset.filter(
Q(id__in=matches_upc.values('id')) | Q(id__in=matches_upc.values('parent_id')))
if qs_match.exists():
# If there's a direct UPC match, return just that.
queryset = qs_match
else:
# No direct UPC match. Let's try the same with an icontains search.
matches_upc = Product.objects.filter(upc__icontains=data['upc'])
queryset = queryset.filter(
Q(id__in=matches_upc.values('id')) | Q(id__in=matches_upc.values('parent_id')))
if data.get('title'):
queryset = queryset.filter(title__icontains=data['title'])
return queryset
You have a circular import - move the import of the list view into the ready() method of the app config:
class CustomerConfig(apps.CustomerConfig):
name = 'yourappsfolder.customer'
def ready(self):
super().ready()
from .views import ProductListView
self.extra_view =ProductListView

Django Unit Testing (with DRF): How to test a Passwordresetview?

I'm currently trying to write my unittest for a successfull password reset.
TLDR: I can't figure out how to handle the injection of the form data in the post request in the set-password view.
For context, let me give you my code first, since a line of code speaks more than 1000 words.
accounts/api/views.py:
class PasswordResetView(generics.GenericAPIView):
"""(POST) Expects email. Sends a password reset mail to email."""
permission_classes = (permissions.AllowAny,)
serializer_class = PasswordResetSerializer
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
if serializer.is_valid(raise_exception=True):
user = User.objects.get(email=serializer.data['email'])
if user.is_active and user.has_usable_password():
send_password_reset_email(user, request)
return Response(
{"detail": "A password reset email has been send."},
status=status.HTTP_204_NO_CONTENT
)
else:
return Response(
{"detail": "This users password can't be reset."},
status=status.HTTP_406_NOT_ACCEPTABLE
)
accounts/api/urls.py:
url(r'^password_reset/$', views.PasswordResetView.as_view(),
name="password_reset"),
accounts/api/serializers.py:
class PasswordResetSerializer(serializers.Serializer):
email = serializers.EmailField()
def validate_email(self, value):
if User.objects.filter(email__iexact=value).exists():
return value
else:
raise serializers.ValidationError("Email not found.")
accounts/utils.py:
from django.contrib.auth.tokens import PasswordResetTokenGenerator
from django.contrib.sites.shortcuts import get_current_site
from django.utils import six
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode
from templated_email import send_templated_mail
password_reset_token = PasswordResetTokenGenerator()
def build_email_context(user_obj, request):
current_site = get_current_site(request)
context = {
"name": "",
"domain": current_site.domain,
"uid": urlsafe_base64_encode(force_bytes(user_obj.pk)),
'token': password_reset_token.make_token(user_obj)
}
if user_obj.name != "":
context["name"]: " " + user_obj.name
return context
def send_password_reset_email(user_obj, request):
context = build_email_context(user_obj, request)
send_templated_mail(
template_name="password_reset",
from_email="noreply#ordersome.com",
recipient_list=[user_obj.email],
context=context
)
The views that are linked to the route in the email are the standard CBV PasswordResetConfirmView and PasswordResetDoneView from django.contrib.auth.
And here is the test I wrote for this password reset sequence:
api/tests/test_views.py:
from django.contrib.auth import get_user, get_user_model
from django.core import mail
from rest_framework import status
from rest_framework.authtoken.models import Token
from rest_framework.reverse import reverse as api_reverse
from rest_framework.test import APITestCase
User = get_user_model()
class UserAPIViewsTestCase(APITestCase):
def setUp(self):
User.objects.create_user(
email="testuser#test.com", password="test1234")
self.login_url = api_reverse("api:auth:login")
self.register_url = api_reverse("api:auth:register")
self.password_reset_url = api_reverse("api:auth:password_reset")
self.password_change_url = api_reverse("api:auth:password_change")
self.user_delete_url = api_reverse("api:auth:user_delete")
def test_api_auth_password_reset_success(self):
"""Test if a password reset successfully resets password."""
pre_user = User.objects.get(email="testuser#test.com")
self.assertEqual(pre_user.check_password("test1234"), True)
email_data = {
"email": "testuser#test.com",
}
email_response = self.client.post(
self.password_reset_url, email_data, format="json")
self.assertEqual(email_response.status_code,
status.HTTP_204_NO_CONTENT)
password_reset_data = {
"new_password1": "newtest1234",
"new_password2": "newtest1234"
}
password_reset_response = self.client.get(
mail.outbox[0].body[-94:-37], format="json", follow=True)
path = password_reset_response.request["PATH_INFO"]
done_url = "http://testserver" + path
password_reset_done_response = self.client.post(
done_url, password_reset_data, format="json")
post_user = User.objects.get(email="testuser#test.com")
self.assertEqual(post_user.check_password("newtest1234"), True)
The last self.assertEqual fails. But when I test the view manually, it works, so the code should be correct. How should I modify the test?
When I log out done_url it gives me http://testserver/auth/reset/MQ/set-password/, which should be the correct path.
And when I log out password_reset_done_response it says, that it is a TemplateResponse and the status_code is 200 (which should mean successful, but it's not). Also this response still seems to have the path /auth/reset/MQ/set-password/ which should not be the case anymore.
password_reset_data is not complete - there's no info to which user the new password should be applied.
from django.contrib.auth.tokens import default_token_generator
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode
...
password_reset_data = {
'uid': urlsafe_base64_encode(force_bytes(pre_user.pk)),
'token': default_token_generator.make_token(pre_user),
'new_password1': 'newtest1234',
'new_password2': 'newtest1234',
}
Other suggestions
setUp(self) should call super().setUp()
Use self.assertTrue instead of self.assertEqual
post_user is not needed, use pre_user.refresh_from_db() before last assert

Django or Django Rest Framework can't resolve url param when testing

I am using Django 1.8.4 and DRF 3.2.1 and when I run requests against the specified urls everything works fine, but when I run the tests with py.test the function update doesn't enter with the task_id param. But the url is fine.
Attached some code from urls.py and views.py and tests.py .. this is an excerpt of the code of course a lot of stuff is missing I just need eyes who can see if I am doing something wrong.
urls.py
from django.conf import settings
from django.conf.urls import include, patterns, url
from rest_framework import routers
from remotetask import views as rt_views
remotetask_detail = rt_views.RemoteTaskViewSet.as_view({'list': 'detail',
'put': 'update'})
remotetask_all = rt_views.RemoteTaskViewSet.as_view({'list': 'list'})
urlpatterns = patterns(
'',
url(r'^remotetasks/$', remotetask_all, name='api-remotetask-all'),
url(r'^remotetasks/(?P<task_id>\d+)/$', remotetask_detail,
name='api-remotetask-detail'),
url(r'^api-auth/', include('rest_framework.urls',
namespace='rest_framework')),
)
views.py
from django.shortcuts import get_object_or_404
from rest_framework import generics
from rest_framework import status
from rest_framework.response import Response
from remotetask.models import RemoteTask
from remotetask.serializers import RemoteTaskSerializer
from rest_framework import viewsets
class RemoteTaskViewSet(viewsets.ViewSet):
queryset = RemoteTask.objects.all()
serializer_class = RemoteTaskSerializer
def detail(self, request, task_id=None):
task = get_object_or_404(RemoteTask, pk=task_id)
serializer = RemoteTaskSerializer(task)
return Response(serializer.data)
def update(self, request, task_id=None):
task = get_object_or_404(RemoteTask, pk=task_id)
new_status = request.data.get('status')
status_changed = task.change_status(new_status, stdout, stderr)
if status_changed:
response_status = status.HTTP_201_CREATED
else:
response_status = status.HTTP_400_BAD_REQUEST
serializer = RemoteTaskSerializer(task)
return Response(serializer.data, status=response_status)
And finally test_views.py
import pytest
from django.core.urlresolvers import reverse
from remotetask.factories import RemoteTaskFactory
from remotetask.models import RemoteTask
from remotetask.views import RemoteTaskViewSet
import json
#pytest.fixture()
#pytest.mark.django_db
def create_remotetask():
remotetask = RemoteTaskFactory.create()
return remotetask
#pytest.fixture()
#pytest.mark.django_db()
def clean_remotetask():
RemoteTask.objects.all().delete()
#pytest.fixture()
def rq_remotetasklist(rf):
url = reverse('api-remotetask-all')
request = rf.get(url)
response = RemoteTaskViewSet.as_view({'list': 'list'})(request)
return response
#pytest.mark.usefixtures('clean_remotetask', 'create_remotetask')
#pytest.mark.django_db
def test_remotetask_changestatus(rq_remotetasklist, rf):
response = rq_remotetasklist
result = response.data.get('results')
id_to_work = result[0]['id']
rt = RemoteTask.objects.get(pk=id_to_work)
assert rt.status == 0
# new request
url = reverse('api-remotetask-detail', kwargs={'task_id':id_to_work})
params = json.dumps({'status': 2, 'stdout': 'test', 'stderr': 'ok'})
request = rf.put(url, data=params,
content_type='application/json')
new_response = RemoteTaskViewSet.as_view({'put': 'update'})(request)
assert new_response.status_code == 200
By default when a new task is created it gets status 0, so I try to change the status to 2 and it fails, doing some debugging I found that is entering on the update function on RemoteTaskViewSet but is not getting the task_id.
I've followed lots of tutorials and changed back and forth the code and still having the same issue, luckily works in production but it worries to me that I cannot make it run test cases from this code.
The error output from py.test is this:
E assert 404 == 200
E + where 404 = <rest_framework.response.Response object at 0x7f9f465ae690>.status_code
I put a debugger into the update function, seems that task_id is None, but when I print request.stream the url is /api/remotetasks/1/ 1 should be the task_id but isn't getting it, I was about to open a ticket on djangoproject but I think isn't a django bug since it works with external client, this must be something on my code, or anything else.
Update: If I use client instead rf and comment the line where I assign new_response with the call of the method, and validate directly the against request.status_code it works!!!.
Something like this:
#pytest.mark.usefixtures('clean_remotetask', 'create_remotetask')
#pytest.mark.django_db
def test_remotetask_changestatus(rq_remotetasklist, client):
response = rq_remotetasklist
result = response.data.get('results')
id_to_work = result[0]['id']
rt = RemoteTask.objects.get(pk=id_to_work)
assert rt.status == 0
# new request
url = reverse('api-remotetask-detail', kwargs={'task_id': id_to_work})
params = json.dumps({'status': 2, 'stdout': 'test', 'stderr': 'ok'})
request = client.put(url, data=params,
content_type='application/json')
assert request.status_code == 201
Now the doubt is why it doesn't work in the previous way?
The issue (as noted in the updated) is in the request assignment:
request = rf.put(url, data=params,
content_type='application/json')
new_response = RemoteTaskViewSet.as_view({'put': 'update'})(request)
assert new_response.status_code == 200
There really is no need to do the custom call to the view. That's already being done by the request assignment. It's not working in the old test because that's not how the view gets called when it's routed through the url routes.
Most importantly in the pervious code the request object is not a request, it's the response to the call. Using the old code I believe this would have worked as well:
#pytest.mark.usefixtures('clean_remotetask', 'create_remotetask')
#pytest.mark.django_db
def test_remotetask_changestatus(rq_remotetasklist, rf):
response = rq_remotetasklist
result = response.data.get('results')
id_to_work = result[0]['id']
rt = RemoteTask.objects.get(pk=id_to_work)
assert rt.status == 0
# new request
url = reverse('api-remotetask-detail', kwargs={'task_id':id_to_work})
params = json.dumps({'status': 2, 'stdout': 'test', 'stderr': 'ok'})
response = rf.put(url, data=params,
content_type='application/json')
assert response.status_code == 200