Delete items from ListView in Django 1.5 - python

I have a ListView and a DeleteView
class MyDeleteView(DeleteView):
success_url = reverse('list')
I want the option to delete the items in the ListView. I know how to do it if I accept the confirmation page in the DeleteView, but I don't want no template in my DeleteView. I just want to delete the item and send the user back.
I guess it should be with POST parameters, but what should the HTML look like? I guess it's something like:
<form method="post" action="/delete/">
<ul>
<li>Item1 (<input type="submit" value="Delete" />)</li>
<li>Item2 (<input type="submit" value="Delete" />)</li>
<li>Item3 (<input type="submit" value="Delete" />)</li>
</ul>
</form>
Can anyone lead me in the right direction? Thank you.

You're already heading the right way, with POST.
<ul>{% for item in object_list %}
<li><form method="post" action="{% url 'mydelete' pk=item.pk %}">
{{item}} (<input type="submit" value="Delete" />)
</form></li>
{% endif %}</ul>
I'm not entirely sure if the the inputs can go directly in a form in the HTML spec you're trying to adhere to. So you might have to sprinkle this idea with some spans or containers.
If the input submit, doesn't give your designers enough styling freedom, you could use them as the <noscript> fallback and add some <button> or javascript: link for the pretty version.

Since you don't want a confirmation, you can override the GET method in your deleteview and just use links:
class MyDeleteView(DeleteView):
success_url = reverse('list')
def get(self, *a, **kw):
return self.delete(*a, **kw)
<ul>
{% for item in object_list %}
<li>Item1 (Delete)</li>
{% endif %}
</ul>

Related

Python Django - update booleanField via List View

Is there any way how to update booleanField in the list view? In list view I have listed all my orders and I need to mark which are done and which are not done. I know I can update it via UpdateView, but that is not user friendly because I have to leave the listview page.
models.py
class Order(models.Model):
...
order = models.CharField(max_length = 255)
completed = models.BooleanField(blank=True, default=False)
views.py
class OrderIndex(generic.ListView):
template_name = "mypage.html"
context_object_name = "orders"
def get_queryset(self):
return Order.objects.all().order_by("-id")
mypage.html
{% extends "base.html" %}
{% block content %}
{% for order in orders%}
User: {{ order.user}} | Completed: {{order.completed}} <input
type="checkbox">
{% endfor %}
<input type="submit">
{% endblock %}
I am quite new to the django framework and have no idea how to make it work.
like this should look you javascript
const updateField = (order_id) =>{
var form = new FormData();
form.append('order_id', order_id);
fetch('{% url "url_updateField" %}', {
method:'post',
body:form,
mode:'cors',
cache:'default',
credentials:'include',
}).then((response)=>{
console.log('field update as well')
})
})
just add a function to your button on envent onclick
{% extends "base.html" %}
{% block content %}
{% for order in orders%}
User: {{ order.user}} | Completed: {{order.completed}} <input
type="checkbox" onclick="updateField({{order.pk}})">
{% endfor %}
<input type="submit">
{% endblock %}
then in your view you should have the below view to process the request
def updateField(request):
print(request.body.get('order_id'))
#you should update you model field here
return JsonResponse({'ok':True}, status=200)
This will help you How to work with ajax request with django
Combine the UpdateView with the part of the listView's functionality by adding to the UpdateView the extra context of the entire list of objects:
class OrderUpdateView(generic.UpdateView):
model = Order
form_class = OrderForm
....
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['orders'] = Order.objects.all().order_by("-id")
return context
Consider a simple template where the entire list is displayed on top, and the bottom has a form allowing the user to update a particular item in the list.
This approach purposefully avoids using Ajax and javascript.
documentation
There is a way to do this without any special magic, just post to an update view from your listview with the entire form filled out correctly in hidden form fields nothing special needs to be done anywhere else.
<!-- todo_list.html -->
<form method="POST" action="update/{{object.id}}/">
{% csrf_token %}
<input type="hidden" name="completed" value="true" />
<input type="hidden" name="name" value="{{object.name}}" />
<input type="hidden" name="due_date" value="{{object.due_date|date:'Y-m-d'}}" />
<input type="hidden" name="details" value="{{object.details}}" />
<button type="submit" class="btn btn-primary">Not Done</button>
</form>

