Django inline formset(UI) delete/remove - python

I'm trying to do a inline formset with UI not with django built in inlineformset_factory form. Here I'm done with add_view and edit_view. Here in the edit view I can update the existing record for the both parent and child model,and can add new record to the child model. But I cant remove the existing record from the child model in inline formset.Every thing is fine working at client side. When I click remove button from the UI, the record is removed by javascript, But in server side, in the edit_view the #Delete Existing record block cloud take the delete/remove functionality. I tried in many possible ways but I can't make the delete query for the removed items form the client side.
models.py
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=128)
def __unicode__(self):
return self.name
class Product(models.Model):
category = models.ForeignKey(Category)
name = models.CharField(max_length=128)
price = models.CharField(max_length=128)
views.py
def add(request):
context = RequestContext(request)
if request.method == 'POST':
category = Category.objects.create(name = request.POST['category'])
try:
for n in range(1,7):
product = Product.objects.create(category= category,name=request.POST['name_'+str(n)],price=request.POST['price_'+str(n)])
except KeyError:
pass
return HttpResponseRedirect('/')
return render_to_response('add.html',context)
def edit(request,pk):
category = get_object_or_404(Category,id=pk)
product = Product.objects.filter(category=category)
product_count = product.count()
context = RequestContext(request)
if request.method == 'POST':
for c in Category.objects.filter(id = category.id):
c.name = request.POST['category']
c.save()
try:
#Update Existing record(child)
for p,n in zip(Product.objects.filter(category = c),range(1,7)):
p.name = request.POST['name_'+str(n)]
p.price = request.POST['price_'+str(n)]
p.save()
except KeyError:
#Delete Existing record(child)
try:
for d in range(1,7):
for i in Product.objects.all().filter(name=request.POST.get('name_'+str(d)),price=request.POST.get('price_'+str(d))):
print i.name
except KeyError:
pass
else:
#Add new record(child)
try:
for r in range(1,7):
product,created = Product.objects.update_or_create(category= category,name=request.POST['name_'+str(r)],price=request.POST['price_'+str(r)])
except KeyError:
pass
return HttpResponseRedirect('/')
args = {'category':category,'product':product,'product_count':product_count}
return render_to_response('edit.html',args,context)
add.html
<h1>Add</h1>
<script type="text/javascript">
var i = 1;
function addProduct(){
if (i <= 5){
i++;
var div = document.createElement('div');
div.innerHTML = 'Name:<input type="text" name="name_'+i+'" >Price:<input type="text" name="price_'+i+'" ><input type="button" value="-" onclick="removeProduct(this)">';
document.getElementById('products').appendChild(div);
}
}
function removeProduct(div) {
document.getElementById('products').removeChild( div.parentNode );
i--;
}
</script>
<form method="post" action="/add/">{% csrf_token %}
<label>Category</label>
<div>
<input type="text" name="category">
</div>
<label>Product</label>
<div id="products">
<input type="button" id="add_product()" onClick="addProduct()" value="+" />(limit 6)<br>
Name:<input type="text" name="name_1">Price:<input type="text" name="price_1">
</div>
<div>
<input type="submit" value="Submit">
</div>
</form>
edit.html
<h1>Edit</h1>
<script type="text/javascript">
var i = {{product_count}};
function addProduct(){
if (i <= 5){
i++;
var div = document.createElement('div');
div.innerHTML = 'Name:<input type="text" name="name_'+i+'" >Price:<input type="text" name="price_'+i+'" ><input type="button" value="-" onclick="removeProduct(this)">';
document.getElementById('products').appendChild(div);
}
}
function removeProduct(div) {
document.getElementById('products').removeChild( div.parentNode );
i--;
}
</script>
<form method="post" action="/edit/{{category.id}}/">{% csrf_token %}
<label>Category</label>
<div>
<input type="text" name="category" value="{{category}}">
</div>
<label>Product</label>
<div id="products">
<input type="button" id="add_product()" onClick="addProduct()" value="+" />(limit 6)
{% for list in product %}
<div>
Name:<input type="text" name="name_{{ forloop.counter }}" value="{{list.name}}">Price:<input type="text" name="price_{{ forloop.counter }}" value="{{list.price}}"><input type="button" value="-" onclick="removeProduct(this)">
</div>
{% endfor %}
</div>
<div>
<input type="submit" value="Submit">
</div>
</form>

Related

Django HttpResponseRedirect doesn´t lead to the page

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
})

Django: how to pass data from view to forms to validate it

