Django POST returns empty - DRF + recaptcha - python

I'm trying to make a POST request to Django and it arrives empty to the view.
views.py
from django.http import HttpResponse
from rest_framework import generics, views
class TESTViewSet(views.APIView):
def post(self, request):
st = f'test: {request.POST} - {request.data} '
s_obj = serializers.RecaptchaSerializer(
data=request.data, context={"request": request}
)
return HttpResponse(st)
The purpose is to test recaptcha with django rest framework, but I haven't even got there yet. The issue is the request always arriving at the view empty of any info. The page renders renders "test: - "
The template rendered in the page:
<div class="">
test
<form method="post" action="/api/test_recaptcha/">
{% csrf_token %}
<label for="ntest">Select:</label>
<select name="ntest" id="ntest">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<label for="stest">Text:</label><br>
<input type="text" id="stest" name="stest" value=""><br>
<script src='https://www.google.com/recaptcha/api.js'></script>
<div class="g-recaptcha" data-sitekey="{MY CAPTCHA PUBLIC KEY}"></div>
<button type="submit" class="btn btn-primary">Post</button>
</form>
</div>
It renders what is in the view, so the route is ok. I inspected the browser request, and all the fields of the post request are filled, including the g-captcha. However when it arrives at the view it's empty.
What am I missing?

Related

Django can't search "method not allowed"

im new to django and im currently doing a website for my friend. he wants me to make a system where the users can search the database and the website gives the relevent items according to their serial number.
i followed a tutorial from the following site: https://learndjango.com/tutorials/django-search-tutorial to figure out how to do db searchs which helped a lot, but im still having a problem: my search bar works, and the result page also works but it only works when i manually type the query on the searchbar myself (e.x. results/?q=number1). However when i search using the input bar and the submit button it sends me to /results/ page and the page gives this:
This page isn’t working
If the problem continues, contact the site owner.
HTTP ERROR 405
-when i open up pycharm to see the error in terminal it says:
Method Not Allowed (POST): /result/
Method Not Allowed: /result/
[27/Oct/2020 20:06:02] "POST /result/ HTTP/1.1" 405 0
here are my codes(python3.7,pycharm) websites/urls:
from . import views
from django.urls import path
from django.contrib.auth import views as auth_views
urlpatterns = [
path('register/',views.UserFormView.as_view(), name='register'),
path('login/', auth_views.LoginView.as_view(), name='login'),
path('', views.IndexViews.as_view(), name='index'),
path('scan/', views.ScanView.as_view(), name='scan'),
path('result/', views.SearchResultsView.as_view(), name='result'),
]
websites/views:
class IndexViews(generic.ListView):
template_name = "websites/index.html"
context_object_name = "object_list"
def get_queryset(self):
return Website.objects.all()
class ScanView(TemplateView):
form_class = SerialFrom
template_name = 'websites/scan.html'
class SearchResultsView(ListView):
model = SerialNumber
template_name = 'websites/result.html'
def get_queryset(self): # new
query = self.request.GET.get('q')
context = self.get_context_data(object=self.object)
object_list = SerialNumber.objects.filter(
Q(number__iexact=query)
)
return object_list
scan.html:
{% extends 'websites/base.html' %}
{% block albums_active %}active{% endblock %}
{% block body %}
<head>
<meta charset="UTF-8">
<title>Scan</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<form class="box" action="{% url 'result' %}" method="POST">
<h1>Product Check</h1>
<p> Please enter the serial id of your product to check it.</p>
{% csrf_token %}
<input type="text" name="q" placeholder="Serial Number">
<input type="submit" name="q" placeholder="Check">
</form>
</body>
{% endblock %}
thank you for taking your time and reading, please help me i really need to do this.
A ListView [Django-doc] by default does not implement a handler for a POST request. Searching is normally done through a GET request, so you should use:
<form class="box" action="{% url 'result' %}" method="GET">
<h1>Product Check</h1>
<p> Please enter the serial id of your product to check it.</p>
<input type="text" name="q" placeholder="Serial Number">
<input type="submit" placeholder="Check">
</form>
Furthermore the <input type="submit"> should not have a name="q" attribute.
As #Melvyn says, you can also alter the type to type="search" [mozilla] for the text box:
<form class="box" action="{% url 'result' %}" method="GET">
<h1>Product Check</h1>
<p> Please enter the serial id of your product to check it.</p>
<input type="search" name="q" placeholder="Serial Number">
<input type="submit" placeholder="Check">
</form>

The view users.views.RegisterView didn't return an HttpResponse object. It returned None instead