How can I generate buttons or fields (forms) in Flask according to a list of strings?

Well, suppose we have a list of strings (objects with a toString() method respectively) and a jinja2 template that shall have selection forms (buttons or something alike) that agree in number and label to the list. This list may alter during the session. So far, I tried to work with submit buttons and radio buttons. Problems are: submit buttons vary in size because of different string length and I dislike that radio buttons force the user to first make a choice and then submit it.
The jinja2 markup looks like this:
<form method = 'post' action= "{{ url_for('add_dialogue_turn') }}">
{% if questions %}
{% for q in questions %}
<input type="radio" name="question" value={{q}}> {{q}} <br>
{% endfor %}
{% endif %}
<input type="submit" /><br /><br />
</form>
The flask function looks like this:
#app.route("/turn", methods=['POST'])
def add_dialogue_turn():
label = request.form["question"]
print(label)
return render_template("sometemplate.html", questions=aListOfQuestions, answers = aListOfAnswers)
Can I make the radio buttons submit the value directly after ticking off the circle? Or can I define some field that returns the string when clicking on it?
Thank you for your help in advance!
This is a Front end problem. You would need either JavaScript to submit your form when a button/radio is ticked. And it also depends on how you submit your form but if you want just the data to be passed into the server without page reloading, I'd suggest Ajax. And if you just want to pass the input value into the server, you do not have to use post.
A simple example would be,
-HTML
<input type="radio" name="question" value={{q}} id="{{something_unique_for_each_iterable}}" onclick="submitFunction(this)">
-JavaScript
function submitFunction(event){
id_of_radio_ticked = '#' + event.id;
$.ajax({
url: "{{url_for('to_your_flask_view_function')}}",
type: 'GET',
data: {'radio_value':$(id_of_radio_ticked).val()},
success: function(resp){
alert('do something with returned data')
}
});
}
I found another solution within the jinja template:
<nav>
<ul>
<div class="sideMenuL">
<form method = 'post' action= "{{ url_for('add_dialogue_turn') }}">
{% if questions %}
{% for q in questions %}
{% autoescape false %}
<input type="submit" name="question" value="{{q}}"><br>
{% endautoescape %}
{% endfor %}
{% endif %}
</form>
</div>
</ul>
</nav>

Delete an object in Django

I am trying to delete an object. This is the HTML, todo should be deleted when you Click on button (I am trying to call delete_todo) :-
<ul>
{% for all %}
</ul>
This is the views.py,
You need to change few things in your code.
First of all change urlpattern delete_todo you need to add argument, which allows to determine in view what object you want to delete:
url(r'^(?P<todo_id>[0-9]+)/$', views.delete_todo, name='delete_todo'),
Then you need change delete_todo itself:
def delete_todo(request, todo_id):
instance = get_object_or_404(Todo, pk=todo_id)
instance.delete()
return redirect('index')
Here you can use get_object_or_404 fuction to get object with id.
And finally you need to pass url's argument to view from template:
<form action="{% url 'lists:delete_todo' todo_id=todo.id %}" method=post>
<input id="submit" type="button" value="Click" />
</form>
Just to add clarification on the use of the form and csrf: it's necessary in order to ensure that different users of your app can't delete content that isn't theirs.
In your template, you'll need to include the csrf tag as such:
<form method="post" action={% url 'delete_todo' todo_id=todo.id %}>
{% csrf_token %}
<input type="button" id="submit" value="Delete" />
</form>

Can I build my form without using Django form?

