How to delete files in Django? - django

I followed this tutorial: Need a minimal Django file upload example
Obviously it works. But I want to be able to delete a file as well. Now even if I delete it manually from disc, it still appears on list, even after reconnecting to a server (why?)
I changed the list.html file by adding another form in the loop:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Minimal Django File Upload Example</title>
</head>
<body>
<!-- List of uploaded documents -->
{% if documents %}
<ul>
{% for document in documents %}
<li>{{ document.docfile.name }}
{% if user.is_staff %}
<form action="{% url 'delete' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="submit" value="Delete" />
</form>
{% endif %}
</li>
{% endfor %}
</ul>
{% else %}
<p>No documents.</p>
{% endif %}
<!-- Upload form. Note enctype attribute! -->
<form action="{% url 'list' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>{{ form.non_field_errors }}</p>
<p>{{ form.docfile.label_tag }} {{ form.docfile.help_text }}</p>
<p>
{{ form.docfile.errors }}
{{ form.docfile }}
</p>
<p><input type="submit" value="Upload" /></p>
</form>
</body>
</html>
As you can see, I added Delete button in a form. By doing so, I have a button near each file. I added this to my views :
def delete(request):
if request.method != 'POST':
raise HTTP404
else:
docId = request.POST.get('docfile', None)
if docId is not None:
docToDel = Document.objects.get(pk=docId)
docToDel.delete()
form = DocumentForm(request.POST, request.FILES)
documents = Document.objects.all()
return HttpResponseRedirect(reverse('myapp.views.list'))
But that does not do anything, just reloads the page.
As I said, now I cannot even delete them manually.
What am I doing wrong?

First of all file on disk and model in DB are different things. To delete file from disk and DB you may try this
from django.shortcuts import get_object_or_404
def delete(request):
if request.method != 'POST':
raise HTTP404
docId = request.POST.get('docfile', None)
docToDel = get_object_or_404(Document, pk = docId)
docToDel.docfile.delete()
docToDel.delete()
return HttpResponseRedirect(reverse('myapp.views.list'))
Also you forgot to specify ID of Document to delete
<!-- List of uploaded documents -->
{% if documents %}
<ul>
{% for document in documents %}
<li>{{ document.docfile.name }}
{% if user.is_staff %}
<form action="{% url 'delete' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="hidden" name="docfile" value="{{ document.pk }}" />
<input type="submit" value="Delete" />
</form>
{% endif %}
</li>
{% endfor %}
</ul>
{% else %}
<p>No documents.</p>
{% endif %}

Related

Hx-push-url doesn’t work on back button click