I am using this code for a register form. But the post request doesn't work and give me an error :
ValueError at /register/
The view users.views.RegisterView didn't return an HttpResponse object. It returned None instead.
views.py
class RegisterView(View):
def get(self,request):
register_form = RegisterForm()
return render(request, 'register.html',{'register_form':register_form})
def post(self,request):
register_form = RegisterForm(request.POST)
if register_form.is_valid():
user_name = request.POST.get("email", "") user_psw = request.POST.get("password", "")
user_profile=UserProfile()
user_profile.username = user_name
user_profile.email = user_name
user_profile.password=make_password(user_psw)
user_profile.save()
send_register_email(user_name,"register")
pass
urls.py
from django.contrib import admin
from django.urls import path, include
from django.views.generic import TemplateView
import xadmin
from users.views import LoginView , RegisterView
import xadmin
urlpatterns = [
path('xadmin/', xadmin.site.urls),
path('',TemplateView.as_view(template_name="index.html"),name="index"),
path('login/',LoginView.as_view(),name="login"),
path('register/',RegisterView.as_view(),name="register"),
path("captcha/", include('captcha.urls'))
]
forms.py
class RegisterForm(forms.Form):
email = forms.EmailField(required=True)
password = forms.CharField(required=True, min_length=5)
captcha = CaptchaField(error_messages={"invalid":"please input correctly"})
register.html
<div class="tab-form">
<form id="email_register_form" method="post" action="{% url 'register' %}" autocomplete="off">
<input type='hidden' name='csrfmiddlewaretoken' value='gTZljXgnpvxn0fKZ1XkWrM1PrCGSjiCZ' />
<div class="form-group marb20 ">
<label>邮 箱</label>
<input type="text" id="id_email" name="email" value="None" placeholder="请输入您的邮箱地址" />
</div>
<div class="form-group marb8 ">
<label>密 码</label>
<input type="password" id="id_password" name="password" value="None" placeholder="请输入6-20位非中文字符密码" />
</div>
<div class="form-group marb8 captcha1 ">
<label>验 证 码</label>
{{ register_form.captcha }}
<img src="/captcha/image/2f3f82e5f7a054bf5caa93b9b0bb6cc308fb7011/" alt="captcha" class="captcha" /> <input id="id_captcha_0" name="captcha_0" type="hidden" value="2f3f82e5f7a054bf5caa93b9b0bb6cc308fb7011" /> <input autocomplete="off" id="id_captcha_1" name="captcha_1" type="text" />
</div>
<div class="error btns" id="jsEmailTips"></div>
<div class="auto-box marb8">
</div>
<input class="btn btn-green" id="jsEmailRegBtn" type="submit" value="注册并登录" />
<input type='hidden' name='csrfmiddlewaretoken' value='5I2SlleZJOMUX9QbwYLUIAOshdrdpRcy' />
{% csrf_token %}
</form>
</div>
request information
Request information
USER
AnonymousUser
GET
No GET data
POST
Variable Value
csrfmiddlewaretoken
'9dQylxY3htVbBMNFunnYwgnarkfjSVioz5rhu0uADk0ShssTFGl9144OEwJoUlPX'
email
'1#1.com'
password
'123456'
captcha_0
'2f3f82e5f7a054bf5caa93b9b0bb6cc308fb7011'
captcha_1
''
FILES
No FILES data
no matter whether the verification code I input is wrong or right, the error is always The view users.views.RegisterView didn't return an HttpResponse object. It returned None instead.
Django's view should return some response.
From doc:
A view function, or view for short, is simply a Python function that takes a Web request and returns a Web response. This response can be the HTML contents of a Web page, or a redirect, or a 404 error, or an XML document, or an image . . . or anything, really.
So you need to add return statement to post() method, e.g. like this:
def post(self,request):
...
return render(request, 'register.html',{'register_form':register_form})

Display selected form items in another page with Flask

I'm using Flask 0.12 with Python 3.6 to create a simple app that will display selected items in another page when the submit button is clicked.
The main Flask app is in app.py as:
from flask import Flask, render_template
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/result', methods=['POST'])
def result():
return render_template('result.html')
This renders the following webpage using Bootstrap:
<h1>Example Page</h1>
<p>Choose the options in the form below then submit your selections.</p>
<form action="">
<div class="form-group">
<label for="vehicle">Vehicle</label>
<select id="vehicle" class="form-control">
<option>truck</option>
<option>car</option>
<option>van</option>
</select>
</div>
<div class="form-group">
<label for="year">Year</label>
<select id="year" class="form-control">
<option>1972</option>
<option>1999</option>
<option>2010</option>
</select>
</div>
</form>
<br>
<button type="submit" class="btn btn-default">Submit</button>
How can I get Flask to show the selected items in my results.html template when the submit button is clicked?
You have to make few changes in the form to display in result page.
You have to add action url and method in form
<form action="/result" method="post">
Add name in the select field
<select id="vehicle" class="form-control" name="vehicle">
<select id="year" class="form-control" name="year">
Use flask request to get the form values
from flask import request
# inside your POST view
vehicle = request.form.get('vehicle')
year = request.form.get('year')
return render_template('result.html', vehicle=vehicle, year=year)
Finally in your result html page add these...
{{ vehicle }} {{ year }}

django modelformset_factory doesn't include actual forms

