def test_post_request_for_api_view(self):
data = {
"email": self.user.email,
}
url = self.reverse('users:the_api', self.user.pk)
response = self.json_post(data, url=url)
self.mock.assert_called_once_with(self.user)
data2 = json.loads(response.content.decode('utf-8'))
self.assertEqual(data2, {
'booking_order': ['ABCDEFGHIJKL'],
'transaction_total': '20000.00'
})
urls.py
urlpatterns = [
url(
regex=r'^$',
view=views.UserListView.as_view(),
name='list'
),
url(
regex=r'^~redirect/$',
view=views.UserRedirectView.as_view(),
name='redirect'
),
url(
regex=r'^(?P<username>[\w.#+-]+)/$',
view=views.UserDetailView.as_view(),
name='detail'
),
url(
regex=r'^~update/$',
view=views.UserUpdateView.as_view(),
name='update'
) ,
url(
regex=r'^the_api/$',
view = views.UserApiView.as_view(),
name='the_api'
),
]
views.py
class UserApiView(APIView):
authentication_classes = authentication.TokenAuthentication ###Am assuming you're authenticating via a token
def get(self, request):
"""
Get user based on username.
Am getting only the username since that's the only field used above.
:param request:
:param format:
:return:
"""
details = User.objects.all()
serializer = UserSerializer(details, many=True)
return Response(serializer.data )
def post(self, request, format=None):
"""
Create a new user instance
:param request:
:param format:
:return:
"""
serializer = UserSerializer(request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors)
As much as i understand how reverse works in Django, i believe for the above test to pass, i only need to have a the_api url in my urls.py.
However, the test does not pass even with that.
As such, i would love to know what the right thing to do is.
How do i get the test to run?
The error i keep getting is:
django.urls.exceptions.NoReverseMatch: Reverse for 'the_api' with arguments '(1,)' and keyword arguments '{}' not found. 1 pattern(s) tried: ['users:the_api/$']
Do you have accepted argument in your url? Looking at your code you should have following entry in your urls.py file:
url(r'the_api/(\d+)/$', your_view, name="the_api")
May be you should paste your url entry too and the corresponding view so that we can look deeper into the issue.
Related
I'm writing some simple unit tests for my class based views. I've completed the tests for urls in which I've used args = ['pk'] for urls that had pks. However, when doing similar tests to views, ones with pks ends with the error Field 'id' expected a number but got 'pk' '.
Here's the working URL test:
url = reverse('user', args=['pk'])
self.assertEquals(resolve(url).func.__name__,
GetUser.as_view().__name__)
Class based view test that gets the error:
class TestViews(TestCase):
def setUp(self):
self.client = Client()
self.single_user_url = reverse('user', args=['pk'])
def test_single_user_view(self):
response = self.client.get(self.single_user_url)
self.assertEquals(response.status_code, 200)
urls.py:
urlpatterns = [
path('', GetUsers.as_view(), name='users'),
path('create/', CreateUser.as_view(), name='create-user'),
path('user/<str:pk>/', GetUser.as_view(), name='user'),
path('update/<str:pk>/', UpdateUser.as_view(), name='update-user'),
]
path('user/<int:pk>/', GetUser.as_view(), name='user'),
path('update/<int:pk>/', UpdateUser.as_view(), name='update-user'),
After submission of a create form in my web app it should redirect in to a single page where it displays the new product that is entered. instead of that, it shows :
Reverse for 'category' with keyword arguments '{'pk': UUID('e3ec4273-22c9-450f-87c9-d12973dce3c1')}' not found. 1 pattern(s) tried: ['app/products/category/<int:pk>']
views.py
def create_category(request):
if request.method=='POST':
form = CategoryForm(request.POST,request.FILES)
if form.is_valid():
data = form.save(commit=False)
data.creator = request.user
data.updater = request.user
data.auto_id = get_auto_id(ProductCategory)
data.save()
return HttpResponseRedirect(reverse('products:category',kwargs={"pk":data.pk}))
else:
...
else:
...
def category(request,pk):
instance = get_object_or_404(ProductCategory.objects.filter(pk=pk))
context = {
'title': "Category : " + instance.name,
'instance' : instance,
}
return render(request,'products/category.html',context)
urls.py
from django.urls import path
from . import views
app_name = 'products'
urlpatterns = [
path('categories',views.categories,name='categories'),
path('category/create',views.create_category,name='create_category'),
path('category/<int:pk>',views.category,name='category'),
path('category/edit/<int:pk>',views.edit_category,name='edit_category'),
path('category/delete/<int:pk>',views.delete_category,name='delete_category'),
]
Th thing is the form is submitted and the values are added to database. But it doesn't move to the next step.
I am new to django 2 so not very sure on how to pass pk in urls/path
In your url:
path('category/<int:pk>',views.category,name='category'),
^^^^
You are expecting an integer but in code you are passing an UUID. So change the url to:
path('category/<uuid:pk>',views.category,name='category'),
More information can be found in documentation.
I have written two class one for posting datas for payment and other one to show payment-successful message with order_id. I am sending order id from first function and i want to catch this id to show in my payment-successful template.
class ApiVIew(TemplateView):
template_name = 'payment.html'
def post(self,request):
r = requests.post(url='www.randomsite.com',params = {'authToken':'12345','card_no':'1234','card_cvv':'****'})
return HttpResponse(json.dumps({'response':r.json(),'status':'ok'}))
I call this class is ajax and parse there,so if r gives no error then i redirect(window.location=localhost:8000/success) to the success-payment.html page. so response gives me a json data:
{'isSuccess': 1, 'order_id': 1cq2,}
so i want to get this order_id and pass it to another function/class written below.
def payment_successfullView(request):
return render(request,'payment-successfull.html')
How can i achieve so? Thanks in advance.
1. Most simple way
urls.py:
...
path('<str:order_id>/success/', views.payment_successfullView, name='success'),
...
Views:
from django.shortcuts import redirect, reverse
class ApiVIew(TemplateView):
template_name = 'payment.html'
def post(self, request):
r = requests.post(url='www.randomsite.com',params = {'authToken':'12345','card_no':'1234','card_cvv':'****'})
if r.isSuccess:
return redirect(reverse('success', args=(r.order_id, )))
# do your stuff in case of failure here
def payment_successfullView(request, order_id):
return render(request,'payment-successfull.html', {
'order_id': order_id,
})
2. Another method using sessions:
urls.py:
...
path('success/', views.payment_successfullView, name='success'),
...
Views:
from django.shortcuts import redirect, reverse
from django.http import HttpResponseForbidden
class ApiVIew(TemplateView):
template_name = 'payment.html'
def post(self, request):
r = requests.post(url='www.randomsite.com',params = {'authToken':'12345','card_no':'1234','card_cvv':'****'})
if r.isSuccess:
request.session['order_id'] = r.order_id # Put order id in session
return redirect(reverse('success', args=(r.order_id, )))
# do your stuff in case of failure here
def payment_successfullView(request):
if 'order_id' in request.session:
order_id = request.session['order_id'] # Get order_id from session
del request.session['order_id'] # Delete order_id from session if you no longer need it
return render(request,'payment-successfull.html', {
'order_id': order_id,
})
# order_id doesn't exists in session for some reason, eg. someone tried to open this link directly, handle that here.
return HttpResponseForbidden()
Ok, I think the best answer points you in the right direction and let you figure out the fun part.
Tips:
Your APIView has to redirect to payment_successfullView
You have the order_id so you could use a DetailView
If you want to display a list of orders (order_id's) use ListView
I think using those tips, you'll be fine. Happy coding.
Note
You might want to read about Form views also, such view has an attribute called success_url. Ring a bell?
My urls.py has an entry:
urlpatterns = [
url(r'^results/(?P<query>).+', views.ResultsView.as_view(), name="results"),
]
which matches to the corresponding Class Based View:
class ResultsView(TemplateView):
template_name = os.path.join(APPNAME, "results.html")
def dispatch(self, request, *args, **kwargs):
query = kwargs['query']
print("HERE: " + str(json.dumps(kwargs, indent=1)))
print(self.kwargs['query'])
print(self.kwargs.get('query'))
print(kwargs['query'])
print(kwargs.get('query'))
if query is None:
return redirect('/')
return super(ResultsView, self).dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super(ResultsView, self).get_context_data(**kwargs)
print("HERE: " + str(json.dumps(kwargs, indent=1)))
print(self.kwargs['query'])
print(self.kwargs.get('query'))
print(kwargs['query'])
print(kwargs.get('query'))
...
# This is just here to test if 'query' is set
def get(self, request, query):
print(query)
I'm trying to get the value of the query variable that is set in urls.py. However, after trying various solutions I found on other SO posts (as you can see from all the print statements), nothing is working.
I'm fairly sure my urls.py is set up properly, because the request resolves to the correct page (results/), but all attempts to print the query entry of the dict return an empty string, and json.dumps(kwargs, indent=1)) prints this:
HERE: {
"query": ""
}
What am I doing wrong?
Just copy my comment as an answer. You missed pattern part in url's regular expression. Try to change url to this:
url(r'^results/(?P<query>[\w.-]+)', views.ResultsView.as_view(), name="results")
I defined a viewset using ModelViewSet as follow
I tried to redefine the GET method to do something like getting something from celery . but this part of code just won't work , it acts just like a standard API and didn't do what I wrote in the get_job_detail function.
How should I correctly define the "detail_route" function.
views.py
class JobViewSet(viewsets.ModelViewSet):
queryset = job.objects.all()
serializer_class = JobSerializer
#detail_route(methods=['get'])
def get_job_detail(self, request, pk=None):
# print('these part wont proceed')
job_item = self.get_object()
if job_item.isReady or job_item.isSuccessful:
return Response(self.serializer_class(job_item).data)
celeryjob = sometask.AsyncResult(pk)
celeryjob.get()
if celeryjob.state == 'SUCCESS':
job_item.state = celeryjob.state
job_item.result = celeryjob.result
job_item.isReady = True
job_item.isSuccessful = True
job_item.save()
if celeryjob.state == 'FAILURE':
job_item.state = celeryjob.state
job_item.result = celeryjob.result
job_item.isReady = True
job_item.isSuccessful = False
job_item.save()
return Response(self.serializer_class(job_item).data)
urls.py
from django.conf.urls import url, include
from apply_api import views
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'job',views.JobViewSet)
urlpatterns = [
url(r'^', include(router.urls)),
]
now your correct url is: /job/<pk>/get_job_detail if you want just: /job/<pk> you don need to use #detail_route just rename your method to the def retrieve(self, request, *args, **kwargs): more details retrievemodelmixin one of the part class of the modelviewset