TOday I am trying to make some kind of to-do list. I know how to add tasks(comments) and now I want to delete them with a button. I don't know how to delete exact task (comment). Code:
#views.py
def add_comment(request):
comments = Comment.objects.all()
if request.method == 'POST':
form = CommentForm(request.POST)
if "delete" in request.POST:
#HERE MAGIC HAPPENS
if form.is_valid():
save_it = form.save()
return render(request, 'task-result.html', {
'form': form, 'comments': comments,
})
else:
form = CommentForm()
return render(request, 'Task-form.html', {
'form': form,
})
#HTML
<form action="">
{% for a in comments %}
<h3>{{ a.body}}</h3>
<input type="submit" name="delete" value="delete" />
{% endfor %}
{% csrf_token %}
</form>
So how to make "magic" happen?
Addition
Now I'm facing new problems. Delete button does nothing or i get eroor: invalid literal for int() with base 10: ''. Code:
#Template:
<html>
<head>
<title>Name</title>
</head>
<body>
<h1>Tasks</h1>
<form action="" method="post">
{{ form.as_p }}
<input type="submit" value="Create task">
{% for a in comments %}
<h3>{{ a.body}}</h3>
<input type="submit" name="delete" value="delete" />
<input type="hidden" name="idcomment" id="{{comments.id}}" />
{% csrf_token %}
</form>
{% endfor %}
</body>
</html>
#Views
def add_comment(request):
comments = Comment.objects.all()
if request.method == 'POST':
form = CommentForm(request.POST)
if "delete" in request.POST:
comments_id = request.POST['idcomment']
comments_object = Comment.objects.get(id=comments_id)
comments_object.delete()
if form.is_valid():
save_it = form.save()
return render(request, 'task-form.html', {
'form': form, 'comments': comments,
})
else:
form = CommentForm()
return render(request, 'Task-form.html', {
'form': form, 'comments': comments,
})
Can you help me solve this one?
My solution will be to add a function delete in your views that will take for argument the comment number.
def del_comment(request, commentsid):
comments = Comment.objects.get(id=commentsid)
comments.delete()
and your url:
url(r'^yoururl/del/(?P<commentsid>\d+)/', del_comment),
in your template link your comment button delete to this url
yoururl/del/{{yourvalue of the comment that will give the id of the current comment}}
example in templates:
{% for a in comments %}
<h3>{{ a.body}}</h3>
Delete ME
{% endfor %}
There is another solution that may work:
if request.method == 'POST':
form = CommentForm(request.POST)
if "delete" in request.POST:
comments_id = request.POST['idcomment'] #the name of the hidden field and get the id of the comment.
comments_object = Comment.objects.get(id=comments_id)
comments_object.delete()
if form.is_valid():
save_it = form.save()
return render(request, 'task-result.html', {
'form': form, 'comments': comments,
})
the hidden field should look like this in your template:
<input type="hidden" name="idcomment" id="{{comments.id}}" /> #or value="{{comments.id}} sorry i do not have my own example on hand.
Related
I'm trying to make a view containing one form and one formset but something does not work.
both form and formset after checking if .is_valid returns false. I do not really undersand why it is like that
def ProductCreateView(request):
context = {}
created_product = None
form = ProductForm()
if request.method == 'POST':
form = ProductForm(request.POST)
if form.is_valid():
created_product = form.save()
print("Successfully created new product: {}".format(created_product))
else:
print("form is not valid")
#print(request.POST) returns csrfmiddlewaretoken ...
#print(request.FILES) returns file : inmemoryuploadedfile ...
#print(list(request.POST.items()))
context['form'] = form
formset = ProductPhotoInlineFormset()
if request.method=='POST':
formset = ProductPhotoInlineFormset(request.POST or None, request.FILES or None, instance=created_product)
if formset.is_valid():
created_images = formset.save()
print("Successfully created new imagest: {}".format(created_images))
else:
print("formset is not valid")
context['formset'] = formset
return render(request, "Ecommerce/create_product_test.html", context)
my template - create_product_test.html
{% extends 'base.html' %}
{% block content %}
<div id="alert-box">
</div>
<div id="image-box" class="mb-3">
</div>
<div id="image-box"></div>
<div class="form-container">
<button class="btn btn-primary mt-3 not-visible" id="confirm-btn">confirm</button>
<form method="POST" enctype="multipart/form-data" action="" id="image-form">
{% csrf_token %}
<div>
{{form}}
{{formset.management_form}}
{{formset.as_p}}
</div>
</form>
</div>
{% endblock content %}
forms.py file
ProductPhotoInlineFormset = inlineformset_factory(
Product,
Photo,
fields=('file',),
form=PhotoForm,
extra=1,
)
where is the problem ?
You can find out what's wrong with the form with:
print(form.errors)
print(form.non_field_errors())
and for a formset:
print(formset.errors)
print(formset.non_form_errors())
This way, you can easily find out why the form is not valid.
The form is always sending a Get request instead of a Post which has been explicitly added using method = "POST". So, not able to persist the data to db. I have just started with Django so, any help will be appreciated.
Below are the code snippets:
create_order.html
<form method="POST" action="{% url 'home' %}">
{% csrf_token %}
{{form}}
<input class="btn btn-primary btn-sm" type="submit" name="Submit">
</form>
urls.py
urlpatterns = [
path('', views.dashboard, name='home'),
path('products/', views.product, name='products'),
path('customer/<str:cust_id>/', views.customer, name='customer'),
path('create_order/', views.create_order, name='create_order'),
]
views.py
def create_order(request):
form = OrderForm()
if request.method == 'POST':
print("In Post", request.method)
form = OrderForm(request.POST)
if form.is_valid():
form.save()
return redirect('/')
else:
print("In else", request.method)
print(form.is_valid())
if form.is_valid():
form.save()
return redirect('/')
context = {'form' : form}
return render(request, 'accounts/create_order.html', context)
terminal output
In else GET False
You are making a POST request to the wrong view. It should be the create_order view, so:
<form method="POST" action="{% url 'create_order' %}">
{% csrf_token %}
{{ form }}
<input class="btn btn-primary btn-sm" type="submit" name="Submit">
</form>
Note that you should not validate the form in case of a GET request, since then you only render the form. So the view logic should be:
def create_order(request):
if request.method == 'POST':
print("In Post", request.method)
form = OrderForm(request.POST)
if form.is_valid():
form.save()
return redirect('home')
else:
form = OrderForm()
context = {'form' : form}
return render(request, 'accounts/create_order.html', context)
Try to add form action method in your HTML file
<form action="" method="post">{% csrf_token %}
{{ form}}
<input type="submit" value="Submit Feedback" />
</form>
</div>
I have a for loop that lists all the testimony instances in my model. I'd like to have the button in the code below delete the related instance when clicked.
html
{% block content %}
{% for testimony in testimonies %}
<a href="{% url "main:update_testimony_view" slug=testimony.slug %}">
<h3>{{testimony.name}}</h3>
<button type="button" class="btn btn-danger">Delete</button>
</a>
{% endfor %}
****
{% endblock content %}
views.py
def create_testimony_view(request):
if request.method == "POST":
form = CreateTestimonyForm(request.POST)
if form.is_valid():
testimony = form.save(commit=False)
testimony.save()
return redirect('main:homepage_view')
else:
form = CreateTestimonyForm
context = {
"title": "Create - Testimony",
"form": form,
"testimonies": Testimony.objects.all(),
}
return render(request=request, template_name="main/create/create_testimony.html", context=context)
def update_testimony_view(request, slug):
instance = get_object_or_404(Testimony, slug=slug)
if request.method == 'POST':
form = CreateTestimonyForm(
request.POST, request.FILES, instance=instance)
if form.is_valid():
testimony = form.save(commit=False)
testimony.save()
return redirect('main:homepage_view')
else:
form = CreateTestimonyForm(instance=instance)
context = {
"title": "Update - Testimony",
"form": form,
"instance": instance,
}
return render(request=request, template_name="main/create/create_testimony.html", context=context)
Thanks for any help
You need to make a POST request to the server which will delete the instance.
Please have a look at Form documentation. https://docs.djangoproject.com/en/3.0/topics/forms/
You need to add simple form and view to delete testimony.
html,
{% for testimony in testimonies %}
<a href="{% url "main:update_testimony_view" slug=testimony.slug %}">
<h3>{{testimony.name}}</h3>
<form action="{% url 'main:delete_testimony' testimony.pk %}" method="POST">
<button type="button" class="btn btn-danger">Delete</button>
</form>
</a>
{% endfor %}
view,
def delete_testimony(request, pk):
deleted = False
try:
Testimony.objects.delete(pk=pk)
deleted = True
except Testimony.DoesNotExist:
pass
return JsonResponse({'deleted':deleted})
I have a simple Form, view and a html that renders the form. but the problem is that the form always returns form.is_valid == False.
So I have checked the cleaned data but I noticed that self.cleaned_data returns an empty list.
Here is the relevant code:
class GraphForm(forms.Form):
from_month = forms.DateField(widget=forms.Select(choices=MONTHS))
from_year = forms.DateField(widget=forms.Select(choices=YEARS))
to_month = forms.DateField(widget=forms.Select(choices=MONTHS))
to_year = forms.DateField(widget=forms.Select(choices=YEARS))
def clean(self):
return self.cleaned_data <<< will always stay be empty
def showgraph(request):
if request.method == 'POST':
form = GraphForm(request.POST)
if form.is_valid():
>>> will never happen <<<
...
...
...
else:
form = GraphForm()
return render(request, 'graph.html', {"form": form})
<form method="post">
{% csrf_token %}
{{ form.from_month }}
{{ form.from_year }}
<br>
{{ form.to_month }}
{{ form.to_year }}
<br>
<p align="center">
<button type="submit" class="btn btn-primary">send</button>
</p>
</form>
Can anyone help with this peculiar problem?
The <form> tag should have action besides method so that the submit button can work, like this.
<form action="{% url 'name_of_the_view' %}" method="post">
...
</form>
If the code doesn't reach inside form.is_valid(), then it means the form is not valid, add an else to if and print the form.errors() and return the same form to template also add form error in the template to see the errors.
def showgraph(request):
if request.method == 'POST':
form = GraphForm(request.POST)
if form.is_valid():
>>> will never happen <<<
else:
print(form.errors())
else:
form = GraphForm()
return render(request, 'graph.html', {"form": form})
Add error for each field:
<span class="text-danger">{{field.errors.as_text|cut:'* '}}</span>
I am trying to make simple to-do list where user can add or delete list items. With adding everything works fine, but when I trying to delete item nothing happens or I get erorr: invalid literal for int() with base 10: ''
Code:
#Views.py
def tasks(request):
comments = Comment.objects.all()
if request.method == 'POST':
form = CommentForm(request.POST)
if "add" in request.POST:
if form.is_valid():
save_it = form.save()
if "delete" in request.POST:
comments_id = request.POST['idcomment']
comments_object = Comment.objects.get(id=comments_id)
comments_object.delete()
return render(request, 'task-form.html', {
'form': form, 'comments': comments,
})
else:
form = CommentForm()
return render(request, 'Task-form.html', {
'form': form, 'comments': comments,
})
And Django template is:
<html>
<head>
<title>Tasks</title>
</head>
<body>
<h1>Tasks</h1>
<form action="" method="post">
{{ form.as_p }}
<input type="submit" name="add" value="add">
{% for a in comments %}
<h3>{{ a.body}}</h3>
<input type="submit" name="delete" value="delete" />
<input type="hidden" name="idcomment" id="{{a.id}}" />
{% endfor %}
{% csrf_token %}
</form>
</body>
</html>
Where is my mistake?
This error is because comments_id is an empty string, because request.POST['idcomment'] is an empty string, and you can't convert an empty string to an int (which is what happens when you do Comment.objects.get(id=comments_id)). Why is it empty? Let's look at your template:
<input type="hidden" name="idcomment" id="{{a.id}}" />
You gave the input an id, but you never gave it a value. Try this:
<input type="hidden" name="idcomment" id="{{a.id}}" value="{{a.id}}"/>