How do I make BrowsableAPI work with functional views? For example, let's say I have
from django.http import HttpResponse, JsonResponse
from rest_framework import generics
from django.views.decorators.csrf import csrf_exempt
from rest_framework.parsers import JSONParser
from rest_framework.decorators import api_view
from .models import Snippet, SnippetSerializer
#api_view(['GET', 'POST'])
#csrf_exempt
def snippet_list(request):
"""
List all code snippets, or create a new snippet.
"""
if request.method == 'GET':
snippets = Snippet.objects.all()
serializer = SnippetSerializer(snippets, many=True)
return JsonResponse(serializer.data, safe=False)
elif request.method == 'POST':
data = JSONParser().parse(request)
serializer = SnippetSerializer(data=data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data, status=201)
return JsonResponse(serializer.errors, status=400)
When I register in the url and acces it, the browser gives me the raw json, not the browsableapi version of it. How can I make it work? I looked up the documentation and posts but couldnt find anything, everyone is either using classes based or generics. I know this way of making views is not ideal, but I still want to know how to make a functional view "Browsable".
#snippets/urls.py
from django.urls import path
from .views import snippet_list
urlpatterns = [
path('', snippet_list, name='snippets')
]
#project/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('snippets.urls'))
]
Was going through your code and found
return JsonResponse(serializer.data, safe=False)
in your Get method and I think this is the issue, maybe.
try with -
from rest_framework.response import Response
return Response(serializer.data)
Related
I have a project that has React as it's frontend & Django as it's backend. after i integrated React with django it works perfectly but the paths i created in React with react-router-dom doesn't load when i search the page on my browser. meaning, i can load http://127.0.0.1:8000 comfortably but if i try to search http://127.0.0.1:8000/rooms/1/UCL a path that i created with React-router-dom using it's Link, it throws an error calling Page not found
how can i fix this ?
#my URL.py
from re import template
from xml.etree.ElementInclude import include
from django.contrib import admin
from django.urls import path,include
from django.views.generic import TemplateView
urlpatterns = [
path('admin/', admin.site.urls),
path('api/',include('api.urls')),
path('',TemplateView.as_view(template_name='index.html')),
]
my views.py
import profile
from rest_framework.response import Response
from django.http import HttpResponse
from rest_framework.decorators import api_view
from app.models import *
from .serializers import *
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework_simplejwt.views import TokenObtainPairView
#api_view(['GET','PUT'])
def updateRoomData(request,pk):
try:
message = Message.objects.get(id=pk)
except message.DoesNotExist:
return HttpResponse(status=404)
if request.method=='GET':
serializer = messageSerializer(message)
if request.method == 'PUT':
serializer = messageSerializer(message, data=request.data)
if serializer.is_valid():
serializer.save()
else:
return Response(serializer.errors, status=400)
return Response(serializer.data)
What is the best practice for migration from request to django.views.generic?
How implement django.views.generic for logoutPage/loginPage if earlier used request?
#This my model.py
from django.db import models
from django.contrib.auth.models import User
#This my view.py
from django.shortcuts import render,redirect
from django.http import HttpResponse
from .models import *
from django.contrib.auth import login,logout,authenticate
from .forms import *
from django.views.generic import ListView
def logoutPage(request):
logout(request)
return redirect('/')
def loginPage(request):
if request.user.is_authenticated:
return redirect('home')
else:
if request.method=="POST":
username=request.POST.get('username')
password=request.POST.get('password')
user=authenticate(request,username=username,password=password)
if user is not None:
print("working")
login(request,user)
return redirect('/')
context={}
return render(request,'book/templates/login.html',context)
You can try the simplest way or a slightly more complicated but giving more possibilities in the future.
If you don't need any modifications (and usually one doesn't at early stage), you can do it directly in your main urls.py file:
from django.contrib.auth import views as auth_views
urlpatterns = [
...
path('login/', auth_views.LoginView.as_view(template_name='book/templates/login.html'), name='login'),
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
]
Alternatively you can create your own classes, that inherit from that views. Obviously, you can set proper path() for each in urls.py.
from django.contrib.auth import views as auth_views
class LoginPage(auth_views.LoginView):
template_name='book/templates/login.html'
...
class LoginPage(auth_views.LogoutView):
...
For both you can set redirect page with variables set in settings.py with wanted path name (it means the name="welcome" part):
LOGIN_REDIRECT_URL = "user_profile"
LOGOUT_REDIRECT_URL = "come_back_please"
I am working of django rest framework api_root. It cannot find view even though I name it.
# board/urls.py
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from .views import BoardList, BoardDetail, api_root
app_name = 'board'
urlpatterns = [
path('boards/', BoardList.as_view(), name='board-list'), # board-list
path('boards/<int:pk>', BoardDetail.as_view(), name='board-detail'),
path('', api_root),
]
urlpatterns = format_suffix_patterns(urlpatterns)
# board/views.py
from django.contrib.auth.models import User
from django.shortcuts import render
from rest_framework import generics, permissions, serializers
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.reverse import reverse
from .models import Board
from .serializers import BoardSerializer
from .permissions import IsAuthorOrReadOnly
#api_view(['GET'])
def api_root(request, format=None):
return Response({
'boards': reverse('board-list', request=request, format=format) # board-list
})
class BoardList(generics.ListCreateAPIView):
queryset = Board.objects.all()
serializer_class = BoardSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
def perform_create(self, serializer):
serializer.save(author=self.request.user)
It throws error,
Reverse for 'board-list' not found. 'board-list' is not a valid view function or pattern name.
Why it cannot find view name?
Since you included an app_name in your urls.py, you need to specify the view name with the app name, so:
#api_view(['GET'])
def api_root(request, format=None):
return Response({
'boards': reverse('board:board-list', request=request, format=format) # board-list
})
I am getting some issues with my urls. I don't have any 'account/' route but i when I want to visit 'login/' and after logging in it should redirect me to my profile... but it is taking me to this route: "http://127.0.0.1:8000/accounts/login/?next=/profile/"
I am sorry if I've posted any unnecessary kinds of stuff:
mainapp.urls
from django.contrib import admin
from django.contrib.auth import views as auth_views
from django.urls import path, include
from forms.views import RegisterView,LoginView
from django.conf import settings
from django.conf.urls.static import static
from user_profile import views as profile_views
from blog import views
urlpatterns = [
path('admin/', admin.site.urls),
path('register/',RegisterView.as_view(), name='register'),
path('login/', LoginView.as_view(), name = 'login'),
path('profile/',profile_views.profile,name='profile'),
path('updateprofile/',profile_views.updateprofile,name='update_profile'),
path('',include('blog.urls')),
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL,
document_root=settings.MEDIA_ROOT)
forms.views(Login/Logout)View
from django.shortcuts import render, redirect,reverse
from django.http import HttpResponse
from django.contrib.auth import authenticate, get_user_model, logout
from django.utils.http import is_safe_url
from django.contrib.auth.decorators import login_required
from django.views.generic import CreateView, FormView
from .models import User
from .forms import RegisterForm,LoginForm
class LoginView(FormView):
form_class = LoginForm #instance
template_name = 'forms/login.html'
success_url = '/profile/'
def User_logout(request):
if request.method == "POST":
logout(request)
return redirect(reverse('login'))
LoginForm:
class LoginForm(forms.Form):
email = forms.EmailField(label='email')
password = forms.CharField(widget=forms.PasswordInput)
def form_valid(self,form):
request=self.request
next_=request.GET.get('next')
next_post=request.POST.get('next')
redirect_path=next_ or next_post or None
email=form.cleaned_data.get('email')
password=form.cleaned_data.get('password')
user=authenticate(username=email, password=password)
if user is not None:
login(request, user)
try:
del request.session['UserProfile.html']
except:
pass
if is_safe_url(redirect_path, request.get_host()):
return redirect(redirect_path)
else:
return redirect("login")
return super(LoginView, self).form_invalid(form)
set a variable in your urls.py of you mainapp as following
appname='mainapp'
now in your login view add following
def get_success_url(self):
return reverse('mainapp:profile')
Currently, in Django 3.2, the reverse method is written this way:
def get_success_url(self):
return reverse('profile')
No need to add appname var in your urls.py
I am trying to define a class in views.py which is inheriting generic view. The code is as follows. On running server I get the error that
class UserFormView(View):
NameError: name 'View' is not defined
although I have imported generic. Please let me know the reason.
from django.views import generic
from django.utils import timezone
from django.shortcuts import render, get_object_or_404,render_to_response,redirect
from django.http import HttpResponseRedirect
from django.contrib import auth
from django.contrib.auth import authenticate,login
from django.core.context_processors import csrf
from .forms import UserForm
# Create your views here.
def home(request):
return render(request, 'fosssite/home.html')
def login(request):
c={}
c.update(csrf(request))
return render_to_response('fosssite/login.html',c)
class UserFormView(View):
form_class=UserForm
template_name='fosssite/signup.html'
def get(self,request):
form=self.form_class(None)
return render(request,self.template_name,{'form':form})
#validate by forms of django
def post(self,request):
form=self.form_class(request.POST)
if form.is_valid():
# not saving to database only creating object
user=form.save(commit=False)
#normalized data
username=form.cleaned_data['username']
password=form.cleaned_data['password']
#not as plain data
user.set_password(password)
user.save() #saved to database
def auth_view(request):
username=request.POST.get('username', '')
password=request.POST.get('password', '')
user=auth.authenticate(username=username,password=password)
if user is not None:
auth.login(request,user)
return HttpResponseRedirect('/loggedin')#url in brackets
else:
return HttpResponseRedirect('/invalid')
def loggedin(request):
return render_to_response('fosssite/loggedin.html',{'fullname':request.user.username})
def logout(request):
auth.logout(request)
return render_to_response('fosssite/logout.html')
def invalid_login(request):
return render_to_response('fosssite/invalid_login.html')
`
You need to either import View explicitly:
from django.views.generic import View
or refer to it as generic.View:
class UserFormView(generic.View):
# ...
The View name needs to be imported. Add the following import statement:
from django.views.generic import View
Or use the already imported generic module in
class UserFormView(generic.View)
# ^
in urls.py
from my_app import views
eg code:
urls.py
from django.conf.urls import url
from django.contrib import admin
from pro1 import views
urlpatterns = [
url(r'^$', views.home, name='home'),
url(r'^admin/', admin.site.urls),
]
views.py
from django.shortcuts import render
def home(request):
template="home.html"
context={}
return render(request,template,context)
guess it will solve the problem.