Django - Render view based on search query from search view - python

I have what is probably a very basic question. I have read through Django forms docs but am still missing something here. I want to have a search bar in one template (search.html) and return the search query in another template (results.html). I have the following so far, using this SO answer as a guide, which returns the following error. Thanks for any help.
Exception Value:
results() missing 1 required positional argument: 'search_id'
urls.py
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^landing/', views.search, name='search'),
url(r'^results/', views.results, name='results'),
]
forms.py
from .models import Apartment
class Apt(forms.ModelForm):
class Meta:
model = Apartment
fields = ('name')
views.py
def search(request):
if request.method == 'POST': #the form has been submitted
form = Apt(request.POST) #bound form
if form.is_valid(): #validations have passed
name = form.cleaned_data['name']
u = Apt.objects.create(name=name)
#REST query will go here.
#commit to database
u.save()
return redirect('results', search_id=u.name)
else: #create an unbound instance of the form
form = Apt(initial={'name':'name'})
#render the form according to the template, context = form
return render(request, 'search/landing.html', {'form':form})
def results(request, search_id):
search_id = request.POST.get('name')
query = get_object_or_404(Apt, pk=search_id)
return render(request, 'search/results.html', {'query':query} )
landing.html
{% extends "base_simple.html" %}
{% block title %}Look up your name{% endblock %}
{% block main_content %}
<!-- Intro Header -->
<header class="intro">
<div class="intro-body">
<div class="container">
<div class="inner cover">
<h1 class="cover-heading">find your name</h1>
<form id="searchform" method="POST" action="" accept-charset="utf-8">
{% csrf_token %}
<input id="apt" type="text" class="form-control" placeholder="Apartment Name" value="{{ Apt.name }}">
<input type="submit" value="Search" class="btn btn-lg btn-default">
</form>
</div>
</div>
</div>
</header>
{% endblock %}
results.html
{% extends "base_simple.html" %}
{% block title %}search results{% endblock %}
{% block main_content %}
<div class='col-sm-6 col-sm-offset-3'>
<div class="row">
<div class="col-sm-12">
{% for q in query %}
<div class="jumbotron">
<h3>{{ q.name }}</h3>
</div>
{% endfor %}
</div>
</div>
<hr/>
</div>
{% endblock %}

in urls you need to change result to
url(r'^results/(?P<search_id>.+)/', views.results, name='results'),
Named groups in the regex are passed as arguments to the view
You should also remove the line search_id = request.POST.get('name') from your results view as the redirect will not contain any POST data

Related

in Django : Why nothing happens when I try to Create new note with the html form in the notes.html page

