Delete object with form in django - django

I'm displaying a table. In every line there should be a delete button which deletes the element from the table.
My problem is, I'm not sure how to pass the id of the element to the view.
html:
{% for post in posts %}
<div>
<h3>Zuletzt ausgewählt:</h3>
<p>published: <b>{{ post.pub_date }}</b>
</p>
<p>
name: <b>{{ post.Name }}</b>
anmeldung: <b>{{ post.get_Anmeldung_display }}</b>
essen: <b>{{ post.get_Essen_display }}</b>
<form action="" method="POST">
{% csrf_token %}
<input class="btn btn-default btn-danger" name="delete" type="submit" value="Löschen"/>
</form>
</p>
<p>
Email: <b>{{ post.Email }}</b>
</p>
</div>
{% endfor %}
views.py
if request.method == 'POST' and 'delete' in request.POST:
Eintrag.objects.filter(pk=id).delete()
return HttpResponseRedirect(request.path)
So I need to pass post.pub_date of every post to the view, how can I accomplish that?

My problem is, I'm not sure how to pass the id of the element to the view.
I can think of two ways to do this. I'll cover them both one by one.
1. Create a separate url route in your app specifically for deleting objects:
('/post/<pk>/delete/', name="delete_post"),
Then point your form's action to this url:
<form action="{% url 'delete_post' post.pk %}" method="POST">
...
Finally, modify your view function to accept the pk argument:
def my_view(request, pk):
...
2. Second method is to just create another field in your form and pass it the pk of the object:
Just create another field in your form.
<form action="" method="POST">
<input type="hidden" value="{{ post.pk }}" name="pk">
...
Then in your view just look at request.POST['pk'] to get the pk of the post.

A non-ajax way which is super easy to implement as it uses the Django generic views is this:
template.html
{% for post in posts %}
<div>
<h3>Zuletzt ausgewählt:</h3>
<p>published: <b>{{ post.pub_date }}</b>
</p>
<p>
name: <b>{{ post.Name }}</b>
anmeldung: <b>{{ post.get_Anmeldung_display }}</b>
essen: <b>{{ post.get_Essen_display }}</b>
<form action="" method="POST">
{% csrf_token %}
<input class="btn btn-default btn-danger" name="delete" type="submit" value="Löschen"/>
</form>
</p>
<p>
Email: <b>{{ post.Email }}</b>
</p>
<a href="/deleteurl/{{ post.pk }}">
Delete this!
</a>
</div>
{% endfor %}
Once the user clicks on the delete link they will be redirected to the delete view and template which will have a URL that looks like this "/deleteurl/1/".
Then your set of views, url, and template for processing the delete could look like this:
views.py
class DeleteMe(generic.DeleteView):
template_name = 'deleteconfirmation.html'
model = YourModel
success_url = '/YourRedirectUrl/'
urls.py
url(r'^deleteurl/(?P<pk>\d+)/$',
views.DeleteMe.as_view(), name='deletemeview'),
deleteconfirmation.html
<form action="" method="post">{% csrf_token %}
<p>Are you sure you want to delete "{{ object }}"?</p>
<input type="submit" value="Confirm" />
</form>
Again, this is without the use of Ajax.
The views and template are taken directly from the Django Docs

Using POST is our priority, but I thought that adding another form will be redundant.
Found solution in django-allauth' email view.
Though it doesn't include confirmation step (as in docs, mentioned by #HoneyNutIchiros or in more details, or via onclick), it can be useful.
They add name (action_remove) to button and check it in the request.POST dict:
# account/email.html
<button type="submit" name="action_primary" >{% trans 'Make Primary' %}</button>
<button type="submit" name="action_send" >{% trans 'Re-send Verification' %}</button>
<button type="submit" name="action_remove" >{% trans 'Remove' %}</button>
...
<button name="action_add" type="submit">{% trans "Add E-mail" %}</button>
# account/views.py
class EmailView(AjaxCapableProcessFormViewMixin, FormView):
...
def post(self, request, *args, **kwargs):
...
if "action_add" in request.POST:
res = super(EmailView, self).post(request, *args, **kwargs)
elif "action_remove" in request.POST:
res = self._action_remove(request)
...
return res

Related

Get an object id from HTML in in request.POST