I've been trying to follow tutorials and other SO questions and have a modelformset_factory that's displaying a list of what looks like forms in the html, but it turns out they're not actual forms.
html that gets displayed:
<div ='container'>
<div class='row'><tr><th><label for="id_form-0-config_key">Config key:</label></th><td><input id="id_form-0-config_key" maxlength="63" name="form-0-config_key" type="text" value="ClientMustVerify" /></td></tr>
<tr><th><label for="id_form-0-config_value">Config value:</label></th><td><input id="id_form-0-config_value" maxlength="63" name="form-0-config_value" type="text" value="TRUE" /><input id="id_form-0-id" name="form-0-id" type="hidden" value="3" /></td></tr> <input type="submit" value="Update" /></div>
<div class='row'><tr><th><label for="id_form-1-config_key">Config key:</label></th><td><input id="id_form-1-config_key" maxlength="63" name="form-1-config_key" type="text" value="Auditing" /></td></tr>
<tr><th><label for="id_form-1-config_value">Config value:</label></th><td><input id="id_form-1-config_value" maxlength="63" name="form-1-config_value" type="text" value="FALSE" /><input id="id_form-1-id" name="form-1-id" type="hidden" value="4" /></td></tr> <input type="submit" value="Update" /></div>
<div>
notice there is no form tag anywhere. working backwards, here's the excerpt from the template:
<div ='container'>
{% for form in formset %}
<div class='row'>{{form}} <input type="submit" value="Update" /></div>
{% endfor %}
<div>
yes, I added the submit button manually hoping to get these to work, but of course if there isn't a form tag, then the submit button won't do anything.
views.py:
from limbo.models import serverConfig
from django.forms import modelformset_factory
from django.forms import formset_factory
def editServer(request):
result = serverConfig.objects.values()
myConfigs = [entry for entry in result]
finalFormSet = modelformset_factory(serverConfig, exclude=('id',), extra=0)
#other lines
return render(request, 'limboHtml/ServerConfiguration.html', {'formset': finalFormSet, 'SubmitMessage': '', 'CurrentConfigs': myConfigs})
forms.py:
class serverForm(ModelForm):
class Meta:
model = serverConfig
fields = ['config_key', 'config_value']
def __init__(self, *args, **kwargs):
super(serverForm, self).__init__(*args, **kwargs)
instance = getattr(self, 'instance', None)
if instance and instance.pk:
self.fields['config_key'].widget.attrs['readonly'] = True
self.fields['config_key'].widget.attrs['disabled'] = True
and models.py:
class serverConfig(models.Model):
config_key = models.CharField(max_length=63)
config_value = models.CharField(max_length=63)
I tried using finalFormSet = formset_factory(serverForm, extra=0) at one point, but then I just got no content in the html...
As described in the formset documention you must add the form tag manually. This is not very different from what you do when displaying a single form.
It appears that you are iterating through the formset and displayig them one by one. That means you must also add the management form
<form method="post" action="">
{{ formset.management_form }}
<div ='container'>
{% for form in formset %}
<div class='row'>{{form}} <input type="submit" value="Update" /></div>
{% endfor %}
<div>
</form>
Or you will get errors about a missing or misconfigured management form.
Note that it does not include the tags, or a submit button. We’ll have to provide those ourselves in the template.
Read more: Working with Forms: Building a form in Django
The reason you are not getting the <form> tag is because from a logical point of view a form validation can be handled anywhere in your application. That's why you need to specify the form tag explicitly with the target url (good to use reverse(view_name)), method and other parameters.

CSRF error in Django; How can I add CSRF to my login view?

I have a simple form I want users to be able to log into; here is the template code with the CSRF tag in it:
<html>
<head><title>My Site</title></head>
<body>
<form action="" method="post">{% csrf_token %}
<label for="username">User name:</label>
<input type="text" name="username" value="" id="username">
<label for="password">Password:</label>
<input type="password" name="password" value="" id="password">
<input type="submit" value="login" />
<input type="hidden" name="next" value="{{ next|escape }}" />
</form>
</body>
</html>
Now here is my views.py page. The question is where do I put in the CSRF supporting part (right now I get a CFRS token error) in my view and how do i do it?
from django.contrib import auth
def login_view(request):
username = request.POST.get('username', '')
password = request.POST.get('password', '')
user = auth.authenticate(username=username, password=password)
if user is not None and user.is_active:
# Correct password, and the user is marked "active"
auth.login(request, user)
# Redirect to a success page
return HttpResponseRedirect("/account/loggedin/")
else:
# Show an error page
return HttpResponseRedirect("account/invalid/")
def logout_view(request):
You have to add the RequestContext to the view that renders the page with the {% csrf_token %} line in it. Here is the example from the tutorial:
# The {% csrf_token %} tag requires information from the request object, which is
# not normally accessible from within the template context. To fix this,
# a small adjustment needs to be made to the detail view, so that it looks
# like the following:
#
from django.template import RequestContext
# ...
def detail(request, poll_id):
p = get_object_or_404(Poll, pk=poll_id)
return render_to_response('polls/detail.html', {'poll': p},
context_instance=RequestContext(request))
The context_instance=RequestContext(request) part is the important part. This makes the RequestContext available to the form template when it is rendered.

Categories