Django can't search "method not allowed" - python

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>

Related

Django POST returns empty - DRF + recaptcha

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?

How do I get user input from search bar to display in a page? Django

Django is very challenging and I still need to get used to the code and currently, I just want the search bar to display every time a user input a text and it will display like a title I really don't how to interpret the code to tell that every time the user inputs in the search bar, It is supposed to display the user input on a page like a title.
Example: user input in the search bar: cat and it displays cat title
Display on the current page:
Result search: "Cat"
HTML Code
<!-- Search Bar -->
<form action="{% url 'enc:search' %}" method="GET">
{% csrf_token %}
<input class="search" type="text" name="q" placeholder="Search">
</form>
In my views.py I only write this code and I don't know what to write it.
views.py
def search (request):
title = request.GET.get("q", "")
urls.py
urlpatterns = [
path("", views.index, name="index"),
path("search/", views.search, name="search"),
Right now just a simple display from the search bar input later I will code it in a data search where there is some file to integrate the search but right now I really need some help my brain is cracking. It's kinda sad I mean I know it be a simple code but I don't know why I can't figure it out.
please do help me if you have tips on how to be better on Django and python too it be much help for me and thank you for your time I really appreciate it very much.
searchpage.html :
<!-- Search Bar -->
<form action="{% url 'enc:search' %}" method="POST">
{% csrf_token %}
<input class="search" type="text" name="q" placeholder="Search">
<input type="submit" value="Submit">
</form>
views.py:
from django.shortcuts import render
def search (request):
#defines what happens when there is a POST request
if request.method == "POST":
title = request.POST.get("q")
return render(request,'new_template.html', { 'title' : title })
#defines what happens when there is a GET request
else:
return render(request,'searchpage.html')
new_template.html:
<!DOCTYPE html>
{% load static %}
<html>
<head>
<title>search term</title>
</head>
<body>
<h1> {{ title }} </h1>
</body>
</html>

Django: Pass arguments from other form to submit button

I'm building a simple Django app that lets users track stuff for specific days:
It records entries with a name and a date using the upper form.
<form action="" method="post" style="margin-bottom: 1cm;">
{% csrf_token %}
<div class="form-group">
{{ form.entry_name.label_tag }}
<div class="input-group">
<input type="text" class="form-control" id="{{ form.entry_name.id_for_label }}" name="{{ form.entry_name.html_name }}" aria-label="new entry field">
{{ form.entry_date }}
<div class="input-group-append">
<button type="submit" class="btn btn-primary">Add</button>
</div>
</div>
<small id="{{ form.entry_name.id_for_label }}Help" class="form-text text-muted">This can be anything you want to track: An activity, food, how you slept, stress level, etc.</small>
</div>
</form>
Below the form, there are quick add buttons that let users quickly add a new entry with a specific name. In addition, I'd like to use the date selected in the form above. I.e., if a user sets a date in the upper form but then clicks one of the suggested buttons, it should still use the selected date for adding the new entry.
This is what the code for the suggested buttons currently looks like:
{% if entry_counts and entry_dict|length > 0 %}
<div class="card" style="margin-bottom: 1cm;">
<div class="card-body">
<div class="card-title">Suggested entries</div>
{% for name, count in entry_counts.items %}
<form method="post" action="{% url 'app:add_entry_with_date' name form.entry_date.value %}" style="display: inline-block;">
{% csrf_token %}
<button type="submit" class="btn btn-secondary" name="{{ name }}" style="margin-bottom: 5px;">{{ name }}</button>
</form>
{% endfor %}
</div>
</div>
{% endif %}
I'm trying to access the selected date and pass it to the corresponding view: action="{% url 'app:add_entry_with_date' name form.entry_date.value %}", but it still adds the entry at the default date (today) not on the selected date.
My guess, is that the problem is with <button type="submit" class="btn btn-secondary" name="{{ name }}" style="margin-bottom: 5px;">{{ name }}</button>. Does this just pass name but not the date when submitting?
Here are the relevant URL patterns:
class DateConverter:
regex = '\d{4}-\d{2}-\d{2}'
def to_python(self, value):
return datetime.datetime.strptime(value, '%Y-%m-%d')
def to_url(self, value):
return value
register_converter(DateConverter, 'yyyymmdd')
urlpatterns = [
path('', views.index, name='index'),
path('add/<entry_name>/', views.add_entry, name='add'),
path('add/<entry_name>/<yyyymmdd:entry_date>/', views.add_entry, name='add_entry_with_date'),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
So whenever adding a new entry (with or without specific date), my add_entry view is called:
#login_required
def add_entry(request, entry_name, entry_date=datetime.date.today()):
# only works for post
# if request.method == 'POST':
entry_name = entry_name.strip().lower()
entry = Entry.objects.create(name=entry_name, date=entry_date, owner=request.user)
return HttpResponseRedirect(reverse('app:index'))
You're trying to pass the date value as part of the URL,
{% url 'app:add_entry_with_date' name form.entry_date.value %}
however, form.entry_date.value won't have a defined value unless your form is bound before it's passed to the template for rendering. As a result, probably, your add_entry view is being called via the URL pattern add, not add_entry_with_date.
Another challenge with your current code is that you want to have the same date-type input element ({{ form.entry_date }}) serve as the source for different, separate HTML forms (you have the first form for adding entries, and then you have one form for each suggested entry). Changing the value of that input when the page is already rendered in the browser won't update the action URLs for the suggested entry forms—unless you use JavaScript.
I think the quickest way to make your existing code work is to write some JavaScript to manipulate the action attribute for the suggested-entry forms whenever the date input value changes.
Manipulating action attributes looks strange though, and also I believe your view, which should work only for POST requests, should use only POST data and not rely on URL parameters. Therefore I recommend that you use hidden inputs, e.g.
<input type="hidden" name="variable-name" value="temporary-date-value-here">
and then have the JavaScript manipulate these input elements' values instead of the form action attribute. Of course you have to update the view too.
Update: sample JS for synchronizing inputs across forms
HTML:
<html>
<head>
<title>Sample synchronization of inputs across forms</title>
</head>
<body>
<h1>Sample synchronization of inputs across forms</h1>
<h2>Form 1</h2>
<form>
<input class="synchronized-inputs" type="date" name="input_date">
</form>
<h2>Form 2</h2>
<form>
<input class="synchronized-inputs" type="date" name="input_date">
</form>
<script src="sync-inputs-across-forms.js" type="text/javascript"></script>
</body>
</html>
JavaScript (sync-inputs-across-forms.js):
var syncedInputs = document.getElementsByClassName('synchronized-inputs');
Array.from(syncedInputs).forEach((source) => {
source.addEventListener('change', () => {
Array.from(syncedInputs).forEach((target) => {
target.value = source.value;
});
});
});
Note that:
Without the JS, selecting a date in one form won't update the other form's value
As indicated in the original answer, you'd want to use hidden inputs for the suggested-entry forms. To do that, just change type="date" to type="hidden" for the other form. Synchronization will still work as the value is tracked in the (invisible parts of the) DOM.

Passing variable with POST in django

Hi im trying to pass a name from a form to a view in django using POST. There are no errors in the execution but its passing nothing from the template and dont know if i doing something wrong here. Im starting with django so i can have newbie errors. If u need more information tell me pls.
Views.py
def crear_pdf(request):
empresa_selec = ""
form = EmpModelForm()
if request.method == 'POST':
form = EmpModelForm(data=request.POST)
if form.is_valid():
empresa_selec = form.cleaned_data['nombre']
#"empresa_selec" that's the empty variable
Models.py
class Empresa_modelo(models.Model):
nombre = models.CharField(max_length=100,blank=True,null=True)
Forms.py
class EmpModelForm(forms.ModelForm):
class Meta:
model = Empresa_modelo
fields = ["nombre"]
template.html
<div class="container-fluid">
<form method="POST" enctype="multipart/form-data" action="{% url 'crear_pdf' %}">{% csrf_token %}
<p>Empresa</p>
<input type="text" name="empresa">
<br>
<button type="submit">Subir</button>
</form>
<br>
<a class="btn btn-primary" href="{% url 'crear_pdf' %}">Atras</a>
</div>
You haven't got a field called nombre in your template; you only have empresa.
That's presumably because you don't ouput your EmpModelForm in the template. You don't show your render call in the view, but assuming you pass it as form, you should just do {{ form.as_p }} in the template.
Try using:
<input type="text" name="nombre">
There is no field named empresa.
Had a look at your code,there are a couple of issues.First you are not using the model form defined in your forms.py file in your template. Second you have defined an input text box with the name that you are not referring in your views. Either use the model form or use the same name of your input text box in your views.
def crear_pdf(request):
empresa_selec = ""
form = EmpModelForm()
if request.method == 'POST':
form = EmpModelForm(data=request.POST)
if form.is_valid():
empresa_selec = form.cleaned_data['nombre']
else:
return render(request,"template.html",{"form":form})
And in your template you can edit as such:
<div class="container-fluid">
<form method="POST" enctype="multipart/form-data" action="{% url 'crear_pdf' %}">{% csrf_token %}
{{ form.as_p }}
<br>
<button type="submit">Subir</button>
</form>
<br>
<a class="btn btn-primary" href="{% url 'crear_pdf' %}">Atras</a>
</div>
Hope this helps.

Django templates not altering form action

I have a URL file chat.urls.py:
`urlpatterns = patterns('',
url(r'^message/(?P<username>\w+)/$',views.message,name='message'),
url(r'^message/(?P<username>\w+)/submit/$',views.send_message,name='send_message'),
url(r'^inbox/$',views.inbox,name='inbox'),
url(r'^inbox/(?P<username>\w+)/$', views.inbox_by_user,name='inbox_by_user'),
)`
and a message.html template to send a message from with a form like this:
<form action="{% url 'inbox' %}" method="post">
{% csrf_token %}
<input type="text" name="text" id="text" value="" />
<label for="message">Enter your message here</label><br />
<input type="submit" value="Send" />
</form>
where I substituted previously working code for "url 'inbox'", and no matter what I substitute for the form action I always get html source rendered as
<form action="/chat/message/[username]/" method="post"...
no matter what. I have restarted the server, made sure I saved changes, and like it has a mind of its own, it's always /chat/message/[username]. When I changed that URL reverse to 'inbox' I should see chat/inbox based on the URLs.
According to the information in comment, you need {% url 'chat:inbox' %} not {% url 'inbox' %} in the form.

Categories