I am trying to use REST API in django for retrieve some data in json format.
When i hit this url:
http://192.168.2.87:8000/locker/123/
It gives me output like this (from Database)
{"id": 1, "locker_id": 123, "locker_user_name": "taimur"}
But if i want to get the output by passing the parameters like this
http://192.168.2.87:8000/locker/?locker_id=123&locker_user_name=taimur&id=1
views.py
from postman, How can i do this??
from django.shortcuts import render, HttpResponse, get_object_or_404
from django.http import JsonResponse
from .models import Locker
from .serializers import LockerSerializer
from rest_framework.response import Response
from rest_framework import status
from rest_framework.views import APIView
def locker_data_response(request, locker_id):
if request.method == 'GET':
locker_information = get_object_or_404(Locker, locker_id = locker_id)
print(locker_information)
locker_information_serialize = LockerSerializer(locker_information)
print(locker_information_serialize)
return JsonResponse(locker_information_serialize.data)
urls.py
from django.urls import path, re_path
from . import views
urlpatterns = [
re_path('(?P<locker_id>[0-9]+)/$', views.locker_data_response, name='locker_data_response'),
]
You get them from the request object:
def locker_data_response(request):
if request.method == 'GET':
locker_id = request.data.get('locker_id') # this will return None if not found
locker_user_name = request.data.get('locker_user_name')
locker_information = get_object_or_404(Locker, locker_id=locker_id)
print(locker_information)
locker_information_serialize = LockerSerializer(locker_information)
print(locker_information_serialize)
return JsonResponse(locker_information_serialize.data)
And the url will change to:
locker/$
[EDIT: Sorry, if you are using drf you should use data rather than GET]
[EDIT 2: If you want to use it like this, you will also need to change the url and signature of the view]
[EDIT 3: Added the code in the correct place in view]
If your url is something like domain/search/?q=haha, Then you would use request.GET.get('q', '').
q is the parameter you want, And '' is the default value if q isn't found.
If you are instead just configuring your URLconf, Then your captures from the regex are passed to the function as arguments (or named arguments).
Such as:
(r'^user/(?P<username>\w{0,50})/$', views.profile_page,),
Then in your views.py you would have
def profile_page(request, username):
# Rest of the method
Related
I have the following Decorator which works fine when applied to different views with: #otp_required(login_url='login') on my site:
Decorator
from django.contrib.auth.decorators import user_passes_test
from django_otp import user_has_device
from django_otp.conf import settings
def otp_required(view=None, redirect_field_name='next', login_url=None, if_configured=False):
"""
Similar to :func:`~django.contrib.auth.decorators.login_required`, but
requires the user to be :term:`verified`. By default, this redirects users
to :setting:`OTP_LOGIN_URL`.
:param if_configured: If ``True``, an authenticated user with no confirmed
OTP devices will be allowed. Default is ``False``.
:type if_configured: bool
"""
if login_url is None:
login_url = settings.OTP_LOGIN_URL
def test(user):
return user.is_verified() or (if_configured and user.is_authenticated and not user_has_device(user))
decorator = user_passes_test(test, login_url=login_url, redirect_field_name=redirect_field_name)
return decorator if (view is None) else decorator(view)
However, I’d like to convert this into a Middleware as I want to avoid having to apply a decorator to every view on my site, but not managed to get working.
I tried to amend the following Middleware which I currently have in place which is just for authorised users and has been working but as per above decorator I want this Middleware extended to also have OTP required as well:
Middleware
from django.utils.deprecation import MiddlewareMixin
from django.urls import resolve, reverse
from django.http import HttpResponseRedirect
from wfi_workflow import settings
from django_otp import user_has_device
from django_otp.decorators import otp_required
from django_otp.middleware import is_verified
class LoginRequiredMiddleware(MiddlewareMixin):
"""
Middleware that requires a user to be authenticated to view any page other
than LOGIN_URL. Exemptions to this requirement can optionally be specified
in settings by setting a tuple of routes to ignore
"""
##otp_required(login_url='login')
def process_request(self, request):
assert hasattr(request, 'user'), """
The Login Required middleware needs to be after AuthenticationMiddleware.
Also make sure to include the template context_processor:
'django.contrib.account.context_processors.account'."""
if not request.user.is_verified() and not request.path.startswith('/admin/') and not request.path.startswith('/account/' ):
current_route_name = resolve(request.path_info).url_name
if not current_route_name in settings.AUTH_EXEMPT_ROUTES:
return HttpResponseRedirect(reverse(settings.LOGIN_URL))
Help is much appreciated.
The fact that you return a HttpResponseRedirect will not work: Django's MiddlewareMixin will simply call the function to (optionally) alter the request, but it will never take the return into account.
What you can do is define middleware in a decorator-like structure, and return the HttpResponseRedirect in case the user should be authenticated with:
from django.urls import resolve, reverse
from django.http import HttpResponseRedirect
from wfi_workflow import settings
def OTPRequiredMiddleware(get_response):
"""
Middleware that requires a user to be authenticated to view any page other
than LOGIN_URL. Exemptions to this requirement can optionally be specified
in settings by setting a tuple of routes to ignore
"""
def middleware(request):
from django_otp import user_has_device
if not user.is_verified() and not (if_configured and user.is_authenticated and not user_has_device(user)):
return HttpResponseRedirect(settings.OTP_LOGIN_URL)
return get_response(request)
I'm building a system where I store a Member model on a Django server, one of the attributes of Member is score which is what I want to change using API calls. My question is what would be the best way to do this? I looked into the Django REST framework but it seems a bit overkill for what I'm trying to do. I've been trying to pass the necessary information through the url using regular expressions but I'm unsure if it will work. Outline of what I need is below
iOS/Android app makes request sending pk and score to add to total
server updates appropriate model instance and returns True/False to app depending if save was successful
You can achieve this by this quite dirty solution:
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('<int:member_id>/<int:score_to_add>/', views.update_score, name='update_score'),
]
views.py
from django.http import HttpResponse
from .models import Member
def update_score(request, member_id, score_to_add):
member = Member.objects.get(pk=member_id)
member.score += score_to_add
try:
member.save
return HttpResponse("True")
except:
return HttpResponse("False")
Also you can respond with Json. Here is alternative views:
Alternative views.py
from django.http import JsonResponse
from .models import Member
def update_score(request, member_id, score_to_add):
member = Member.objects.get(pk=member_id)
member.score += score_to_add
try:
member.save
return JsonResponse({'status': True})
except:
return JsonResponse({'status': False})
But i think Django Rest Framework is a better way to do this.
You can create a view to return JsonResponse. Take example of polls app in django and convert a post view to return a JSON response.
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.http import JsonResponse
from .models import Choice, Question
# Need to disable csrf here
#csrf_exempt
def vote(request, question_id):
question = get_object_or_404(Question, pk=question_id)
# If you want Json requests Or you can use
# received_json_data=request.POST if you are using normal form data request.
received_json_data=json.loads(request.body)
try:
selected_choice = question.choice_set.get(pk=received_json_data['choice'])
except (KeyError, Choice.DoesNotExist):
# If failed
return JsonResponse({'result': False})
else:
selected_choice.votes += 1
selected_choice.save()
return JsonResponse({'result': True})
Although It works but I would still recommend using DRF because what you are doing needs proper REST API and DRF eases a lot of pain points.
I can't work out how to test that a Django class-based view receives the expected kwargs from a URL pattern.
If I have my urls.py:
from django.conf.urls import url
from myapp import views
urlpatterns = [
# ...
url(
regex=r"^people/(?P<pk>\d+)/$",
view=views.PersonDetailView.as_view(),
name='person_detail'
),
]
And my views.py:
from django.views.generic import DetailView
from myapp.models import Person
class PersonDetailView(DetailView):
model = Person
I can test that a request to the URL calls the correct view like this:
from django.test import TestCase
from django.urls import resolve
from myapp import views
from myapp.factories import PersonFactory
class UrlsTestCase(TestCase):
def test_person_detail_view(self):
PersonFactory(pk=3)
self.assertEqual(resolve('/people/3/').func.__name__,
views.PersonDetailView.__name__)
But I'd also like to test that a request to /people/3/ results in {'pk': '3'} being passed to PersonDetailView, and I can't work out where in a class-based view receives the kwargs in order to test it (by patching the receiving method, I guess).
Here's how I checked the id or pk on my views (I'm using Django1.11):
from menus.models import Item
from menus.views import ItemListView
from django.test import RequestFactory
from django.contrib.auth.models import User
person = User.objects.get(username='ryan')
factory = RequestFactory()
request = factory.get('/items/')
request.user = person
response = ItemListView.as_view()(request)
#prints the id or pk of the requesting user
response._request.user.pk
response._request.user.id
I want to check if a user is allowed to register for a specific event. I thought in order to save code I could do it like the login_required decorator right between the url() and MyClass.as_view(). But how do I get that slug? Or is this solution totally wrong? (I unfortunatelly can't use the user_passes_test because I don't want to test someting on the user but on the url.)
So I tryed this:
views.py
from registration.models import Event
from django.utils import timezone
from django.contrib.auth.decorators import login_required
from django.shortcuts import get_object_or_404
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
def reg_is_open(event_slug):
"""
Return True if registration is open.
"""
event = get_object_or_404(Event, slug=event_slug)
if event.open_date <= timezone.now() and event.cut_off >= timezone.now():
return True
def allow_view(cls, **initkwargs):
"""
Check weather registration is open and user is logged in.
Returns to registration start page if registration is closed.
"""
slug = initkwargs.get('event') # Does not work!
if not reg_is_open(slug):
return HttpResponseRedirect(reverse('registration:event_index', args=slug))
return login_required(cls.as_view(**initkwargs))
# Also works when I remove **initkwargs. That means that what I'm looking for just passes...
urls.py
from django.conf.urls import patterns, url, include
from registration import views
event_patterns = patterns('',
url(r'^person/$', views.allow_view(views.PersonList), name='person_list'),
# instead of
# url(r'^person/$', login_required(views.PersonList.as_view()), name='person_list'),
# ...
urlpatterns = patterns('',
url(r'^(?P<event>[-a-zA-Z0-9_]+)/$', views.EventDetails.as_view(), name='event_index'),
url(r'^(?P<event>[-a-zA-Z0-9_]+)/', include(event_patterns)),
# ...
If I understand correctly, your view is a DetailView of the event, correct? In that case, use something along the lines of:
class EventDetailView(DetailView):
model = Event
def dispatch(self, request, *args, **kwargs):
if self.request.user not in self.object.registered_users.all():
return HttpResponseForbidden()
else:
return super(EventDetailView, self).dispatch(request, *args, **kwargs)
This assumes that you have a M2M key between User and Event models, called registered_users on the Event side; change the code to fit your situation.
I was wondering if there is a way to pass view variables directly to dajaxice?
Actually I convert the id to a json string and load them via the dajaxice function.
I like to avoid passing the id this way and have to handle it as user manipulated input.
view.py
from django.shortcuts import render_to_response, redirect
from django.shortcuts import get_object_or_404
from django.template import RequestContext
from django.utils import simplejson
def site(request, slug, number):
collection = get_object_or_404(Collection, slug=slug)
site = get_object_or_404(Site, collection=collection, number=number)
json_id = simplejson.dumps(site.pk)
return render_to_response('base/site.html',
{
'site': site,
'json_id': json_id,
},
context_instance=RequestContext(request))
site.html
...
var id = {{ json_id|safe }};
var user_changes = "";
...
Dajaxice.base.submit_changes(callback, {'id': id, 'user_changes': user_changes});
ajax.py
from django.utils import simplejson
from dajaxice.decorators import dajaxice_register
#dajaxice_register
def submit_changes(request, id, user_changes):
...
return simplejson.dumps({'message':'You changed:%s in Site #%s!' % (user_changes, id)})
The best way is probably to store such information in the session to prevent manipulation
view.py
...
request.session['id'] = site.pk
...
ajax.py
...
id = request.session['id']
...