I have an user with list of tasks that he can add. I want to give him ability to delete those tasks, or mark as done.
The problem is that my solution is working only when user has one task, because of non-unique id's problem
Is there any way to pass the id to html so that it will be easily accesible in views? Thank you!
This is my current code
{% for task in tasks %}
<form id='is_checked' method='POST' action="{% url 'mark_as_done'%}" enctype="multipart/form-data">
{% csrf_token %}
<div class="input-group-text">
<input type="hidden" id="id_checked" value="{{task.id}}" name = "id_checked">
</div>
</form>
<form class="input-group" action="{% url 'delete_task'%}" method='POST' enctype="multipart/form-data">
{% csrf_token %}
<div class="input-group-prepend">
<div class="input-group-text">
<input onChange="document.getElementById('is_checked').submit()" type="checkbox" {% if task.is_done %}checked{% endif %}>
</div>
</div>
<h7 type="text" class="form-control">{{task}}</h7>
<input type="hidden" id="id" value="{{task.id}}" name = "id">
<button type="submit" class="input-group-append btn btn-danger">Delete</button>
</form>
{% endfor %}
And in views:
def delete_task(request):
if request.method == 'POST':
task = Task.objects.get(pk=request.POST['id'])
task.delete()
return redirect('tasks')
#login_required()
def mark_as_done(request):
if request.method == 'POST':
task = Task.objects.get(pk=request.POST['id_checked'])
task.is_done = True
task.save()
return redirect('tasks')```

django multi form and file field

I am currently using several differences forms on a single view. I am able to fill my forms but when I submit one of them, it seems that my form is invalid. I displayed the request.POST (it contains all my information) and my form (it contains my information except files parts.)
Could you explain me how to correct it?
Could it be linked to my models?
(I am using bootstrap 3 through django)
my view :
def view_addfiles(request):
try:
print(request.POST)
except:
{}
if request.method == 'POST' and 'search' in request.POST:
print("recherche")
recherche=searchbar(request.POST, prefix='search')
if recherche.is_valid():
print("recherche")
else :
recherche=searchbar(prefix='search')
if request.method == 'POST' and 'film' in request.POST:
print("film")
addfilm=Addfilms(request.POST,request.FILES, prefix='film')
print(addfilm)
if addfilm.is_valid():
print("film")
return redirect(view_accueil, inscription=3)
else :
print("dfsd")
addfilm=Addfilms(prefix='film')
if request.method == 'POST' and 'serie' in request.POST:
print("serie")
addserie=Addseries(request.POST,request.FILES, prefix='serie')
if addserie.is_valid():
print("serie")
return redirect(view_accueil, inscription=3)
else :
addserie=Addseries(prefix='serie')
return render(request, 'menuAjout.html',locals())
my html :
<form action="{% url "add_files" %}" method="post">
{% csrf_token %}
{{ recherche.as_p }}
<input type="submit" id="validation" name="search"/>
</form>
<div id="films">
{% load bootstrap3 %}
{% bootstrap_css %}
<form action="{% url "add_files" %}" method="post">
{% csrf_token %}
{% bootstrap_form addfilm %}
{% buttons %}
<button type="submit" class="btn btn-primary" id="submitbutton" name="film" value="submit">
{% bootstrap_icon "star" %} Ajouter
</button>
{% endbuttons %}
</form>
</div>
<div id="series">
<form action="{% url "add_files" %}" method="post">
{% csrf_token %}
{% bootstrap_form addserie %}
{% buttons %}
<button type="submit" class="btn btn-primary" id="submitbutton" name="serie">
{% bootstrap_icon "star" %} Ajouter
</button>
{% endbuttons %}
</form>
</div>
my forms :
class Addseries(forms.ModelForm):
class Meta:
model = series
exclude = ('nbTelechargement','datedepot')
class Addfilms(forms.ModelForm):
class Meta:
model = series
exclude = ('nbTelechargement','datedepot')
class searchbar(forms.Form):
motclef=forms.CharField(max_length=15,widget=forms.TextInput(attrs={'placeholder': 'Search...','style':'background :#ededef url("/static/image/search.png") no-repeat;background-size: auto 90%;'}))
categorie=forms.ChoiceField(choices=(('films', 'films'),
('séries', 'séries'),
('jeux', 'jeux'),
('logiciels', 'logiciels'),
('livres', 'livres'),
('musiques', 'musiques')))
I see several things:
It's not a Django issue but a HTML one:
When a user submits a form, he/she submits only form.
Django receives in request.POST only the data sent by one form.
Your forms share the same fields' names.
Addseries.nbTelechargement and Addfilms.nbTelechargement will have the same key in request.POST
I just forgot to add enctype="multipart/form-data" in my form balise.
My request.FILES was empty because of that.
So my form was unvalid because of that.

Django Admin Action Confirmation Page

In my Django project I have an admin action which requires an confirmation page. I oriented it on the delete_selected action, but it does not work. Here is what I have.
part of my admin.py
def my_action(modeladmin, request, queryset):
if request.POST.get('post'):
print "Performing action"
# action code here
return None
else:
return TemplateResponse(request, "admin/my_action_confirmation.html")
admin/my_action_confirmation.html
<form action="" method="post">{% csrf_token %}
<div>
<input type="hidden" name="post" value="yes" />
<input type="hidden" name="action" value="my_action" />
<input type="submit" value="Confirm" />
</div>
</form>
This works almost. I get to the confirmation page but if I click "confirm" I just get back to the original page. The part with the action code is never reached. In fact the my_action function isn't called a second time. So how do I tell django, that the my_action function should be called a second time, once I clicked confirm?
Edit: I was more missing then I thought
The corrected my_action
def my_action(modeladmin, request, queryset):
if request.POST.get('post'):
print "Performing action"
# action code here
return None
else:
request.current_app = modeladmin.admin_site.name
return TemplateResponse(request, "admin/my_action_confirmation.html")
admin/my_action_confirmation.html
{% load l10n %}
<form action="" method="post">{% csrf_token %}
<div>
{% for obj in queryset %}
<input type="hidden" name="{{ action_checkbox_name }}" value="{{ obj.pk|unlocalize }}" />
{% endfor %}
<input type="hidden" name="post" value="yes" />
<input type="hidden" name="action" value="my_action" />
<input type="submit" value="Confirm" />
</div>
</form>
admin.py
def require_confirmation(func):
def wrapper(modeladmin, request, queryset):
if request.POST.get("confirmation") is None:
request.current_app = modeladmin.admin_site.name
context = {"action": request.POST["action"], "queryset": queryset}
return TemplateResponse(request, "admin/action_confirmation.html", context)
return func(modeladmin, request, queryset)
wrapper.__name__ = func.__name__
return wrapper
#require_confirmation
def do_dangerous_action(modeladmin, request, queryset):
return 42/0
admin/action_confirmation.html
{% extends "admin/base_site.html" %}
{% load i18n l10n admin_urls %}
{% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} delete-confirmation
delete-selected-confirmation{% endblock %}
{% block content %}
<p>Are you sure you want to {{ action }}?</p>
<ul style="padding: 0">
{% for object in queryset.all %}
<li style="list-style: none; float: left; margin: 5px">
{{ object }}
</li>
{% endfor %}
</ul>
<hr>
<br>
<form action="" method="post">{% csrf_token %}
<fieldset class="module aligned">
{% for obj in queryset.all %}
<input type="hidden" name="_selected_action" value="{{ obj.pk|unlocalize }}"/>
{% endfor %}
</fieldset>
<div class="submit-row">
<input type="hidden" name="action" value="{{ action }}"/>
<input type="submit" name="confirmation" value="Confirm"/>
<a href="#" onclick="window.history.back(); return false;"
class="button cancel-link">{% trans "No, take me back" %}</a>
</div>
</form>
{% endblock %}
Just in case of anyone wanting to add a confirmation view to something more than an action.
I wanted to make the save of an admin creation view go to a confirmation view. My model was very complex and created a lot of implications for the system. Adding the confirmation view would make sure that the admin was aware of these implications.
The solution would be overriding some _changeform_view method which is called on the creation and the edition.
The full code is here: https://gist.github.com/rsarai/d475c766871f40e52b8b4d1b12dedea2
Here is what worked for me:
Add confirm action method (in admin.py)
from django.template.response import TemplateResponse
def confirm_my_action(modeladmin, request, queryset):
response = TemplateResponse(request,
'admin/confirm_my_action.html',
{'queryset': queryset})
return response
and point to it from your admin model (in admin.py)
class SomeModelAdmin(admin.ModelAdmin):
actions = [confirm_my_action]
Add template, which has a form whose action is pointing to my_action endpoint.
{% extends "admin/base_site.html" %}
{% block content %}
<div id="content" class="colM delete-confirmation">
<form method="post" action="/admin/my_action/">
{% csrf_token %}
<div>
{% for obj in queryset %}
<input type="hidden" name="obj_ids[]" value="{{ obj.pk }}" />
<ul><li>Obj: ">{{obj}}</a></li></ul>
{% endfor %}
</div>
<input type="submit" value="Yes, I'm sure">
No, take me back
</form>
<br class="clear">
<div id="footer"></div>
</div>
{% endblock %}
Add appropriate endpoint (e.g. in urls.py).
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^admin/my_action/', my_action_method),
]

django-ckeditor request dont get changes in form

I have one form called in ajax function, this function return one django form with one ckeditor field.
This field is displayed without problems, but when I make a request, the field value, dont sended in request, but if I make another, in the same form, with the same values, the value is update and is sended in request.
My form field
class EditCommentForm(IdeiaForm):
content = forms.CharField(
max_length=settings.COMMENT_TEXT_LIMIT if hasattr(settings, "COMMENT_TEXT_LIMIT") else 10000,
required=True,
widget=CKEditorWidget(config_name='question')
)
comment_id = forms.IntegerField(required=True)
My html template
<form class="create-comment" data-group-class=".comment-group" data-ajaxform="true" data-toggle="replace" class="create-comment" data-update="#{{ to_update }}" action="{% url 'comment:edit' %}" method="post">{% csrf_token %}
<div class="comment-group create-comment-body{% if form.content.errors %} has-error{% endif %}">
<textarea name="content" class="form-control" placeholder="Deixe seu comentário">{{ instance.content }}</textarea>
<span class="help-block"></span>
</div>
<input name="comment_id" value="{{ instance.id }}" type="hidden"/>
<div class="create-comment-footer">
<input type="submit" value="Editar" class="btn btn-primary">
</div>
</form>

How insert 2 different forms on the same page in Django

I have to insert 2 forms in the same page:
1) Registration form
2) Login form
.
So if I use this in the views.py:
if request.method == 'POST':
form = registrationForm(request.POST)
if form.is_valid():
form.save()
return render_to_response('template.html', {
'form': form,
})
I will get error by submitting one of two forms.
How can I distinguish the 2 forms submitting in the views ?
You can also do like this,
<form method='POST'>
{{form1.as_p}}
<button type="submit" name="btnform1">Save Changes</button>
</form>
<form method='POST'>
{{form2.as_p}}
<button type="submit" name="btnform2">Save Changes</button>
</form>
CODE
if request.method=='POST' and 'btnform1' in request.POST:
do something...
if request.method=='POST' and 'btnform2' in request.POST:
do something...
You can submit two forms on the same page... but the action that each form calls (i.e. the view function that will process each form) should probably be different. That way, you won't have to try and distinguish the forms.
e.g. On your page:
<form id="login_form" action="{% url app.views.login %}" method="post">
...form fields...
</form>
<form id="registration_form" action="{% url app.views.registration %}" method="post">
...form fields...
</form>
And so, in views.py, you'll have a login() view function and a registration() view function that will handle each of those forms.
<form action="Page where u want to post the data" method="post">
<input name="edit" type="submit" value="Edit Client">
<input name="delete" type="submit" value="Delete Client">
</form>
just Give different names to the buttons.
if request.method == "POST" and 'edit' in request.POST:
/ Do /
if request.method == "POST" and 'delete' in request.POST:
/Do /
You can post both forms to same url too:
forms in template are like this:
<form method="post" action="/profile/">
{% for field in firstform %}
<div class="mb10">
<div class="fl desc">{{ field.label_tag }}<br />
<div class="fr">{{ field }}{{ field.errors }}</div>
<div class="clear"></div>
</div>
{% endfor %}
{% for field in secondform %}
<div class="mb10">
<div class="fl desc">{{ field.label_tag }}<br /><</div>
<div class="fr">{{ field }}{{ field.errors }}</div>
<div class="clear"></div>
</div>
{% endfor %}
<a class="submit fr" href="#""><img src="{{ MEDIA_URL }}img/save.png" /></a>
</form>
and just handle them like this in view:
if request.method == 'POST':
firstform = ProfileForm(request.POST, request.FILES, instance=profile)
secondform = UserForm(request.POST, instance=request.user)
and then do stuff with firstform&secondform.
You can have both forms posting to the same URL and have a hidden input with name set to login or registration and sort that out on the server
You can do the Registration and Login POST to different urls so each POST will be handled by corresponding view