I am trying to integrate Htmx with django and achieve single page application behaviour. I am rewritting Djangoproject.com poll app with htmx. When I click on detail page link, content loads, htmx push a new url in address bar. When I press back button, it took me to index page perfectly for the first time, after that if I again go to detail page and click back button, url shows of the index, button index content doesn’t load, content remains same as detail page.
Here is my code
views.py
def index(request):
latest_question_list = Question.objects.filter(pub_date__lte=timezone.now()).order_by('-pub_date')[:5]
context = {'latest_question_list': latest_question_list}
if request.headers.get("Hx-Request") is not None:
return render(request, 'main/index/index.html', context)
else:
return render(request, 'main/index/index-full.html', context)
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
print(request.headers.get("Hx-Request"))
if request.headers.get("Hx-Request") is not None:
return render(request, 'main/detail/detail.html', {'question': question})
else:
return render(request, 'main/detail/detail-full.html', {'question': question})
index.html
<div id="index" class="">
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><div class="has-text-link" hx-get="{% url 'main:detail' question.id %}" hx-push-url="true" hx-target="#index" hx-swap="outerHTML">{{ question.question_text }}</div></li>
{% endfor %}
</ul>
{% else %}
<p>
No polls are available.
</p>
{% endif %}
</div>
index-full.html
{% extends 'base.html' %}
{% block content %}
{% include 'main/index/index.html' %}
{% endblock content %}
detail.html
<div id="detail" class="">
<form action="{% url 'main:vote' question.id %}" method="post">
{% csrf_token %}
<fieldset>
<legend><h1>{{ question.question_text }}</h1></legend>
{% if error_message %}<p>
<strong>{{ error_message }}</strong>
</p>
{% endif %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
{% endfor %}
</fieldset>
<input type="submit" value="Vote">
</form>
</div>
detail-full.html
{% extends 'base.html' %}
{% block content %}
{% include 'main/detail/detail.html %}
{% endblock content %}
I found no error in browser console, no error in terminal
Now, I know I can put a back button in detail page that can took me to index page. But user won't use that, they will just use the back button on their device.
Adding this javascript code you can reload the page when the user click the back button:
var auxBack = performance.getEntriesByType("navigation");
if (auxBack[0].type === "back_forward") {
location.reload(true);
}

My form does not save using bootstrap for styling in django

hello thank you for your visiting
I'm a new learner of Django
I would like to know how to style form using django-bootstrap-v5
i try this and does not work
i have this form.py
pathesForm = inlineformset_factory(
Book,
quotation,
fields=('name','time',),
can_delete=False,extra=4,max_num=4,
widgets={'name': forms.TextInput(attrs={
'placeholder': 'name of book',
})
}
)
i use django-bootstrap-v5 and in file html
this form is not working with me
<form role="form" class="form-horizontal" method="post">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
<div class="row">
<div class="col-md-6">
{% bootstrap_field form.name %}
</div>
<div class="col-md-6">
{% bootstrap_field form.time %}
</div>
</div>
{% if form.maybemissing %}
{% bootstrap_field form.maybemissing %}
{% endif %}
{% endfor %}
<button type="submit">Save</button>
</form>
but this is working with me (i can save the form)
{% bootstrap_formset_errors formset %}
<form role="form" class="form-horizontal" method="post">
{% csrf_token %}
{% bootstrap_formset formset %}
<button type="submit">Save</button>
</form>
this is my view.py
def hello(request,id):
book=Book.objects.get(id=id)
if request.method == 'POST':
form= pathesForm(request.POST,request.FILES,instance=book)
if form.is_valid():
form.save()
form = pathesForm(instance=book )
return render(request,'hello/pathesForm.html',{'formset':form})
i use print('hello) to try know where is the problem and the result seems like the form is not valid
how i can to customize the style of my form like the first one
in your views you forgot to pass then else statement so here it is
def hello(request,id):
book=Book.objects.get(id=id)
if request.method == 'POST':
form= pathesForm(request.POST,request.FILES,instance=book)
if form.is_valid():
form.save()
else:
form = pathesForm(instance=book)
return render(request,'hello/pathesForm.html',{'formset':form})
and in your html while requsting the file field
you have to give form a encryptio type here it is
<form role="form" class="form-horizontal" method="POST" enctype="multipart/form-data">
this has to solve your problem and tell me if you still getting any error have a good day
allways if you have a problem with from use print(form.errors) before the form is valid and after it
i got my problem and i got this error [{'id': ['This field is required.']}
soulition:
<form role="form" method="post">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
<div class="row">
<div class="col-md-6">
{% bootstrap_field form.name %}
</div>
</div>
{% if form.maybemissing %}
{% bootstrap_field form.maybemissing %}
{% endif %}
{% endfor %}
i think it success using formset only because of ( id add automatically )
and if you want to forloop you should be add it manually

Html code for showing multiple forms on one page

Below is the view
def TestPageView(request):
if request.method == 'POST':
contactform = ContactForm(request.POST,prefix="contact")
subscriptionform = SubscriptionForm(request.POST,prefix="subscription")
suggestionform = SuggestionForm(request.POST,prefix="suggestion")
globalmessageform = GlobalMessageForm(request.POST,prefix="globalmessage")
if contactform.is_valid() and subscriptionform.is_valid() and suggestionform.is_valid() and globalmessageform.is_valid():
contact = contactform.save()
subscription = subscriptionform.save()
suggestion = suggestionform.save()
globalmessage = globalmessageform.save()
else:
print(form.errors)
else:
contactform = ContactForm(prefix="contact")
subscriptionform = SubscriptionForm(prefix="subscription")
suggestionform = SuggestionForm(prefix="suggestion")
globalmessageform = GlobalMessageForm(prefix="globalmessage")
return render(request,'dashboard/test_page.html',{'contactform':contactform,'subscriptionform':subscriptionform,'suggestionform':suggestionform,'globalmessageform':globalmessageform})
How to write html code to show and save these forms on test_page.html.I know how to show one form but there are 4 forms in this case.
I have coded like this but i cannot see any output on test_page.html. Page is completely blank.
{% extends "base.html" %}
{% block content %}
{% load static %}
<div>
<div>
<form method="post" >
{% csrf_token %}
{{ contactform.as_p }}
</form>
</div>
<div>
<form method="post" >
{% csrf_token %}
{{ subscriptionform.as_p }}
</form>
</div>
<div>
<form method="post" >
{% csrf_token %}
{{ suggestionform.as_p }}
</form>
</div>
<div>
<form method="post" >
{% csrf_token %}
{{ globalmessageform.as_p }}
</form>
</div>
<input type="submit" name="Save">
</div>
{% endblock %}

Why forms.ModelForm loss data from FileField in Django 2.0

I have a CustomForm that extends from forms.ModelForm and use a FileField like this:
avatar = forms.FileField(required=False, label="avatar")
When I save the model, everything works, and file was saved in directory. But when I re-enter in view (file is over there), and just click in "Save", the file is lost. My views.py is:
def edit_user(request):
if request.method == "POST":
form = CustomForm(request.POST, request.FILES)
if form.is_valid():
user = form.save(commit=False)
user.save()
else:
user= User\
.objects\
.get_or_create(user=request.user,
defaults={'name':request.user.first_name,
'email':request.user.email})
form = CustomForm(instance=user)
return render(request, 'user.html', {'form':form, 'user':user})
I'm using Python 3.6 and Django 2.0.
HTML:
<form method="post" action="{% url 'myprofile' %}"
class="form-horizontal" role="form"
enctype="multipart/form-data">
{% csrf_token %}
{% for field in form %}
<div class="form-group row">
<label class="col-2 col-form-label">{{ field.label_tag }}</label>
<div class="col-10">
{% render_field field class+="form-control" %}
{% if field.errors %}
<br/>
{% for error in field.errors %}
<div class="alert alert-danger alert-dismissable">
<p><strong>{{ error|escape }}</strong></p>
</div>
{% endfor %}
{% endif %}
</div>
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
<input type="submit" value="{% trans 'save' %}" >
</form>

modal form embedded in html does not work in django

I'm making an application for food recipes and am trying to do the same html in the recipe and include comments in a modal window, the problem is that when I give I submit template fails and does not save the comment on the data base
urls.py
urlpatterns = patterns('recetas.apps.menus.views',
url(r'^recetas/$','recetas_view',name='vista_recetas'),
url(r'^reporte/$','reporte_receta',name='receta_reporte'),
url(r'^receta/(?P<id_receta>\d+)$','detalle_receta', name='vista_detalle'),
)
The html code that calls this url
<td><a href='/receta/{{ receta.id }}'>{{ receta.titulo }}</a></td>
views.py
def detalle_receta(request, id_receta):
dato = get_object_or_404(Receta, pk=id_receta)
comentarios = Comentario.objects.filter(receta=dato)
if request.POST:
if request.POST.get('cancel', id_receta):
return HttpResponseRedirect('/receta/{0}'.format(id_receta))
form = ComentarioForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/receta/{0}'.format(id_receta))
else:
form = ComentarioForm(initial={'receta': id_receta})
cxt = {'receta':dato,'comentarios':comentarios,'form':form}
return render_to_response('menus/receta.html', cxt, context_instance=RequestContext(request))
receta.html
{% extends 'base.html' %}
{% block titulo %}{{ receta.titulo }}{% endblock titulo %}
{% block estatico %}
<link rel='stylesheet' href='{{ STATIC_URL }}css/receta.css' type='text/css'>
<link rel='stylesheet' href='{{ STATIC_URL }}css/modal.css' type='text/css'>
<script type='text/javascript'>
function despliegaModal(valor) {
var elem = document.getElementById("bgVentanaModal");
elem.style.visibility = valor;
}
</script>
{% endblock estatico %}
{% block contenido %}
<div id="bgVentanaModal">
<div id="ventanaModal">
<form action="/receta/{{ receta.id_receta }}" method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Grabar">
<input name="cancel" type="submit" value="Cancelar">
</form>
</div>
</div>
<div id=receta>
<div id="nombre_receta">
<h1>{{receta.titulo|title}}</h1>
<hr>
</div>
<div id='ingredientes'>
<h2>Ingredientes</h2>
<p>{{ receta.ingredientes }}</p>
</div>
<div id='imagen'>
<img src='{{MEDIA_URL}}{{receta.imagen}}' width="480" height="300" >
</div>
<div id='preparacion'>
<h2>Preparación</h2>
<p>{{ receta.preparacion }}</p>
</div>
<div id='comentarios'>
<h2>Comentarios</h2>
{% for item in comentarios %}
<p>{{ item.texto}}</p>
{% empty %}
<p>Sin Comentarios registrados</p>
{% endfor %}
{% if user.is_authenticated %}
Agregue su comentario
{% endif %}
</div>
<div id="pie">
<hr>
<p>Receta Registrada el {{ receta.tiempo_registro|date:'SHORT_DATETIME_FORMAT' }} por {{ receta.usuario }}</p>
</div>
</div>
{% endblock contenido %}
everything works until I give the cancel key, does not validate the POST.
I believe the problem is in your view.py. Specifically in this part:
if request.POST.get('cancel', id_receta):
return HttpResponseRedirect('/receta/{0}'.format(id_receta))
That if will never result in a False value and, hence, your comment will never be saved. This has to do with how the dict.get function works:
get(key[, default])
Return the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError.
So, if you click Grabar you'll get the default value (id_receta). Try the following instead:
if request.POST.get('cancel'): # Default to None
return HttpResponseRedirect('/receta/{0}'.format(id_receta))
A workaround would be just using a button with some JavaScript to redirect when you click Cancelar in your template:
views.py
def detalle_receta(request, id_receta):
dato = get_object_or_404(Receta, pk=id_receta)
comentarios = Comentario.objects.filter(receta=dato)
if request.POST:
# if request.POST.get('cancel', id_receta):
# return HttpResponseRedirect('/receta/{0}'.format(id_receta))
form = ComentarioForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/receta/{0}'.format(id_receta))
else:
form = ComentarioForm(initial={'receta': id_receta})
cxt = {'receta':dato,'comentarios':comentarios,'form':form}
return render_to_response('menus/receta.html', cxt, context_instance=RequestContext(request))
receta.html
...
...
<form action="/receta/{{ receta.id_receta }}" method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Grabar">
<input type="button" value="Cancelar" onclick="window.location.href='/receta/{{ dato.id }}'"/>>
</form>
...
...
Of course, you should use get_absolute_url instead of hardcoding URLs.
Thanks for help me Cesar, your answer help me, but my error is in the variable in receta.html
is {{ receta.id }} and in the button is the same the correct is
<form action="/receta/{{ receta.id }}" method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Grabar"/>
<input type="button" value="Cancelar" onclick="window.location.href='/receta/{{ receta.id }}'"/>
</form>
Thanks for your help and a friend who found the error