i am trying to build a django search functionality for my app but the input form keeps returning a none
views.py
def search(request):
if request.method == 'POST':
query = request.POST.get('text')
houses = Product.objects.filter(name__contains='query')
context = {
'houses':houses,
}
return render (request, 'searchresult.html', context)
search.html
<form>
<input type='text' placeholder='search houses>
<button type='submit'>Search</button>
</form>
First off, your python indentation is invalid, and your HTML is also invalid on the input line. I will assume this is a typo in the question, but if not, you have issues there.
Your main problem is the filter for houses:
houses = Product.objects.filter(name__contains='query')
is looking for a name containing the string "query". You need the variable you've just defined.
houses = Product.objects.filter(name__contains=query)
You have an indentation issue in the code you have posted.
You need to add action and method in your Form.
<form action="/url_of_search/" method="post">
Missing quote in input line.
<input type='text' placeholder='search houses'>
You need to use query instead of 'query' in the filter.
Product.objects.filter(name__contains=query)
Things missing in html code:
form action attribute
form method attribute
input field name attribute
<!-- add form attributes method and action -->
<form method="POST" action="{% url '<url_name>' %}">
<!-- add input attribute name to identify the field and pass the value in request body -->
<input type='text' placeholder='search houses' name='search_text'>
<button type='submit'>Search</button>
</form>
update views for search
def search(request):
if request.method == 'POST':
# use input field name to get the search text
query = request.POST.get('search_text')
houses = Product.objects.filter(name__contains=query)
context = {
'houses':houses,
}
return render (request, 'searchresult.html', context)
Related
I am struggling with validating a form based on damage_type choice field.
I show only one DamageTypeForm in the template (other two are hide by js .hide() function).
Each DamageTypeForm has got some required=True fields, therefore I cannot save the selected form this way:
def createDamage(request):
damage_specify_form = DamageSpecify(request.POST or None)
damage_type_form1 = DamageTypeForm1(request.POST or None)
damage_type_form2 = DamageTypeForm2(request.POST or None)
damage_type_form3 = DamageTypeForm3(request.POST or None)
if request.method == 'POST':
damage_type = request.POST.get('damage_type ')
if damage_type == 'DamageType1':
if damage_type_form1.is_valid():
damage_type_form1.save()
return reverse('damage:type1')
elif damage_type == 'DamageType2':
if damage_type_form2.is_valid():
damage_type_form2.save()
return reverse('damage:type2')
elif damage_type == 'DamageType3':
if damage_type_form3.is_valid():
damage_type_form3.save()
return reverse('damage:type3')
else:
damage_type_form1 = DamageTypeForm1()
damage_type_form2 = DamageTypeForm2()
damage_type_form3 = DamageTypeForm3()
context = {
'damage_specify_form': damage_specify_form,
'damage_type_form1': damage_type_form1,
'damage_type_form2': damage_type_form2,
'damage_type_form3': damage_type_form3,
}
return render(request, 'create_damage.html', context)
How can I get damage_type in View before submitting the form in the template, to save only desired form??
Here are two approaches you could take based on the answer to your previous question. Where it was suggested that you have:
<form>
{% csrf_token %}
{{damage_type_form.as_p}}
<div id="type1">
{{damage_form_1.as_p}}
</div>
<div id="type2">
{{damage_form_2.as_p}}
</div>
<div id="type3">
{{damage_form_3.as_p}}
</div>
<input type="submit" ...>
</form>
I'm not so sure why it was suggested to you that way. But the issue you highlighted is that the other forms (the hidden ones) do have required fields even though their respective forms are hidden.
So one way is to use the novalidate attribute on the form tag:
<form novalidate>
...
</form>
This novalidate is a form-level attribute used to turn off validation for a form, despite the attributes of the inputs it contains (i.e. will override inputs with the required attribute, or that would otherwise fail validation).
NOTE: Do not use novalidate if you simply want to internationalize or otherwise change the content of the default error messages. This can be done with JavaScript.
I personally don't think using the novalidate attribute is a good practice even though it might come in handy for some scenarios.
On the other hand, (my recommendation), you could use JavaScript or Jquery to set/remove the fields required attribute if the respective form is visible or not. For example:
# But let's say you do have separate forms...
<form id="form-1">
...
</form>
<form id="form-2" style="display:none">
...
</form>
# javascript
<script type="text/javascript">
# using jquery here...
$(document).ready(function(){
# Checking for a form's visibility
if($("#form-2").css('display') === 'none'){
# form-2: display is none. Therefore set its field attributes required to false
$('#form-2 input[type="text"]').removeAttr('required');
# or
# $('#form-2 #field_id').removeAttr('required');
}
else{
# form-2: display is not none. Therefore set its field attributes required to true
$('#form-2 input[type="text"]').attr('required','true');
# or
# $('#form-2 #field_id').attr('required','true');
}
});
</script>
Please note that the above JavaScript can be a bit cleaner, even adding some/an event listener to pick up when a form's visibility has changed: to set/remove the required attributes on a specific form.
That's just a basic concept of an approach I'd use.
i created a view + form that creates two widgets + a button for a user. One to select a choice and another to type something in. Now i want to redirect the user after the clicking the button to another webpage displaying his input. (Generally i want to know how to access the userinput and further use it).
This is my form:
class Eingabefeld(forms.Form):
eingabefeld = forms.CharField(label="Flight Number",max_length=20)
a = Auswahlmoeglichkeiten.objects.all()
flughafenname = forms.ModelChoiceField(label="Target Airport",queryset=a,empty_label="-------")
source = forms.CharField(
max_length=50,
widget=forms.HiddenInput(),
required=False
)
This is my views.py:
def get_eingabe(request):
log = logging.getLogger(__name__)
if request.method =="POST":
eingabe = Eingabefeld(request.POST)
log.warn(eingabe)
if eingabe.is_valid():
return HttpResponseRedirect("answerrequest")
else:
eingabe = Eingabefeld()
return render(request, "app_one/labels.html", {"eingabe": eingabe})
def answerrequestseite(request):
return render(request, "app_one/answerrequest.html")
and this is my html ( the included html in this one is just for layout):
<head>
<title>Home</title>
</head>
<form method="post" novalidate>
{% csrf_token %}
{% include "app_one/bootstrap_layout2.html" with form=eingabe %}
<div class="row">
<div class="col-sm-5"></div>
<div class="col-sm-2">
<button type="submit" class="btn btn-primary btn-block">Let's Go!</button>
</div>
<div class="col-sm-5"></div>
</div>
</form>
So basically when opening my webpage "get_eingabe" gets called, and the template gets rendered, now when clicking the button the input is validated and after successfull validation a different URL is opened which will trigger the method "answerrequestseite". Now how do i pass the userinput (eingabefeld and flughafenname) into the other method which will render the template for the second URL?
I read alot about using "request.GET" but i am not quite sure where exactly to place it and how.
After if eingabe.is_valid(): create some variable containing the values you want.
then in you redirect you need to pass those values as get argument like:
your_url/?id=123
Then you can retrieve your variable in your views.py via
request.GET.get('id')
But in your case, you don't want to pass simple id, you want to pass user_input.
One way will be to sanitize this input to make it url compatible.
Otherwise the more flexible solution is to store the values in the session.
Session (via cookie)
# views.py
# Set the session variable
request.session['you_variable_name_here'] = 'the value'
# Retrieve the session variable
var = request.session.get['you_variable_name_here']
https://docs.djangoproject.com/en/2.2/topics/http/sessions/
For your exemple in the first view:
if eingabe.is_valid():
eingabefeld = eingabe.cleaned_data.get('eingabefeld')
flughafenname = eingabe.cleaned_data.get('flughafenname')
request.session['eingabefeld'] = eingabefeld
request.session['flughafenname'] = flughafenname.pk
return HttpResponseRedirect("answerrequest")
In the second view:
def answerrequestseite(request):
eingabefeld = request.session.get('eingabefeld')
flughafenname_pk = request.session.get('flughafenname')
flughafenname = YourFlughafennameModel.objects.get(pk=flughafenname_pk)
return render(request, "app_one/answerrequest.html",{'eingabefeld':eingabefeld,'flughafenname':flughafenname})
In Django1.6, is there a way to pass a dynamic parameter to my view or URL without parsing the URL?
Ideally I would want a urls.py that looks like:
url(r'^dash/$',
dash_view.account_modify,
{'account': **dynamic_account_identifier_here**}
name='dash_account_modiy')
And in views.py:
def account_modify(request, account,
template_name='profile.html,
change_form=AccountModifyForm):
...
:param account:
comes from model:
class Dash(models.Model):
name = models.Charfield()
account = models.IntegerField()
....
Basically, I would really like to avoid a urls.py with the account identifier as part of the string, like:
url(r'^dash/(?P<account>\w+)/$',
dash_view.account_modify,
name='dash_account_modiy')
Any suggestions on how I can pass these values from the a template to the processing view for use in the AccountModifyForm (which expects that 'account' parameter)?
url(r'^dash/$',
dash_view.account_modify,
{'account': **dynamic_account_identifier_here**}
name='dash_account_modify')
You can't dynamically evaluate anything there, because the dictionary is evaluated only once, when the URL conf is loaded.
If you want to pass information from one view to another your three options are:
in the URL, which you don't seem to want to do
as GET or POST data
store it in the session in one view and retrieve it from the session in the next
If anyone cares...figured it out...
In the template:
{% for dash in dashes %}
blah blah blah
<form action="..." method="POST">
<input type="hidden" name="id" value="{{ dash.account }}">
{{ form.as_ul }}
<input type="submit" value="Do stuff">
</form>
{% endfor %}
In the views:
if request.method == 'POST'
account = request.POST['id']
# be sure to include checks for the validity of the POST information
# e.g. confirm that the account does indeed belong to whats-his-face
form = AccountModifyForm(request.POST, account,
user=request.user)
....
{% if firstpass != secondpass %}
errors.append('Passwords are not the same')
I am trying to make a page where users can change their personal information. This one in particular pertains to checking whether the password textbox (firstpass) and password re-entering textbox (secondpass) contain the same password. For some reason, I am getting a compiler error on the line with the != sign. Can anyone suggest why? : (
If my taught is right you need to append this error message to errors list. Then you need to change it a bit.
First you need to create a form in template. I just create a dummy form for understand what happening.
<form action="/password-confirm/" method="post">{% csrf_token %}
<input type="text" name="firstpass">
<input type="text" name="secondpass">
<input type="submit" name="">
</form>
Second Create a view in views.py.
def password_confirm(request):
if request.method == "POST":
firstpass = request.POST["firstpass"]
secondpass = request.POST["secondpass"]
if firstpass == secondpass:
// Write code if passwords are same.
else:
errors.append("Passwords are not the same")
return render(request, 'password_confirm.html')
Third in urls.py.
url(r'^password-confirm/$', 'happytenants.views.password_confirm', name='about_us'),
And if you need to display error in template, you just pass the variable to template.
def password_confirm(request):
...
return render(request, 'password_confirm.html', {"errors": errors})
I'm using the code found here (SO.com) to use the same template to both add and edit a record, but when I add a new record and click Submit, I get a 404 on the URL http://192.168.1.3:5678/app/student/edit/None/, and I'm not exactly sure why.
Here is the relevant portion of my urls.py:
url(r'^app/lesson/new/$', 'edit_lesson', {}, 'lesson_new'),
url(r'^app/lesson/edit/(?P<id>\d+)/$', 'edit_lesson', {}, 'lesson_edit'),
Here is the relevant portion of my views.py:
def edit_lesson(request, id=None, template_name='lesson_edit_template.html'):
if id:
t = "Edit"
lesson = get_object_or_404(Lesson, pk=id)
stu = get_object_or_404(Student, pk=sid)
if stu.teacher != request.user:
raise HttpResponseForbidden()
else:
t = "Add"
lesson = Lesson()
if request.POST:
form = LessonForm(request.POST, instance=lesson)
if form.is_valid():
form.save()
# If the save was successful, redirect to another page
return view_lessons(request)
else:
form = LessonForm(instance=lesson)
return render_to_response(template_name, {
'form': form,
't': t,
'lesson': lesson,
}, context_instance=RequestContext(request))
And finally, here is my template:
<h1>{{ t }} Lesson</h1>
<form action="/app/lesson/edit/{{ lesson.id }}/" method="post"> {% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
I'm certain that I'm missing something really easy, but I can't seem to put my finger on it. I'm using Django 1.3.1 if that makes any difference.
Thanks,
MC
There's no need to specify any URL in the form's action attribute. Just do
<form action="" method="post">
and it will POST back to the URL that you originally used to access it, which is what you want.
In add case {{ lesson.id }} is None, because lesson is unsaved Lesson() instance, without pk, so your form is being fired to nonexistent URL.
I recommend separating create and edit views and processing them in different ways (or even inherit generic views - with new class-based generic views it's easy and pleasant).
Also, use {% url %} template tag everywhere instead of hard-coded urls.