I've just started my first app with Django by following a video on YouTube.
The app is a students dashboard with 8 tools and features to help the student to make note, search for help, save books, etc.
When I follow the steps I get stuck in the creation of a new note but note from the admin side but from the actual notes template that has a crispy form and a create button.
The program is supposed for writing a title and description (the content of the note) and then press the create button. When I try to click, nothing is happening.
#This is the view.py page in the dashboard app :
from django.shortcuts import render
from . forms import *
from django.contrib import messages
# Create your views here.
def home(request):
return render(request, 'dashboard/home.html')
def notes(request):
if request.method == "POST":
form = NotesForm(request.POST)
if form.is_valid():
notes = Notes(user=request.user,title=request.POST['title'],description=request.POST['description'])
notes.save()
messages.success(request,f"Notes Added from {request.user.username} Successfully")
else:
form = NotesForm()
notes = Notes.objects.filter(user=request.user)
context = {'notes':notes,'form':form}
return render(request,'dashboard/notes.html',context)
and this is the notes.html page in the dashboard app > template folder > dashboard folder :
{% extends 'dashboard/base.html' %}
<!-- Load the static files here -->
{% load static %} {% load crispy_forms_tags %}
<!-- loading the crispy files must be here so now i write anything to
create some space and lines here we go baby lets add more -->
{% block content %}
<div class="container">
<div class="row">
{% for note in notes %}
<div class="col-md-3">
<a href="#">
<div class="card">
<div class="card-header">{{note.title}}</div>
<div class="card-body">{{note.description|slice:"0:100"}}</div>
<div class="card-footer mt-auto">
<i class="fa fa-trash fa-2x"></i>
</div>
</div>
</a>
</div>
{% endfor %}
<br /><br />
</div>
</div>
<br /><br />
<div class="container">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Create Notes</legend>
</fieldset>
{% crispy form %}
<div class="form-group">
<button href="" class="btn btn-outline-info" type="submit">Create</button>
</div>
</form>
</div>
{% endblock content %}
so, this the models.py file too
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Notes(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
description = models.TextField()
def __str__(self):
return self.title
class Meta:
verbose_name = "notes"
verbose_name_plural = "notes"
in case the problem is not here, please take a look on the inside this forms.py
from dataclasses import fields
from django import forms
from . models import *
class NotesForm(forms.ModelForm):
class Meta:
model = Notes
fields = ['title', 'description']
and .. urls.py
from django.urls import path
from . import views
urlpatterns = [
path('',views.home, name='home'),
path('notes',views.notes, name="notes")
]
There are many minor mistakes in the code:
It is {{form|crispy}} to display the form not {% crispy form %}.
You are also not using HttpResponseRedirect[django-doc] for redirecting, after saving form from POST data, you should always return an HttpResponse, its a good practice.
Try below code:
Notes.html
{% block content %}
{% load crispy_forms_tags %}
<div class="container">
<div class="row">
{% for note in notes %}
<div class="col-md-3">
<a href="#">
<div class="card">
<div class="card-header">{{note.title}}</div>
<div class="card-body">{{note.description|slice:"0:100"}}</div>
<div class="card-footer mt-auto">
<i class="fa fa-trash fa-2x"></i>
</div>
</div>
</a>
</div>
{% endfor %}
<br /><br />
</div>
</div>
<br /><br />
<div class="container">
<form method="POST" action="{% url 'notes' %}" novalidate>
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Create Notes</legend>
</fieldset>
{{form|crispy}}
<input type="submit" value="Create">
</form>
</div>
{% endblock content %}
views.py
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.shortcuts import render
from . forms import *
from django.contrib import messages
from django.urls import reverse
def home(request):
return render(request, 'dashboard/home.html')
def notes(request):
if request.method == "POST":
form = NotesForm(request.POST)
if form.is_valid():
title = form.cleaned_data['title']
descrip = form.cleaned_data['description']
notes = Notes(
user=request.user, title=title, description=descrip)
notes.save()
messages.success(
request, f"Notes Added from {request.user.username} Successfully")
return HttpResponseRedirect(reverse('thanks'))
else:
form = NotesForm()
notes = Notes.objects.filter(user=request.user)
context = {'notes': notes, 'form': form}
return render(request, 'dashboard/notes.html', context)
def thanks(request):
return render(request, 'dashboard/thanks.html')
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.home, name='home'),
path('notes/', views.notes, name="notes"),
path('thanks/', views.thanks, name='thanks')
]
thanks.html
<body>
<h2>The form successfully submitted</h2>
</body>
Your forms.py can be remain same as it is.

Django request.POST returns an empty dict

code skips the whole if block directly goes to the last else. I am using django.forms to get input from the user. the same thing happens when the method is set to GET. I tried the same with normal HTML forms the same result. But the weird fact it earlier It was working properly in the initial stages of the project while I was experimenting with my views and models this start causing the error in my project as I cannot get the user input.
views.py
def form(request):
form = InputForm()
return render(request, 'classifier/form.html', {'form':form})
def output(request):
print(request.POST) # returns empty dict
if request.method == "POST":
form = InputForm(request.POST)
if form.is_valid():
url = form.cleaned_data['input_url']
print(url)
return render(request, 'classifier/output.html', {'url':url})
else:
print(form.errors())
else:
print("error")
error = "Oops"
return render(request, 'classifier/output.html',{'url':error})
form.html
<form action="{% url 'classifier:output' %}" method="POST">
{% csrf_token %}
{% for non_field_error in form.non_field_error %}
<p class="help is-danger">{{ non_field_error}}</p>
{% endfor %}
{{ form }}
{% for error in form.erros %}
<p class="help is-danger">{{ error }}</p>
{% endfor %}
<div class="text-center">
<button type="button" class="btn btn-primary" id="btn" value='Save'>Submit</button>
</div>
</form>
urls.py
from django.urls import path
from . import views
app_name = 'classifier'
urlpatterns = [
path('', views.index, name='index'),
path('form/',views.form, name='form'),
path('output/',views.output, name='output'),
]
In your template:
<div class="text-center">
<button type="button" class="btn btn-primary" id="btn" value='Save'>Submit</button>
</div>
Submit button in reality is link: Submit
so there is a simple link following.
The corrected part of the code looks like this:
<div class="text-center">
<button type="submit" class="btn btn-primary" id="btn">Submit</button>
</div>

Filter templates by ChoiceField - Django

