i have soaplib for webservice as soap [server], all request route and response as xml by url well.but i can't fetch request http headers, How can i get request HTTP headers for rendering view some method of class ?
like this method :
def redirect_http(self,request):
return render(request, 'ask/redirect.html', {
''' 'question': question,
'error_message': "You didn't select a choice.", '''
})
Code Project :
soap.py
'''
documentation in http://soaplib.github.com/soaplib/2_0/
'''
import base64
import soaplib
from soaplib.core import Application
from soaplib.core.model import primitive as soap_types
from soaplib.core.service import DefinitionBase
from soaplib.core.service import rpc as soapmethod
from soaplib.core.server import wsgi
from soaplib.core.model.clazz import ClassModel
from soaplib.core.model.clazz import Array
from django.http import HttpResponse
# the class with actual web methods
# the class which acts as a wrapper between soaplib WSGI functionality and Django
class DjangoSoapApp(wsgi.Application):
def __call__(self, request):
# wrap the soaplib response into a Django response object
django_response = HttpResponse()
def start_response(status, headers):
status, reason = status.split(' ', 1)
django_response.status_code = int(status)
for header, value in headers:
django_response[header] = value
response = super(DjangoSoapApp, self).__call__(request.META, start_response)
django_response.content = '\n'.join(response)
return django_response
class SoapView(DefinitionBase):
#classmethod
def as_view(cls):
soap_application = Application([cls], __name__)
return DjangoSoapApp(soap_application)
# the view to use in urls.py
#my_soap_service = DjangoSoapApp([MySOAPService], __name__)
views.py
from soap import SoapView
from soap import soapmethod
from soap import soap_types, Array
class MySoapService(SoapView):
__tns__ = '[url]http://localhost:8989/api/soap/verify.wsdl[/url]'
#soapmethod(soap_types.String, soap_types.Integer, returns=soap_types.String)
def request_verify(self, q, id, uri):
#Some Code
return 'some return'
my_soap_service = MySoapService.as_view()
urls.py
from django.conf.urls import patterns, include, url
from django.views.generic import RedirectView
import views
# Main URL Patterns
urlpatterns = [
url(r'^verify', views.my_soap_service),
url(r'^verify.wsdl', views.my_soap_service),
]
problem resolved : change method request (for generate html and get http header most Observe protocol HTTP and structure), so to request and response html content should be send http request and get all headers generated
Related
I am trying to write a test which goes through the signup/login workflow, and then attempts to change the status of a user, which requires them to be logged in. I verified that the first 2 POST requests work (the user is indeed created and then gets a valid auth token after logging in), however I cannot seem to pass in said token in the headers for the 3rd and final POST request. I also checked that the auth_headers variable is indeed set with the correct token, but I keep getting back a 401 status code.
Thanks in advance!
tests.py
from email.headerregistry import ContentTypeHeader
from urllib import request
from wsgiref import headers
from django.http import HttpRequest
from django.test import TestCase, Client
from rest_framework import status
from rest_framework.test import APITestCase
from django.urls import reverse
from rest_framework.authtoken.models import Token
from django.contrib.auth.models import User
from profiles_api.serializers import UserProfileSerializer
from django.contrib.auth import get_user_model
from profiles_api.views import UserLoginApiView
client = Client()
User = get_user_model()
class MyTestCase(APITestCase,UserLoginApiView):
def test_add_status_to_profile(self):
response = self.client.post("/api/profile/", data={
'email':"John#gmail.com",
'name':'Pavle',
'password':'password'
})
response = self.client.post("/api/login/", data={
'username':"John#gmail.com",
'password':'password'
})
auth_headers = {
'Authorization': 'Bearer ' + response.json()['token']
}
response = self.client.post("/api/feed/", content_type='application/json', data={
'status_text':'Hello world!'
}, **auth_headers)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
I'm doing a feature where the user on their profile page makes changes (not related to the user model). Everything is implemented through static HTML templates. I need the user to click on the button and return to the same page (i.e., their profile page) after processing the request.
Html template
<td>Accept</td>
endpoints.py
#router.get('/invite/{pk}/decline')
async def decline_event_invite(
request: Request,
pk: int,
user_id: str = Depends(get_current_user),
service: InviteService = Depends(),
):
await service.invite_decline(pk)
...
--> here I want redirect to user profile page
return RedirectResponse('DYNAMIC URL WITH ARGS')
profile.py
#router.get('/{pk}')
async def user_profile(
request: Request,
pk: int,
service: UserService = Depends()
):
user = await service.get_user_info(pk)
events_invites = await service.get_user_events_invite_list(pk)
return templates.TemplateResponse(
'profile.html',
context=
{
'request': request,
'user': user,
'events_invites': events_invites,
}
)
But I can't find anywhere how to do a redirect similar to the logic that applies to templates. For example:
Sender
You can use url_for() function and pass the (**kwargs) path parameters.
import uvicorn
from fastapi import FastAPI, Request
from fastapi.templating import Jinja2Templates
from fastapi.responses import RedirectResponse
import urllib
from fastapi import APIRouter
router = APIRouter()
templates = Jinja2Templates(directory="templates")
#router.get('/invite/{pk}/decline')
def decline_event_invite(request: Request, pk: int):
redirect_url = request.url_for('user_profile', **{ 'pk' : pk})
return RedirectResponse(redirect_url)
#router.get('/{pk}')
def user_profile(request: Request, pk: int):
return templates.TemplateResponse("profile.html", {"request": request, "pk": pk})
if __name__ == "__main__":
uvicorn.run(router, host='127.0.0.1', port=8000, debug=True)
To add query params
In case you had to pass query params as well, you could use the following code (make sure to import urllib). Alternatively, you could use the CustomURLProcessor, as described in this and this answer (which pretty much follows the same approach).
If the endpoint expected query params, for example:
#router.get('/invite/{pk}/decline')
def decline_event_invite(request: Request, pk: int, message: str):
pass
you could use:
redirect_url = request.url_for('user_profile', pk=pk)
parsed = list(urllib.parse.urlparse(redirect_url))
parsed[4] = urllib.parse.urlencode({**{ 'message' : "Success!"}})
redirect_url = urllib.parse.urlunparse(parsed)
or even use:
message = 'Success!'
redirect_url = request.url_for('user_profile', pk=pk) + f'?message={message}'
Update
Another solution would be to use Starlette's starlette.datastructures.URL, which now provides a method to include_query_params. Example:
from starlette.datastructures import URL
redirect_url = URL(request.url_for('user_profile', pk=pk)).include_query_params(message="Success!")
CLIENT Side:
UserA requests GET /file/from/some/location
SERVER Side:
UserA request will hit the API1 which will generate a URL and redirect the user to API2 the API will take the generated URL and return the file to the user directly without sending a response to the API1.
You can use the redirect shortcut in Django to redirect to call to the other url:
urls.py:
url(r'^/file/from/some/location$', views.api_1_view, name='api_1_view')
url(r'^/file/from/some/other/second/location$', views.api_2_view, name='api_2_view')
views.py:
from django.urls import reverse
from django.shortcuts import redirect
def api_1_view(request):
url_for_api_2 = reverse('api_2_view')
return redirect(url_for_api_2)
def api_2_view(request):
# do stuff
# return the file
I'm trying to test an UpdateView that adds a message to the redirected success page. It seems my issue comes from messages because of pytest returns:
django.contrib.messages.api.MessageFailure: You cannot add messages without installing django.contrib.messages.middleware.MessageMiddleware
My test code is:
def test_authenticated_staff(self, rf):
langues = LanguageCatalog.objects.create(
lang_src='wz',
lang_dest='en',
percent='4'
)
req = rf.get(reverse("dashboard.staff:lang-update", kwargs={'pk': langues.pk}))
data = {'lang_src': 'it',
'lang_dest': 'en',
'percent': '34'}
req = rf.post(reverse(
"dashboard.staff:lang-update", kwargs={'pk': langues.pk}), data=data)
req.user = UserFactory()
resp = views.LangUpdateView.as_view()(req, pk=langues.pk)
I precise that the MessageMiddleware is present in MIDDLEWARE settings. I use Django==2.0.13.
I found the solution. In order to test a such request, you need first to annotate it with a session and then a message. Actually it means to add these lines:
from django.contrib.messages.middleware import MessageMiddleware
from django.contrib.sessions.middleware import SessionMiddleware
# in your test method:
"""Annotate a request object with a session"""
middleware = SessionMiddleware()
middleware.process_request(req)
req.session.save()
"""Annotate a request object with a messages"""
middleware = MessageMiddleware()
middleware.process_request(req)
req.session.save()
# and then (in my case)
resp = views.LangUpdateView.as_view()(req, pk=langues.pk)
You can also move manual request annotation int a separate context manager that can be reused within multiple tests, the code would look like this then:
import contextlib
from django.contrib.messages.middleware import MessageMiddleware
from django.contrib.sessions.middleware import SessionMiddleware
#contextlib.contextmanager
def middleware(request):
"""Annotate a request object with a session"""
middleware = SessionMiddleware()
middleware.process_request(request)
request.session.save()
"""Annotate a request object with a messages"""
middleware = MessageMiddleware()
middleware.process_request(request)
request.session.save()
yield request
def test_authenticated_staff(self, rf):
langues = LanguageCatalog.objects.create(
lang_src='wz',
lang_dest='en',
percent='4'
)
req = rf.get(reverse("dashboard.staff:lang-update", kwargs={'pk': langues.pk}))
data = {'lang_src': 'it',
'lang_dest': 'en',
'percent': '34'}
req = rf.post(reverse("dashboard.staff:lang-update", kwargs={'pk': langues.pk}), data=data)
req.user = UserFactory()
with middleware(req): # << !
resp = views.LangUpdateView.as_view()(req, pk=langues.pk)
My Django Rest API views.py:
# encoding: utf-8
from fileupload.response import JSONResponse, response_mimetype
from fileupload.models import *
from rest_framework.views import *
from rest_framework.parsers import *
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
"""A simple API for file upload."""
class FileUploadView(APIView):
authentication_classes = ()
#method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
return super(FileUploadView, self).dispatch(request, *args, **kwargs)
def put(self, request):
print "xxx:", request
try:
psfile = MyFile.objects.create(file=request.FILES['file'])
psfile.save()
data = {'files': 'testing'}
response = Response(data)
except Exception as e:
print "Exception when put file:", e
data = { 'error' : str(e)}
response = Response(data)
return response
setting.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': ()
}
I am doing PUT in Postman with Postman Interceptor enabled.
Tried to put the file in the body as form-data.
But failed with the following error:
Could not get any response
There was an error connecting to https://ip/projectname/api/upload/.
Why this might have happened:
1. The server couldn't send a response:
Ensure that the backend is working properly
2. SSL connections are being blocked:
Fix this by importing SSL certificates in Chrome
3. Cookies not being sent: Use the Postman Interceptor extension
4. Request timeout:
Change request timeout in Settings > General
Any ideas? Thanks in advance.
UPDATE
https://github.com/postmanlabs/postman-app-support/issues/506
http://blog.getpostman.com/2014/01/28/using-self-signed-certificates-with-postman/