Serving XML and HTML with Django - python

I have a Django App, that has to serve HTML-Files to normal Browsers, that understand HTML, and XML-Files to other clients.
In my views.py I'm trying to differentiate between the different HTTP_ACCEPT tags, the incoming HTTP request has. This seems to work already, since a normal HTML file is served as intended.
Only when i try to serve an XML file, i get an Error saying:
ValueError at /appstore/
The view appstore.views.index didn't return an HttpResponse object.
Here is my views.py
from appstore.models import App
from django.shortcuts import render_to_response, get_object_or_404
from django.http import HttpResponse
from django.core import serializers
def index(request):
if (request.META['HTTP_ACCEPT'].find('text/html') != -1):
latest_app_list = App.objects.all().order_by('name')[:5]
return render_to_response('appstore/index.html', {'latest_app_list': latest_app_list})
else:
def xml_view(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return HttpResponse(serializers.serialize("xml", result),
mimetype="text/xml")
return wrapper
#xml_view
def index(request):
return App.objects.all()
#xml_view
def get(request, id):
return get_object_or_404(App, pk=app_id)
I hope someone of you can help me.
Thanks in advance.

Related

Redirect non authenticated user to login page (for all views)

I am looking to redirect my user to login page, if they have not logged in.
I initally looked at the decorator #login_required(login_url='/accounts/login/').
But this is not ideal, for 2 reasons: first I want this to apply to all views. Also the decorator returns an error message when I try to login with allauth.
I am sure this is solvable, but I am looking for a solution that could apply to all views.
I found something using authmiddleware(doc: https://pypi.org/project/django-authmiddleware/). However the code doesn't not seem to be responsive, in the sense nothing is happening and the logs on the console don't seem to pick up anything.
Can someone see what I am doing wrong?
base.py
MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware',
'AuthMiddleware.middleware.AuthRequiredMiddleware',
]
AUTH_SETTINGS = {
"LOGIN_URL" : "login_user",
"DEFAULT_REDIRECT_URL" : None,
"REDIRECT_AFTER_LOGIN" : False,
}
views.py
from django.shortcuts import render, redirect, reverse
from django.http import HttpResponse, HttpResponseRedirect
from django.contrib.auth import authenticate, login, logout, get_user_model
from django.urls import reverse
def list_event(request): #ADDED FOLLOWING REQUEST IN COMMENTS
event_list = Event.objects.all
return render(request, 'main/list_event.html',{'event_list':event_list})
class AuthRequiredMiddleware(object):
def process_request(self, request):
if not request.user.is_authenticated():
return HttpResponseRedirect(reverse('login_user'))
return None
Found an alternative solution and thought I would leave it there.
I used a tutorial on youtube (https://www.youtube.com/watch?v=axsaC62UQOc) which, with a few changes (the video is old), works like a charm. Its about 3 videos 30 minutes very well explained.
Here it goes:
settings.py
MIDDLEWARE = [
'[yourappname].middleware.LoginRequiredMiddleware',
]
LOGIN_EXEMPT_URLS =( #<-- I am using allauth, so left some examples here)
r'logout',
r'register_user',
r'accounts/google/login/',
r'accounts/social/signup/',
r'accounts/facebook/login/',
)
middleware.py (this files goes in your main app, by default "mysite")
import re
from django.conf import settings
from django.shortcuts import redirect
EXEMPT_URLS = [re.compile(settings.LOGIN_URL.lstrip('/'))]
if hasattr(settings, 'LOGIN_EXEMPT_URLS'):
EXEMPT_URLS += [re.compile(url) for url in settings.LOGIN_EXEMPT_URLS]
class LoginRequiredMiddleware:
pass
def __init__(self, get_response):
self.get_response = get_response
def __call__ (self, request):
response = self.get_response(request)
return response
def process_view(self, request, view_func, view_args, view_kwargs):
assert hasattr(request,'user')
path = request.path_info.lstrip('/')
print(path)
if not request.user.is_authenticated:
if not any(url.match(path) for url in EXEMPT_URLS):
return redirect(settings.LOGIN_URL)
why not use
return redirect('%s?next=%s' % (settings.login_user, request.path))'
instead of HttpResponse?

'None Type' object has no attribute 'id' Hot to resolve Type Error

This is a medical inventory system.
Can't seem to get around this Type error. I am new to python and django.
I have looked at other similar errors but have not found a solution. here is my views.py file inside the home directory.
Kindly assist...thank you.
from django.shortcuts import render, redirect, Http404, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseRedirect, JsonResponse
from accounts.models import Registration, YearEnding
from home.backup import BackupDatabase
#login_required(login_url='/account/login/')
def HomePage(request):
if not request.user.is_authenticated():
raise Http404
try:
** current_session_id = request.session['session'] **
except:
** currentSession = YearEnding.objects.order_by("-id").first() **
** request.session['session'] = currentSession.id **
current_session_id = currentSession.id
current_session = get_object_or_404(YearEnding, id = current_session_id)
return render(request, 'home/index.html', {"current_session":current_session})
#login_required(login_url='/account/login/')
def takeBackup(request):
if request.method == "GET" and request.is_ajax():
forcefully = request.GET.get("forcefully")
backup = BackupDatabase()
response = backup.run(forcefully = int(forcefully))
if response["code"] == 200:
return JsonResponse(response, status=200)
else:
return JsonResponse(response, status=400)
else:
return JsonResponse({}, status=400)
As per documentation:
Returns the first object matched by the queryset, or None if there is no matching object.
Means if there is not YearEnding instance has been created, then YearEnding.objects.order_by("-id").first() will return None. So you need create one. You can do that from admin site, or shell. For example:
>> python manage.py shell
>> [python] from my_app.models import YearEnding
>> [python] YearEnding.objects.create(field1=value1,field2=value2)
One more suggestion, you can remove this code:
if not request.user.is_authenticated():
raise Http404
Because you are using #login_required decorator, it will automatically prevent non-logged in users from entering this view.

How, with Python, can i retrieve the data content of a POST request?

I have a WooCommerce webhook who sends a POST request to a specific URL (http://po.tic.ch/polls/hello) for every order on my website. This WooCommerce is running on https://vi.tic.ch.
For each order, i want to retrieve the informations of the POST like user ID = 12, product ID = 234, price = 50CHF, etc. to save it in my server po.tic.ch.
The server po.tic.ch runs Django with Apache2. He have the port 80 open and receives all the POSTS but i don't know how to get the his content.
I tried this on my views.py file:
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
import json
#csrf_exempt
def hello(request):
# r = json.loads(request.POST)
r = json.loads(request.POST.body)
print(r)
return HttpResponse(r)
def get(self, request, *args, **kwargs):
return HttpResponse('This is GET request')
def post(self, request, *args, **kwargs):
return HttpResponse('This is POST request')
the POST request on my Django
Thank You!
that's what i was searching.... thanks anyway
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
import json
#csrf_exempt
def hello(request):
r = json.loads(request.body)
mail = (r['billing']['email'])
print (mail)
return HttpResponse(r)
If your function receives all POST request, you can simply access the body via data = request.get('data', None). This will return the request data or None in case of an empty request.

The view app.views.model didn't return an HttpResponse object

This is my views.py file. i am on the way to generate xml file, The data i am getting from mysql. First time its working but i make some changes then i cant remember what i did now it s not working ...
in the views.py
def MessageHeaderModel2(request):
if request.method == "POST":
form = MessageHeaderForm(request.POST)
if form.is_valid():
DDEX_Party_Id = request.POST.get('DDEX_Party_Id',None)
data = serializers.serialize("xml", MessageHeaderModel2.objects.all())
with open("file.xml", "w") as out:
xml_serializer.serialize(MessageHeaderModel2.obj ects.all(), stream=out)
The error now i am gettin is
>Exception Type:ValueError
Exception Value:The view app.views.MessageHeaderModel2 didn't return an HttpResponse object.
Like stated in the error, your view isn't sending any response to the client.
Add at the end of your view a line like :
return render(request, 'template.html')
Or any other response, that you need
You in fact are not returning an HttpResponse object!
Django views must return an instance of HttpResponse so at the end of your view:
from django.http import HttpResponse
def view(request):
...
return HttpResponse("the page content")
You can also return may other subclasses of HttpResponse, see the documentation for a list.
You can also use some of the shortcut functions to render a page using the django templating system, again the documentation is helpful here, but briefly:
from django.shortcuts import render_to_response
def view(request):
...
return render_to_response('my_template.html',
my_data_dictionary,
context_instance=RequestContext(request))
A complete example using your code from above:
def view(request):
if request.method == "POST":
form = MessageHeaderForm(request.POST)
if form.is_valid():
DDEX_Party_Id = request.POST.get('DDEX_Party_Id',None)
data = serializers.serialize("xml", MessageHeaderModel2.objects.all())
with open("file.xml", "w") as out:
out.write(data)
return HttpResponse(data)
else:
# return error response?
return HttpResponseNotAllowed(['POST'])
You are not returning anything so that's why you have such an error...
You can also for example return Success value or redirect to other view..

Using Google App Engine Queues service with Django

I am trying to use Google App Engine queues API, I am having problems on testing this. It seems that in some part of the process the CSRF it's not working.
as I understand the api executes the task calling the url and making and http request in background.
The complete url is the API is calling is → http://localhost.localdomain:8000/admin/cooking/recipe/36/chefworker/
When it raises this exception:
Traceback (most recent call last):
File "/home/mariocesar/Proyectos/Cooking/cooking/django/core/handlers/base.py", line 100, in get_response
response = callback(request, *callback_args, **callback_kwargs)
File "/home/mariocesar/Proyectos/Cooking/cooking/django/views/decorators/csrf.py", line 24, in wrapped_view
resp.csrf_exempt = True
AttributeError: 'NoneType' object has no attribute 'csrf_exempt'
So, the csrf middleware, the cookie, some data or the response itself is missing from the request that the GAE api makes to execute the task in the background.
How to solve this without disabling CSRF on Django? however, it's posible with djangoappengine at all?
Down are the models.py and admin.py files I am using.
models.py
from django.db import models
class Recipe(models.Model):
name = models.CharField(max_length=140)
description = models.TextField()
cooking_time = models.PositiveIntegerField()
status = models.CharField(max_length=40)
def __unicode__(self):
return self.name
def cookthis(self):
import time
self.status = 'The chef is cooking this recipe'
self.save()
time.sleep(obj.cooking_time)
self.status = 'It\'s done ! the recipe is ready to serve'
self.save()
admin.py
import logging
from django.contrib import admin, messages
from django.http import HttpResponse
from django.utils.functional import update_wrapper
from django.contrib.admin.util import unquote
from django.shortcuts import get_object_or_404, render_to_response
from django import template
from django.core.urlresolvers import reverse
from google.appengine.api import taskqueue
from google.appengine.api.taskqueue import TaskAlreadyExistsError
from cooking.models import Recipe
from django.views.decorators.csrf import csrf_exempt
class AdminRecipe(admin.ModelAdmin):
def get_urls(self):
from django.conf.urls.defaults import patterns, url
def wrap(view):
def wrapper(*args, **kwargs):
return self.admin_site.admin_view(view)(*args, **kwargs)
return update_wrapper(wrapper, view)
info = self.model._meta.app_label, self.model._meta.module_name
urlpatterns = super(AdminRecipe, self).get_urls()
myurls = patterns('',
url(r'^(.+)/cook/$',
wrap(self.cook_view),
name='%s_%s_chefworker' % info),
url(r'^(.+)/chefworker/$',
wrap(self.chefworker_worker),
name='%s_%s_chefworker' % info),
)
return myurls + urlpatterns
def cook_view(self, request, object_id, extra_context=None):
obj = get_object_or_404(Recipe, pk=unquote(object_id))
if request.POST:
try:
taskqueue.add(
name="recipie-%s" % obj.id,
url=reverse('admin:cooking_recipe_chefworker', args=(obj.id,))
)
messages.add_message(request, messages.INFO, 'Chef is cooking the recipe.')
except TaskAlreadyExistsError:
messages.add_message(request, messages.ERROR, 'chef is already cooking that recipe.')
context_instance = template.RequestContext(request, current_app=self.admin_site.name)
return render_to_response("admin/cooking/recipe/cook_view.html", {'object': obj}, context_instance=context_instance)
#TODO: Add csrf token on form
#csrf_exempt
def chefworker_worker(self, request, object_id, extra_context=None):
import time
if request.POST:
obj = get_object_or_404(Recipe, pk=unquote(object_id))
obj.cookthis()
return HttpResponse('done')
admin.site.register(Recipe, AdminRecipe)
IMPORTANT NOTE:
Was hard to debug this error, cause the dev_appserver logger was just raising 403 errors, no other info; so, I have to patch the file google/appengine/api/taskqueue/taskqueue_stub.py line 574 and add "logging.info('response --- \n%s' % result)" to get the output.
If you have the CsrfViewMiddleware enabled, Django will require a csrf_token in all POSTs to your views.
Django provides a decorator, #csrf_exempt, that you should place on your task queue views. This turns off the middleware just for those views.
Alternatively, you can avoid using CsrfViewMiddleware altogether and instead use the #csrf_protect decorator where you need it. I don't recommend doing this -- it's probably safer to protect everywhere and carve out a small number of exemptions for your task queue views.
(One last note: both answers above -- that something is wrong with your view, or that you should just use GET for the task queue -- strike me wrong. There's nothing wrong with your view, and POST is the right verb to use for task queue tasks.)
Looking at the source of csrf.py, it looks like this would only occur if your view function is returning None (or not explicitly returning, in which case Python would return None implicitly). Looking at your code, I don't see how that could occur, though - are you sure this is your exact deployed code?
Also, you probably don't want to use get_object_or_404 inside a task queue task - if it can't find the object, it'll throw a 404, which will cause the task to error and retry indefinitely.
You also shouldn't need CSRF protection (per your TODO); instead, make sure the task queue URL is marked admin-only, and it will only ever be called by the task queue service.
I'm not an expert, but you may try using GET instead of POST. See http://groups.google.com/group/django-non-relational/browse_thread/thread/e6baed5291aed957/d6c42150c8e246e1?lnk=gst&q=queue#d6c42150c8e246e1 (the last entry)

Categories