I'm using Django and I just did a big form Using HTML5 and bootstrap. Can I still send the form via the post method to django if I'm not using it to generate the form? Should I definitely redo my form using Django?
NOTE: There may be a better way of doing this, if there is I'd really like to know, this is just how I have done it in the past.
You will still need a forms.py file in your app.
In forms.py:
from django import forms
class MyForm(forms.Form):
# FORM FIELDS HERE
Then put the form in the context dictionary for your view:
def myView(request):
if request.method == "POST":
# FORM PROCESSING HERE
else:
myform = MyForm() #create empty form
return render(request, "template.html", {"myform": myForm}
Now in your template you can add:
<form id="myForm" name="myFormName" method="post" action=".">
{% csrf_token %}
{% for field in myform %}
{{ field.as_hidden }}
{% endfor %}
</form>
This will add your django form to the page without displaying it. All of your form inputs are given the id id_fieldName where fieldName is the field name you defined in the forms.py file.
Now when the user clicks your "submit" button (which I am assuming is a bootstrap button given the rest of your form is). You can use Jquery to input the bootstrap field values into those of the hidden form.
Something like:
$("#mySubmitButton").click(function() {
$("#id_djangoFormField").val($("#myBootstrapFormField").val());
$("#myForm").submit();
}
);
This will submit the django form with the inputs from bootstrap. This can be processed in the view as normal using cleaned_data["fieldName"].
A bit late I post the solution I found for including a form in a modal in a class based detail view. Dunno if it's really orthodox but it works.
I don't use any Form Class or Model. (Django 3.9)
Within the template, I send a field value of my object in a hidden div. If this value is missing for a special action (because for the most of actions on the object, it's not required), a modal pops asking for updating the given field. This modal is triggered with JS that check the presence (or not) of the required value.
In the modal, I display a list of radio choices buttons in an ordinary form inviting the user to update the field. The form's action leads to a view that will update the given field.
modal.html
<form action="{% url 'update-sku-column' object.pk %}" method="post">
{% csrf_token %}
{% if csv_headers %}
<div class="m-3 ps-3">
{% for header in csv_headers %}
{% for csv_sample in csv_samples %}
{% if forloop.counter0 == forloop.parentloop.counter0 %}
<div class="form-check">
<input class="form-check-input" type="radio" name="chosen-field" value="{{ forloop.counter0 }}">
<label class="form-check-label" for="{{ forloop.counter0 }}">
<span class="ms-3">{{ header }} </span>: <span class="ms-1 text-secondary">{{ csv_sample }}</span>
</label>
</div>
{% endif %}
{% endfor %}
{% endfor %}
</div>
{% endif %}
<div class="modal-footer">
<button type="submit" class="btn btn-success">Enregistrer</button>
</div>
</form>
urls.py
[...]
path('flow/<int:pk>/update-sku-column',
set_sku_column, name='update-sku-column'),
[...]
views.py
#login_required
def set_sku_column(request, pk):
if request.method == 'POST':
column = request.POST['chosen-field']
flow = Flow.objects.get(pk=pk)
flow.fl_ref_index = column
flow.save()
return redirect('mappings-list', pk=pk)
[...]
Even if I can imagine it's not the best way, it works.
don't forget the {% csrf_token %}otherwise it won't

Display form input with Django

So basically I want to make a simple form I can enter text and the after I hit submit, see the text.
Here is my forms.py:
class Search(forms.Form):
search = forms.CharField()
Here is my views.py:
def search(request):
context = RequestContext(request)
if request.method == 'POST':
search = Search(data=request.POST)
if search.is_valid():
ticker = search.save()
ticker.save()
success = True
else:
print search.errors
else:
search = Search()
return render_to_response('ui/search.html', {"search":search}, context)
Here is the html form that you use to type in (I'm using bootstrap for styling purposes):
<form class="navbar-form navbar-right" role="search" action="/search/" method="post" name="tick">
{% csrf_token %}
<div class="form-group">
<input type="text" class="form-control" placeholder="Enter stock symbol">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
And finally, I want the text entered in the form to be displayed on "search.html" which looks like this currently:
{% extends 'ui/base.html' %}
{% block title %} search {% endblock %}
{% block body_block %}
<br>
<p>test</p>
{{ form.search.data }} <!--I'm pretty sure this is not correct -->
{% endblock %}
Anyone know how I can do this? Thanks.
Your form name is search.
To render the value with modern django, you need to call the value method of the field, therefore your template should look like the following:
{{ search.search.value }}
Your template is wrong, as you suspect.
It is looking for a context variable named "form", but you have given it a context dictionary with a key named "search".
Also, "data" is the argument that you use to build up your Search object (correctly), but when you want to extract the user's input from it, you should use the field names instead, and you need to call value() on them in order to get the bound value. So, to get the contents of the text field called search, you should use search.search.value.
Try changing the line
{{ form.search.data }}
to
{{ search.search.value }}

Categories