I'm new in django and i'm stuck now.
I'm trying to pass the url in form [action] attribute that would go to my edit function defined in [views.py] file and do it's job but whenever I try to pass the url [NoReverseMatch] is shown.
This is what i tried to do:
<div class="modal fade" id="editform" role="dialog">
<div class="modal-dialog">
<div class = "modal-content">
<div class = "modal-header">
<button type = "button" class = "close" data-dismiss="modal">×</button>
<h3 class="modal-title">
<b>Edit Information</b>
</h3>
</div>
<div class = "modal-body">
<form action="{% url 'studentapp:editrow' rowid=id %}" id="editform" method="POST">
{% csrf_token %}
<div class = "form-group">
<label for = "your_name">
Your name:
</label>
<input class = "form-control" id="new_name" type = "text" name="name" value="{{ student_detail.name }}" placeholder="Enter your name">
</div>
<div class="form-group">
<label for = "course_name">
Course:
</label>
<input id="new_course" class = 'form-control' type = "text" name="course" value="{{ student_detail.course }}" placeholder="Enter your course">
</div>
<div class = "form-group">
<label for = "rollno">
Roll No.:
</label>
<input id="new_rollno" type = "text" class = 'form-control' name="roll" value="{{ student_detail.roll }}" placeholder="Enter your roll number">
</div>
<div class = "form-group">
<label for ="addr">
Address:
</label>
<input id="new_address" type = "text" name="address" class = 'form-control' value="{{ student_detail.address }}" placeholder="Enter your address"/>
</div>
<input type = "submit" value="Update" id="update" class = "btn btn-success" style="font-size:18px;" />
</form>
</div>
</div>
</div>
</div>
In my urls.py I've used the following url:
url(r'^editrow/(?P<rowid>[0-9]+)/$', views.editrow, name='editrow'),
My [editrow] view looks something like this:
def editrow(request, rowid):
item = get_object_or_404(Studentapp, rowid=id)
print item
if request.method=="POST":
form = EntryForm(request.POST, instance=item)
if form.is_valid():
post=form.save(commit=False)
post.save()
return HttpResponseRedirect(reverse('studentapp:index'),rowid.id)
else:
form=EntryForm(instance=item)
return render(request, 'index.html',{'form':form})
else:
form=EntryForm(instance=item)
return render(request, 'index.html',{'form':form})
View that render's the template:
def index(request):
context = {}
latest_student = Studentapp.objects.order_by('pub_date')
context.update({
'latest_student': latest_student
})
response = {"status": False, "errors": []}
if request.is_ajax():
id = request.POST['id']
response = {}
response['status'] = False
student_detail = Studentapp.objects.filter(id=id).first()
context = {
"student_detail": student_detail
}
template = render_to_string("studentapp/_edit_student.html", context)
response['template'] = template
response['status'] = True
return HttpResponse(json.dumps(response), content_type="applicaton/json")
return render(request, "studentapp/index.html", context)
What i'm doing in crud is:
1) make an [edit] button in table through for loop.
2) when i click [edit] button a pre-populated form shows up(which i'm getting).
3) After i click the pre-populated form i want to edit that form and save it and updated data is reflected in my django db.
Thanks to #Alasdair, I looked in my code what he was trying to tell me and i got the answer.
The url that i was trying to pass through my action attribute was wrong. Here's what i did.
<form action="{% url 'studentapp:editrow' rowid=student_detail.id %}" id="editform" method="POST">
Through "student_detail" i'm able to get pre-populated form as i mentioned above. i used the same to get the id and pass it to my "editrow" view.
It's working for me now.
It seems like you never add id to your context in your view index. So the template does not have that variable available.
You need to add that id to your context.
Just like #Alasdair pointed out in the comments.
Related
I am working on the CS50 project2 commerce. I try to create a new list but when I click on the submit button, it doesn´t redirect to the index page as I want. Anybody can help please? I get the error message: auctions.models.Category.DoesNotExist: Category matching query does not exist. However I can add list directly from admin page.
views.py
def createlisting(request):
if request.method == "GET":
allCategories = Category.objects.all()
return render(request, "auctions/create.html", {
"categories": allCategories
})
else:
# get the data from the form
title = request.POST["title"]
description = request.POST["description"]
imageurl = request.POST["imageurl"]
price = request.POST["price"]
category = request.POST["category"]
currentuser = request.user
# get the contents
categoryData = Category.objects.get(categoryName=category)
#create new list object
newListing = Listing(
title=title,
description=description,
imageUrl=imageurl,
price=float(price),
category=categoryData,
owner=currentuser
)
newListing.save()
return HttpResponseRedirect(reverse("index"))
create.html
{% extends "auctions/layout.html" %}
{% block body %}
<h2>Create New Listing</h2>
<form action = "{% url 'create' %}" method="POST">
{% csrf_token %}
<div class="form-group">
<label for="title">Title</label>
<input type="text" name="title" class="form-control" id="title" placeholder="Enter title">
</div>
<div class="form-group">
<label for="description">Description</label>
<input type="text" name="description" class="form-control" id="description" placeholder="Enter Description">
</div>
<div class="form-group">
<label for="imageurl">Image URL</label>
<input type="text" name="imageurl" class="form-control" id="imageurl" placeholder="Image Url">
</div>
<div class="form-group">
<label for="price">Price</label>
<input type="number" name="price" class="form-control" id="price" placeholder="Price">
</div>
<div class="form-group">
<label for="category">Choose a Category</label>
<select name="category" id="category">
{% for category in categories %}
<option value="category">{{category}}</option>
{% endfor %}
</select>
</div>
<button type="submit" class="btn btn-success">Create New Listing</button>
</form>
{% endblock %}
Use redirect. And you don't need to use else after returning in the if statement.
from django.shortcuts import redirect
def createlisting(request):
if request.method == "GET":
allCategories = Category.objects.all()
return render(request, "auctions/create.html", {
"categories": allCategories
})
# POST
title = request.POST["title"]
description = request.POST["description"]
imageurl = request.POST["imageurl"]
price = request.POST["price"]
category = request.POST["category"]
currentuser = request.user
# get the contents
categoryData = Category.objects.get(categoryName=category)
#create new list object
newListing = Listing(
title=title,
description=description,
imageUrl=imageurl,
price=float(price),
category=categoryData,
owner=currentuser
)
newListing.save()
return redirect("index")
Try this view:
def createlisting(request):
allCategories=""
if request.method == "GET":
allCategories = Category.objects.all()
else:
# get the data from the form
title = request.POST["title"]
description = request.POST["description"]
imageurl = request.POST["imageurl"]
price = request.POST["price"]
category = request.POST["category"]
currentuser = request.user
# get the contents
categoryData = Category.objects.get(categoryName=category)
#create new list object
newListing = Listing(
title=title,
description=description,
imageUrl=imageurl,
price=float(price),
category=categoryData,
owner=currentuser
)
newListing.save()
return redirect("index")
return render(request, "auctions/create.html", {
"categories": allCategories
})
I have been working on a search form and it's giving me this error when i open the url or submit the form.
I am watching a codemy django tutorial and the only thing that is different is that i have some code for pagination i don't know if that's what is affecting it.
base.html
<div class="header-search-wrapper novis_search">
<form method="POST" action="{% url 'listing' %}" name="searchform">
{% csrf_token %}
<div class="custom-form">
<label>Keywords </label>
<input type="text" placeholder="Property Keywords" name="search"/>
<!-- <label >Categories</label>
<select data-placeholder="Categories" name = "home_type" class="chosen-select on-radius no-search-select" >
<option>All Categories</option>
<option>Single-family</option>
<option>Semi-detached</option>
<option>Apartment</option>
<option>Townhomes</option>
<option>Multi-family</option>
<option>Mobile/Manufactured</option>
<option>Condo</option>
</select>
<label style="margin-top:10px;" >Price Range</label>
<div class="price-rage-item fl-wrap">
<input type="text" class="price-range" data-min="10000" data-max="100000000000" name="price-range1" data-step="1" value="1" data-prefix="$₦">
</div> -->
<button type="submit" class="btn float-btn color-bg"><i class="fal fa-search"></i> Search</button>
</div>
</form>
</div>
views.py
def listing(request):
if request.method == 'POST' and 'searchform' in request.POST :
search = request.POST['search']
print(search)
propertys = Property.objects.filter(name__icontains=search)
p = Paginator(Property.objects.order_by('-listed_on'), 2)
page = request.GET.get('page')
propertys = p.get_page(page)
nums = "p" * propertys.paginator.num_pages
return render(request, 'listing.html',{'search_keyword':search,'nums':nums,'propertys':propertys})
else:
p = Paginator(Property.objects.order_by('-listed_on'), 2)
page = request.GET.get('page')
propertys = p.get_page(page)
nums = "p" * propertys.paginator.num_pages
return render(request, 'listing.html',{'propertys':propertys, 'nums':nums})
I want to save a value in the database when the button is clicked without using a form.
I want to save the value in h2 to another model when the button is clicked.
What can i do?
TEMPLATE
<div class="widget-main">
<center><h2 name="urun" value="{{ urun.urun_adi }} ">{{ urun.urun_adi }}</h2></center>
</a>
<input type="submit" onclick="location.href='{% url 'sepete_ekle' %}'" value = "sepete ekle" class="btn btn-sm btn-default pull-right">
Sepete Ekle
</input>
{{urun.fiyat}} TL
</div>
VIEWS
def sepete_ekle(request):
if request.method == 'POST':
urun = request.POST["urun"]
status = 0
urunler = Siparis.objects.create(urun,status)
urunler.save()
messages.success(request, " Sepete Eklendi")
return redirect('/bayi/profil_duzenle')
else:
return HttpResponseRedirect("/")
MODEL
class Siparis(models.Model):
bayi = models.ForeignKey('auth.User', verbose_name='bayi', on_delete=models.CASCADE, related_name='bayi',limit_choices_to={'groups__name': "BayiGrubu"})
urun = models.ForeignKey(Urun, on_delete=models.CASCADE)
adet = models.IntegerField()
tarih = models.DateTimeField()
status = models.BooleanField()
class Meta:
verbose_name = 'Bayi Sipariş'
verbose_name_plural = 'Bayi Siparişleri'
Replace the html posted by you in problem statement with the below one.
<div class="widget-main">
<center>
<h2>{{ urun.urun_adi }}</h2>
</center>
<form method="POST" action="{% url 'sepete_ekle' %}">
<input type="hidden" value="{{ urun.urun_adi }}" name="urun" />
<input
type="submit"
value="sepete ekle"
class="btn btn-sm btn-default pull-right"
/>
</form>
{{urun.fiyat}} TL
</div>
to know more about form hidden fields, here is a simple explaination for reference check this out
Once try this, I hope it works.
Change view.py to this. Add an arguement to your function sepete_ekle.
def sepete_ekle(request,urun):
if request.method == 'POST':
status = 0
urunler = Siparis.objects.create(urun,status)
urunler.save()
messages.success(request, " Sepete Eklendi")
return redirect('/bayi/profil_duzenle')
else:
return HttpResponseRedirect("/")
And urls.py to this:
path('/path/to/function/<urun>',views.sepete_ekle,name='sepete')
And in your html file:
<div class="widget-main">
<center><h2 name="urun" value="{{ urun.urun_adi }} ">{{ urun.urun_adi }}</h2></center>
</a>
<input type="submit" onclick="location.href='{% url 'sepete_ekle' %}'" value = "sepete ekle" class="btn btn-sm btn-default pull-right">
Sepete Ekle
</input>
{{urun.fiyat}} TL
</div>
So, when you click the button the h2 value will be sent in the url and in the view it will be taken from the arguement.
This is my view.So I want to keep 2 different HTML forms in same view ,But I am unable to do so beacuse whenever I add 1 form , I get the error of other on being none.
def home(request):
name = None
if request.method == 'POST':
name = request.POST.get('name')
choices = request.POST.get('choices')
subtest = request.POST.get('subtest')
reference = request.POST.get('reference')
unit = request.POST.get('unit')
test = Test()
test.name = name
test.save()
subtest = Subtest()
subtest.test = Test.objects.get(name=choices)
subtest.name = subtest
subtest.unit = unit
subtest.reference_value = reference
subtest.save()
# print(name)
return redirect('home')
return render(request,'main.html',{})
I have got 2 different forms . I didn't use django forms because I wanted to try something new.
MY FIRST FORM
<form method="POST">
{% csrf_token %}
<div class="icon-holder">
<i data-modal-target="test-popup" class="icon-cross"></i>
</div>
<div class="input-group">
<input type="text" name="name" placeholder="Test name" />
</div>
<div class="button-group">
<button type="submit">Submit</button>
</div>
</form>
MY SECOND FORM
<form method="POST">
{% csrf_token %}
<div class="icon-holder">
<i data-modal-target="menu-test-popup" class="icon-cross"></i>
</div>
<div class="input-group">
<label for="test-select">Test Name:</label>
<select name="choices" id="test-select">
{% for test in test %}
<option value="{{test.name}}" name='choices'>{{test.name|title}}</option>
{% endfor %}
</select>
</div>
<div class="input-group">
<input type="text" name="subtest" placeholder="SubTest name" />
</div>
<div class="input-group">
<input type="text" name="reference" placeholder="Reference rate" />
</div>
<div class="input-group">
<input type="text" name="unit" placeholder="Unit" />
</div>
<div class="button-group">
<button type="submit">Submit</button>
</div>
</form>
first form
<form method="POST">
...
<input name="form_type" value="first-form" type="hidden">
</form>
second form
<form method="POST">
...
<input name="form_type" value="second-form" type="hidden">
</form>
view function
def view(request):
if method == "POST":
form_type = request.POST.get('form_type')
if form_type == "first-form":
# first form's process
elif form_type == "second-form":
#second form's process
You have two forms here, when you submit the second form, only the fields from the second form gets submitted.
so from this line
name = request.POST.get('name')
name will become None. But I believe your Test model does not take any None value for name field( the reason for you " IntegrityError at / NOT NULL constraint failed: lab_test.name ").
To overcome this, first check if there is any value for 'name' then proceed with creating the test instance
if name:
test = Test()
test.name = name
test.save()
Similarly check if the other fields are present for the second form before creating and saving the instance.
I want to validate my update form using form validation. When i leave a field blank and hit update button I get a blank page showing the error message. I want that error message to be displayed on top of that particular field when I leave it blank and hit update button.
This is my latest update view:
def update(request, id):
item = get_object_or_404(BookEntry, id=id)
if request.method == "POST":
form = UpdateForm(request.POST, instance=item)
# print template
error_messages = {
'error': form.errors,
}
if form.is_valid():
print(form.cleaned_data)
post = form.save(commit=False)
post.save()
return HttpResponseRedirect(reverse('bms:index'), id)
else:
form = UpdateForm()
return HttpResponse(json.dumps(error_messages))
return render(request, 'index.html',{'form':form})
This is my old update view:
def update(request, id):
item = get_object_or_404(BookEntry, id=id)
if request.method=="POST":
form = UpdateForm(request.POST, instance=item)
if form.is_valid():
post=form.save(commit=False)
post.save()
return HttpResponseRedirect(reverse('bms:index'), id)
else:
form=UpdateForm(instance=item)
return HttpResponseRedirect(reverse('bms:index'), id)
return render(request, 'bms.html',{'form':form})
This is my forms.py:
class UpdateForm(forms.ModelForm):
title = forms.CharField(max_length=100)
author = forms.CharField(max_length=100)
edition = forms.CharField(max_length=100)
publisher = forms.CharField(max_length=100)
genre = forms.CharField(max_length=100)
detail = forms.CharField(max_length=100)
language = forms.CharField(max_length=100)
price = forms.IntegerField()
dop = forms.CharField(max_length=100)
cop = forms.CharField(max_length=100)
copyright = forms.CharField(max_length=100)
isbn = forms.IntegerField()
class Meta:
model = BookEntry
fields = '__all__'
This is my html form:
<form action="{% url 'bms:update' book.id %}" id="updateform" name="updateform" method="POST">
{% csrf_token%}
<div class = "form-group">
<label for = "title">
Title:
</label>
<input class = "form-control" id="book_title" type = "text" name="title" value="{{ book.title }}">
</div>
<div class="form-group">
<label for = "author">
Author:
</label>
<input id="book_author" class = 'form-control' type = "text" name="author" value="{{ book.author }}">
</div>
<div class = "form-group">
<label for = "edition">
Edition:
</label>
<input id="book_edition" type = "text" class = 'form-control' name="edition" value="{{ book.edition }}">
</div>
<div class = "form-group">
<label for ="publisher">
Publisher:
</label>
<input id="book_publisher" type = "text" name="publisher" class = 'form-control' value="{{ book.publisher }}"/>
</div>
<div class = "form-group">
<label for ="genre">
Genre:
</label>
<input id="book_genre" type = "text" name="genre" class = 'form-control' value="{{ book.genre }}"/>
</div>
<div class = "form-group">
<label for ="detail">
Detail:
</label>
<input id="book_detail" type = "text" name="detail" class = 'form-control' value="{{ book.detail }}"/>
</div>
<div class = "form-group">
<label for ="language">
Language:
</label>
<input id="book_language" type = "text" name="language" class = 'form-control' value="{{ book.language }}"/>
</div>
<div class = "form-group">
<label for ="price">
Price:
</label>
<input id="book_price" type = "text" name="price" class = 'form-control' value="{{ book.price }}"/>
</div>
<div class = "form-group">
<label for ="dop">
DOP:
</label>
<input id="book_dop" type = "text" name="dop" class = 'form-control' value="{{ book.dop }}"/>
</div>
<div class = "form-group">
<label for ="cop">
COP:
</label>
<input id="book_cop" type = "text" name="cop" class = 'form-control' value="{{ book.cop }}"/>
</div>
<div class = "form-group">
<label for ="cop">
Copyright
</label>
<input id="book_copyright" type = "text" name="copyright" class = 'form-control' value="{{ book.copyright }}"/>
</div>
<div class = "form-group">
<label for ="isbn">
ISBN:
</label>
<input id="book_isbn" type = "text" name="isbn" class = 'form-control' value="{{ book.isbn }}"/>
</div>
<input type = "submit" value="Update" id="update" class = "btn btn-success" style="font-size:18px;" />
</form>
This is the URL it shows when a field is left empty:
http://127.0.0.1:8000/bms/update/2/
And this is the error message:
{"error": {"edition": ["This field is required."]}}
I had left edition field empty to check if validation is working properly or not.
Can anyone suggest me how to do it the right way?
As Daniel pointed out, you need to re-render the form.
The basics of HTTP Form Post are:
If the form is valid: save + do a HttpResponseRedirect
If the form is not valid; re-render the same template with the errors
Change your function to:
def update(request, id):
item = get_object_or_404(BookEntry, id=id)
if request.method == "POST":
form = UpdateForm(request.POST, instance=item)
# print template
error_messages = {
'error': form.errors,
}
if form.is_valid():
print(form.cleaned_data)
post = form.save(commit=False)
post.save()
return HttpResponseRedirect(reverse('bms:index'), id)
return render(request, 'index.html',{'form':form}) # Form invalid case is handled here; the form is reused from above; form.errors is available in the template now
else:
pass # Handle GET requests here