In my form class I have a contact field in string to save several contacts separated by semicolons. In the request, contacts is an array so I do a ";".join(contacts) to get one contact field for my class form. I would like to pass this ";"join(contacts) contact from my view to the form class to validate it.
I simplified the code to focus on the part I have difficulties
the model class:
class Accounts(AbstractBaseUser):
phone_numbers = models.CharField(max_length=255))
the form class:
from django import forms
from .models import Accounts
import re
class RegisterForm(forms.ModelForm):
confirm_password = forms.CharField()
class Meta:
model = Accounts
fields = ('phone_numbers')
def clean_phone_numbers(self):
phone_numbers = self.cleaned_data['phone_numbers']
if len(phone_numbers) < 10:
raise forms.ValidationError('Your number must not be less than 10 digits')
if len(phone_numbers) > 15:
raise forms.ValidationError('Your number must not exceed 15 digits')
regex = '^[0-9]{10,15}$'
if not (re.fullmatch(regex, phone_numbers)):
raise forms.ValidationError('The number must not contain letters')
return phone_numbers
The view:
from django.shortcuts import render, HttpResponse
from .forms import RegisterForm
import logging
# Create your models here.
def register_user(request):
context = {}
if request.method == 'POST':
numbers = request.POST.getlist('phone_numbers')
numbers = ",".join(numbers)
form = RegisterForm(request.POST, phone_numbers=numbers) # Error
else:
form = RegisterForm()
context['form'] = form
return render(request, 'authentication/register.html', context)
the template:
<form action="#" method="post" novalidate>
<div id="number-composant">
<div class="form-group" id="input-field">
<label for="{{form.phone_numbers.id_for_label}}">Votre numero *</label>
<div>
{% if form.is_bound %}
{% if form.phone_numbers.errors %}
<input type="text" class="form-control is-invalid" id="{{form.phone_numbers.id_for_label}}" name="{{form.phone_numbers.html_name}}" value="{{form.phone_numbers.value}}" required>
{% else %}
<input type="text" class="form-control" id="{{form.phone_numbers.id_for_label}}" name="{{form.phone_numbers.html_name}}" value="{{form.phone_numbers.value}}" required>
{% endif %}
{% else %}
<input type="text" class="form-control" id="{{form.phone_numbers.id_for_label}}" name="{{form.phone_numbers.html_name}}" required>
{% endif %}
{% if form.phone_numbers.errors %}
<ul class="errorDetail">
{% for error in form.phone_numbers.errors %}
<li> {{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</div>
<div>
<button type="button" class="btn btn-outline-primary-2 mt-1 mb-1" id="add-in"><span>Cliquez pour ajouter un autre numero <span class="ml-2">&plus;</span></span></button>
</div>
</div><!-- End .form-group -->
<script>
var i = 1
const MAX_LENGTH = 4
function remove(el){
document.getElementById('input-field').removeChild(el.parentNode.parentNode)
i--
}
function add(){
if(i<MAX_LENGTH){
div = document.createElement('div')
div.setAttribute('class', 'input-group mt-1')
html = ""
html += '<input type="text" class="form-control" placeholder="Un autre numero" name="{{form.phone_numbers.html_name}}">'
html += '<div class="input-group-append"><button type="button" class="btn btn-outline-primary-2" onclick="remove(this)"><span>&times</span></button></div>'
div.innerHTML = html
document.getElementById('input-field').appendChild(div)
i++
}
}
document.getElementById('add-in').addEventListener('click', add)
</script>
</div><!-- .End .tab-pane -->
</form><!-- End .form-box -->

How can I handle the data of post requests in Django

I want to receive a request by adding several inputs to the form by the user.
I want to know how to control the received data separately.
in html file, {% for i in request.POST.items %} it works. but in views.py, it doesn't work like this
views.py
def debate_create(request):
if request.method == "POST":
content = request.POST
for k,v in content.items:
if k == 'sup_title':
sup_title = SuperTitle()
sup_title.author = request.user
sup_title.super_title = v
sup_title.save()
elif 'img' not in k and 'section' in k:
sub_title = Subtitle()
sub_title.super_title = sup_title.super_title.id
sub_title.sub_title = v
sub_title.save()
elif 'img' in k:
stg = Images()
imgs = request.FILES
stg.images = imgs
stg.sub_title = sub_title.sub_title.id
stg.save()
elif 'section' in k and 'opt' in k:
opt = SelectOption()
opt.sub_title = sub_title.sub_title.id
opt.option = v
return render(request, 'polls/test.html')
models.py
class SuperTitle(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='debate_author')
super_title = models.CharField(max_length=100)
liker = models.ManyToManyField(User, related_name='debate_liker')
class Subtitle(models.Model):
super_title = models.ForeignKey(SuperTitle, on_delete=models.CASCADE)
sub_title = models.TextField(blank=True)
class Images(models.Model):
sub_title = models.ForeignKey(Subtitle, on_delete=models.CASCADE)
images = models.ImageField(null=True)
class SelectOption(models.Model):
sub_title = models.ForeignKey(Subtitle, on_delete=models.CASCADE)
option = models.CharField(max_length=20)
option_voter = models.ManyToManyField(User)
html
<form method="POST" id="debate_form" action="{% url 'polls:debate_create' %}">
{% csrf_token %}
<input type='text' name='sup_title' placeholder='제목'>
<div id="form_container">
<section id='section_1'>
<input type="text" name="section_1">
<input type="file" name="img_section_1" multiple>
<div id="section_1_div">
<input type="text" name="section_1_opt_1" value="1">
<input type="text" name="section_1_opt_2" value="2">
</div>
<input type="button" value="add option" onclick='add_option(this.id)' id="section_1">
<input type="button" value="sub option" onclick='sub_option(this.id)' id="section_1">
</section>
</div>
<input type="button" value='add content' onclick='add_content()'>
<input type="button" value='sub content' onclick='sub_content()'>
<input type="submit">
</form>
There was a confusion between the django syntax in HTML and the syntax in python.
html
{% for i in request.POST.items %}
views.py
#for i in request.POST.items >>> syntaxerror
for i in request.POST.items():

How to delete an item that is connected to a foreignkey django?

I have a problem adding a delete functionality to my simple django project which is a todoapp. The problem is when i press the delete button it redirect me to the same page but the item is not deleted. Can someone explain to me what is happening on my code?
This is my code solution but still does not work.
This is my views.py
def index(request, id):
ls = ToDoList.objects.get(id=id)
p = request.POST
if request.method == "POST":
if p.get("save"):
for item in ls.item_set.all():
item_id = str(item.id)
if "clicked" == p.get("c" + item_id):
item.complete = True
else:
item.complete = False
if p.get("text" + item_id) in p:
item.text = p.get("text" + item_id)
if p.get("d" + item_id) == "delete": # Solution
item.delete()
return HttpResponseRedirect("/%i" % ls.id)
item.save()
elif p.get("add"):
new_item = p.get("new")
if new_item:
ls.item_set.create(text=new_item)
else:
return HttpResponse("<strong>Invalid Input</strong>")
return render(request, "todoapp/index.html", {"ls": ls})
models.py
from django.db import models
class ToDoList(models.Model):
date = models.DateTimeField(auto_now_add=True)
name = models.CharField(max_length=200)
def __str__(self):
return self.name
class Item(models.Model):
toDoList = models.ForeignKey(ToDoList, on_delete=models.CASCADE)
text = models.CharField(max_length=500)
complete = models.BooleanField(default=False)
def __str__(self):
return self.text
index.html
{% extends 'todoapp/base.html' %}
{% block title %}View List{% endblock %}
{% block content %}
<h2>{{ls.name}}</h2>
<form method="post", action="#">
{% csrf_token %}
{% for item in ls.item_set.all%}
<div class="input-group mb-3">
<div class="input-group-prepend">
<div class="input-group-text">
<input class="btn btn-danger btn-sm" type="submit" name="d{{item.id}}" value="delete"> <!-- Solution -->
<input type="checkbox" name="c{{item.id}}" value="clicked" aria-label="Checkbox for following text input" {% if item.complete %} checked {% endif %}>
</div>
</div>
<input type="text" name="text{{item.id}}" value="{{item.text}}" class="form-control" aria-label="Text input with checkbox">
</div>
{% endfor %}
<div class="input-group mb-3">
<div class="input-group-prepend">
<button name="add", value="add", type="submit", class="btn btn-success">Add New</button>
</div>
<input type="text" name="new" value="" class="form-control">
</div>
<br>
<button name="save", value="save", type="submit", class="btn btn-success">Save</button>
</form>
{% endblock %}
I think it should work if you include the delete logic inside another 'if' clause.
if p.get("delete"):
for item in ls.item_set.all():
item_id = str(item.id)
if p.get("d" + item_id) == "delete": # Solution
item.delete()
return HttpResponseRedirect("/%i" % ls.id)
However, I'm not sure what you are trying to achieve as the end result. Here, only one item would get deleted (the item for which 'delete' button was clicked).

Trying to pass url in form action

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.

Categories