consider this model on Django:
class My_model(models.Model):
my_choices = { '1:first' 2:second'}
myfield1=CharField()
myfield2=CharField(choices=my_choices)
Then on my form:
class My_form(forms.ModelForm):
class Meta:
model = My_model
fields = ['myfield1', 'myfield2']
My views:
def get_name(request):
if request.method == 'POST':
form = My_form(request.POST)
if form.is_valid():
return HttpResponseRedirect('/')
else:
form = My_form()
return render(request, 'form/myform.html', {'form': form})
On my template:
{% extends "base.html" %}
{% block content %}
<form action="/tlevels/" method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit">
</form>
{% endblock %}
On my base.html, I will load this template like this:
{% extends "base.html" %}
{% block content %}
{% load crispy_forms_tags %}
<div class="p-3 mb-2 bg-info text-white" style="margin-left:20px; margin-bottom:20px;">Status</div>
<div class="form-row" style="margin-left:20px; margin-bottom:20px; margin-top:20px;">
<div class="form-group col-md-6 mb-0">
{{ form.myfield1|as_crispy_field }}
</div>
<div class="form-group col-md-6 mb-0">
{{ form.myfield2|as_crispy_field }}
</div>
</div>
<input type="submit" class="btn btn-primary" value="Submit" style="margin-left:20px;">
</form>
{% endblock %}
What I want, is to have 2 other different templates, with whatever difference on them, and load them depending on the choice made on the ChoiceField, I guess that one way could be on the view, by adding some kind of conditional, and load a different template (html file).
Any ideas?
It is possible to use {% include %} with a variable.
def some_view_after_post(request):
# ... lookup value of myfield2 ...
return render(request, "path/to/after_post.html", {'myfield2: myfield2})
The in the after_post.html template:
<!-- include a template based on user's choice -->
<div class="user-choice">
{% include myfield2 %}
</div>
You'll want to make sure there is no possible way the user can inject an erroneous choice. For example, make sure the value of myfield2 choice is valid before adding it to the context.

Getting user input using django forms.py return nothing

I'm trying to get the users input and add to a table in the database, everything goes smoothly with no errors .. but the input is not added to DB
urls.py
path('category/add/', views.add_cat, name="add_cat"),
view.py
def add_cat(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = CatForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
entry = Categories.objects.create(category_name=new_cat_name)
entry.save()
# ...
# redirect to a new URL:
return HttpResponseRedirect('/')
# if a GET (or any other method) we'll create a blank form
else:
form = CatForm()
return render(request, 'add_cat.html', {'form': form})
add_cat.html
{% extends 'base.html' %}
{% block content %}
{% load static %}
<form action="/" method="post">
{% csrf_token %}
{% for form in form %}
<h3 align="center">{{ form.label }}</h3>
<div align="center">{{ form }}</div>
<br>
<br>
{% endfor %}
<div align="center">
<input type="submit" class="btn btn-dark" style="width: 100px;"value="إضافة" />
</div>
</form>
{% endblock %}
{% extends 'base.html' %}
{% block content %}
{% load static %}
<form action="" method="post">
{% csrf_token %}
{% for form in form %}
<h3 align="center">{{ form.label }}</h3>
<div align="center">{{ form }}</div>
<br>
<br>
{% endfor %}
<div align="center">
<input type="submit" class="btn btn-dark" style="width: 100px;"value="إضافة" />
</div>
</form>
{% endblock %}
change your form action, you were posting the data to '/' url but you need to put it in your add view
if form.is_valid():
form.save()
return HttpResponseRedirect('/')

In Django, form isn't rendered on browser

I have started learning django, but I can't understand how to render form.
This is form.py I have made.
from django import forms
class TweetForm(forms.Form):
text = forms.CharField(widget = forms.Textarea(attrs = {'rows' : 1, 'cols' : 85}), max_length = 160)
country = forms.CharField(widget = forms.HiddenInput())
This is code snippet in views.py.
from .forms import TweetForm
class Profile(View):
def get(self, request, username):
params = dict()
user = User.objects.get(username = username)
tweets = Tweet.objects.filter(user = user)
params["user"] = user
params["tweets"] = tweets
form = TweetForm
return render(request, 'profile.html', {'params' : params, 'form' : form})
This is html file and it must render form I have made.
{% extends "base.html" %}
{% block content %}
<div class="row clearfix">
<div class="col-md-12 column">
<form method="post" action="post/">
{% csrf_token %}
<div class="col-md-8 col-md-offset-2 fieldWrapper">
{{ form.text.errors }}
{{ form.text }}
</div>
{{ form.country.as_hidden }}
<div>
<input type="submit" value="post">
</div>
</form>
</div>
<h3> </h3>
<div class="col-md-12 column">
{% for tweet in tweets %}
<div class="well">
<span>{{ tweet.text }}</span>
</div>
{% endfor %}
</div>
</div>
{% endblock %}
When I issue command(run server), browser don't render form without any exception.
I think there is a problem in views.py file, But I can't find it.
How can I send form parameter to Template(.html file) and render form in result?
You didn't instantiate the form.
You need to instantiate the form, for rendering in a template, like this,
form = TweetForm()
Note:
The params variable is already a dict(), you could just add form into the params like this,
params['form'] = form
Then, render the template with context as params,
render(request, 'profile.html', params)

Categories

Resources