Uploading/Deleting files from a database in Django - python

I'm trying to figure out a way to delete pictures I've uploaded to a carousel in django. Does anyone have a solution to this? I can't find any online examples that are clear to me. You can assume I have imported everything, and that all models, etc. are correct.
My code is below:
carousel.html:
{% load staticfiles %}
{% load filename %}
<div class="container">
<div class="row">
<div class="col-md-12">
<div id="myCarousel" class="carousel slide" data-ride="carousel">
<div class="carousel-inner" role="listbox">
{% for document in documents %}
<div class="item {% if forloop.first %} active {% endif %}">
<div class="row">
<div class="col">
<li>{{document.docfile.name}}</li>
<img src = "{{STATIC_URL}}img/{{document|filename}}" >
<p align="center"><form style="text-align:center" action="{% url 'webportal:delete' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>{{ form.non_field_errors }}</p>
<p>{{ form.Document.label_tag }} {{ form.docfile.help_text }}</p>
<p>
{{ form.Document.errors }}
{{ form.Document }}
</p>
<p><input type="submit" value="Delete" /></p>
</form></p>
</div>
</div>
</div>
{% endfor %}
</div>
<a class="left carousel-control" href="#myCarousel" role="button" data-slide="prev">
<span class="glyphicon glyphicon-chevron-left"></span>
<span class="sr-only">Previous</span>
</a>
<a class="right carousel-control" href="#myCarousel" role="button" data-slide="next">
<span class="glyphicon glyphicon-chevron-right"></span>
<span class="sr-only">Next</span>
</a>
</div>
<!-- /.carousel -->
</div>
</div>
<form action="{% url 'webportal:carousel' %}" 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>
</div>
Views.py
def delete(request, my_id):
Deleted=get_object_or_404(Document, docfile=my_id)
if request.method=='POST':
form=DeleteForm(request.POST, instance=Deleted)
if form.is_valid():
Deleted.delete()
return HttpResponseRedirect('http://127.0.0.1:8000/alzheimers/')
else:
form=DeleteForm(instance=Deleted)
return render_to_response(
'webportal/index.html',
{'documents': documents, 'form': form,},
context_instance=RequestContext(request)
)
# Redirect to the document list after POST
def carousel(request):
# Handle file upload
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
newdoc = Document(docfile = request.FILES['docfile'])
newdoc.save()
# Redirect to the document list after POST
return HttpResponseRedirect('http://127.0.0.1:8000/alzheimers/')
else:
form = DocumentForm() # A empty, unbound form
# Load documents for the list page
documents = Document.objects.all()
#documents=DocumentForm().
# Render list page with the documents and the form
return render_to_response(
'webportal/index.html',
{'documents': documents, 'form': form,},
context_instance=RequestContext(request)
)

You don't wanna handle too much in one view. You could, but it makes ugly hard to maintain code. Better add a separate view for deleting. With this in your template loop.
<a href='{% url 'delete_document' pk=document.pk %}'>delete</a>
Then add a new url pattern with a pk argument:
url(r'^document/delete/(?P<pk>\d+)/$', "delete_document", name="delete_document"),
And a view like:
def delete_document(request, pk):
try:
Docuent.objects.get(pk=pk).delete()
except Document.DoesNotExist:
pass
return HttpResponseRedirect(...)

Related

Why the html custom form is not working django

I have a contact page with a simple form.
Here is views.py:
def contact_view(request):
if request.method == 'GET':
form = ContactForm()
else:
form = ContactForm(request.POST)
if form.is_valid():
subject = form.cleaned_data['subject']
from_email = form.cleaned_data['from_email']
message = form.cleaned_data['message']
try:
send_mail(subject, message, from_email, settings.ADMIN_EMAILS)
except BadHeaderError:
return HttpResponse('Invalid header found.')
return redirect('success')
return render(request, "base/contact.html", {'form': form})
def success_view(request):
return HttpResponse('Success! Thank you for your message.')
this is contact.html:
{% block content%}
<main class="page contact-page">
<section class="portfolio-block contact">
<div class="container">
<div class="heading">
<h2>Contact me</h2>
</div>
<form method="post">
{% csrf_token %}
<div class="mb-3"><label class="form-label" for="name">Your Name</label><input class="form-control item" type="text" id="name"></div>
<div class="mb-3"><label class="form-label" for="subject">Subject</label><input class="form-control item" type="text" id="subject"></div>
<div class="mb-3"><label class="form-label" for="email">Email</label><input class="form-control item" type="email" id="email"></div>
<div class="mb-3"><label class="form-label" for="message">Message</label><textarea class="form-control item" id="message"></textarea></div>
<div class="mb-3"><button class="btn btn-primary btn-lg d-block w-100" type="submit" value="submit">Submit Form</button></div>
</form>
</div>
</section>
</main>
{% endblock %}
When I use form.as_p it works very well but when I use this template it is not working
it only shows in the terminal that a post request was made.
The html looping syntax of form is following, where we have access to specific field, field.label ,non_field_errors as well as particular field errors.
In your case you can use in this way:
contact.html
{% block content%}
<main class="page contact-page">
<section class="portfolio-block contact">
<div class="container">
<div class="heading">
<h2>Contact me</h2>
</div>
<form method="POST" novalidate>
{% csrf_token %}
{% if form.non_field_errors %}
{% for error in form.non_field_errors %}
<div>
{{error}}
</div>
{% endfor %}
{% endif %}
{% for field in form %}
<p>{{field.label_tag}} {{field}}</p>
<br>
{% for error in field.errors %}
<span>{{error}}</span>
{% endfor %}
{% endfor %}
<input type="submit" value="Save">
</form>
</div>
</section>
</main>
{% endblock %}
You can use it as above it will work perfectly with your existing views, as you said it is working with form.as_p.
If you give only form.as_p, it will render form fields in <p> tag of html, you can see through Ctrl+U of view page source,there we cannot have more control over form.
Your question -- How can i use bootstrap's classes in django's form?
Answer - You can set through widget in your form's fileds. for example:
class MyForm(forms.Form):
name=forms.CharField(widget=forms.TextInput(attrs={'class':'form-control'}))
In the above way, you can set it to every field.

How to link "Searchbar" to Search view Django

I create a post_searchview :
def post_search(request):
form = SearchForm()
query = None
results = []
if 'query' in request.GET:
form = SearchForm(request.GET)
if form.is_valid():
query = form.cleaned_data['query']
search_vector = SearchVector('title', 'body')
search_query = SearchQuery(query)
results = Post.published.annotate(
search=search_vector,
rank=SearchRank(search_vector, search_query),
).filter(search=search_query).order_by('-rank')
context = {'form': form, 'query': query, 'results': results}
return render(request, 'blog/post/search.html', context)
And i want to link that to my base.html where i have located an html code for the searchbar (look in the bottom of the file):
<body>
<nav class="navbar navbar-expand-md navbar-dark bg-dark mb-4">
<a class="navbar-brand" href="{% url 'blog:post_list' %}">
My Blog</a>
<button class="navbar-toggler" type="button" data-toggle="collapse"
data-target="#navbarCollapse" aria-controls="navbarCollapse"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span></button>
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav ml-auto">
<li class="nav-item mr-2">
<input class="form-control" type="text" placeholder="Search" aria-label="Search">
</li>
Also, now i have a search.html file to make the searchs, idk if i should delete it :
{% extends "blog/base.html" %}
{% block title %}Search{% endblock %}
{% block content %}
{% if query %}
<h1>Posts containing "{{ query }}"</h1>
<h3>
{% with results.count as total_results %}
Found {{ total_results }} result{{ total_results|pluralize }}
{% endwith %}
</h3>
{% for post in results %}
<h4>{{ post.title }}</h4>
{{ post.body|safe|truncatewords_html:5 }}
{% empty %}
<p>There are no results for your query.</p>
{% endfor %}
<p>Search again</p>
{% else %}
<h1>Search for posts</h1>
<form method="get">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Search">
</form>
{% endif %}
{% endblock %}
Thanks for reading.
Wrap the <input> in a form tag with the correct action, and make sure the form field has a correct name ("query" in your case), á la
<form method="get" action="{% url "blog:search" %}">
<input name="query" class="form-control" type="text" placeholder="Search" aria-label="Search">
</form>
You do need that template to show the results, don't get rid of it.

Django 2 form in modal

Im tries to open in Django the user edit form in Bootstrap modal. But the form is empty, only the save button is shown. But I don't understand how I can make the connection. If I call the edit page directly, then I can edit the user
127.0.0.1:8000/account/edit/
index.html, includes the referral to the form
{% extends 'base.html' %}
{% block head %}
{% endblock %}
{% block body %}
<div class="container-fluid">
<div class="row">
<div class="col-sm-12 col-md-6">
<div class="panel panel-default">
<div class="panel-body">
{% if error_message %}
<p><strong>{{ error_message }}</strong></p>
{% endif %}
<form action="{% url 'account:edit_profile' %}">
<input type="submit" value="Edit" />
</form>
<form action="{% url 'account:change_password' %}">
<input type="submit" value="Change Login" />
</form>
<br>
Open Modal
<br>
<div class="control-label col-sm-2">
First name:
</div>
<div class="col-sm-2">
{{ user.first_name }}
</div><br>
<div class="control-label col-sm-2">
Last name:
</div>
<div class="col-sm-2">
{{ user.last_name }}
</div><br>
<div class="control-label col-sm-2">
Email:
</div>
<div class="col-sm-2">
{{ user.email }}
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal fade" id="edit-profile-modal" >
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header" align="center">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
</button>
</div>
<div id="div-forms">
{% include "account/edit_profile.html" with form=form %}
</div>
</div>
</div>
</div>
{% endblock %}
edit_profile.html
{% block head %}
{% endblock %}
{% block body %}
<div class="container-fluid">
<div class="row">
<div class="col-sm-12 col-md-6">
<div class="panel panel-default">
<div class="panel-body">
<h3>Profile</h3>
{% if error_message %}
<p><strong>{{ error_message }}</strong></p>
{% endif %}
<form method="post">
{% csrf_token %}
{{ user_form.as_p }}
<button type="submit">Save</button>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
views.py
def edit_profile(request):
if request.method == 'POST':
user_form = EditUserForm(request.POST, instance=request.user)
if all([user_form.is_valid(), profile_form.is_valid()]):
user_form.save()
return render(request, 'account/index.html')
else:
user_form = EditUserForm(instance=request.user)
args = {'user_form': user_form}
return render(request, 'account/edit_profile.html', args)
urls.py
urlpatterns = [
...
url(r'^edit/$', views.edit_profile, name='edit_profile'),
...
]
forms.py
class EditUserForm(forms.ModelForm):
class Meta:
model = User
fields = (
'email',
'first_name',
'last_name'
)
Im using:
Python 3.6.3
Django 2.0.7
Windows 8.1
Bootstrap 3.3.6
JQuery 1.12.0
I think that variable form doesn't exist and you use in template just user_form not form variable
{% include "account/edit_profile.html" with form=form %}
Try use it:
{% include "account/edit_profile.html" with user_form=user_form %}
Maybe you could try the code I wrote and you can find it at django-bootstrap-modal-forms. You will be able to bind your form to the modal and all of the validation stuff will work out of the box.
You will create a trigger element opening the modal
Your selected form will be appended to the opened modal
On submit the form will be POSTed via AJAX request to form's URL
Unsuccessful POST request will return errors, which will be shown under form fields in modal
Successful POST request will redirects to selected success URL

Create a custom html template using forms in Django

I've been going over the docs and some StackOverflow examples but I'm still having a little trouble. In Django I created a form, the view renders it and I have it displayed as form.as_p in the HTML template. This works perfectly, but I would like to be able to customize my HTML template instead of having it displayed as form.as_p. Any examples on how to do so?
So far I have the following.
View:
#login_required
def register(request):
info = Content.objects.get(id=request.user.id)
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES, instance=info)
if form.is_valid():
info = form.save(commit=False)
info.save()
return HttpResponseRedirect('/portal/register')
else:
form = UploadFileForm(instance=info)
return render(request, 'portal/register.html', {'form': form, 'gallery': info})
Form:
class UploadFileForm(ModelForm):
logo = forms.ImageField(required=False)
image1 = forms.ImageField(required=False)
terms = forms.CharField(required=False)
class Meta:
model = Content
fields = ['user', 'logo', 'image1', 'terms']
Model:
class Content(models.Model):
user = models.ForeignKey(User)
logo = models.ImageField(upload_to=content_file_name, null=True, blank=True)
image1 = models.ImageField(upload_to=content_file_name, null=True, blank=True)
terms = models.CharField(max_length="256", blank=True)
def __unicode__(self):
return self.title
HTML Template:
<form method="POST" action="" enctype="multipart/form-data">
{% csrf_token %}
<div class="col-lg-3 col-md-4 col-xs-6 thumb">
<a class="thumbnail" href="#">
{% if gallery.logo %}
<img class="img-responsive" id="logo" src="/media/{{ gallery.logo }}" alt="">
{% else %}
<img class="img-responsive" id="logo" src="/media/images/placeholder.png" alt="">
{% endif %}
</a>
<input type="file" name="logo" id="logo" multiple>
</div>
<div class="col-lg-3 col-md-4 col-xs-6 thumb">
<a class="thumbnail" href="#">
{% if gallery.image1 %}
<img class="img-responsive" id="image1" src="/media/{{ gallery.image1 }}" alt="">
{% else %}
<img class="img-responsive" id="image1" src="/media/images/placeholder.png" alt="">
{% endif %}
</a>
<input type="file" name="image1" id="image1" multiple>
</div>
<div class="form-group">
<input type="text" name="terms" id="terms" class="form-control input-sm" placeholder="terms" value="{{ gallery.terms }}">
</div>
<input type="submit" value="Submit" />
</form>
Yes you can loop on the form fields by doing the following
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
<label>
{{ field.label_tag }}
</label>
<div>
{{ field }}
</div>
</div>
{% endfor %}
Then you can add class to the div and label tags and style the form fields
You can also use Django Widget Tweaks to add classed to the form fields.
Click here to read in more details
By using widget tweaks you simply find the field in which you want to add the class by doing this
{% load widget_tweaks %}
{{ form.name|add_class:"inputContact volunteer" }}
You can render the fields manually:
We don’t have to let Django unpack the form’s fields; we can do it
manually if we like (allowing us to reorder the fields, for example).
Each field is available as an attribute of the form using {{
form.name_of_field }}, and in a Django template, will be rendered
appropriately.
Example from the documentation:
{{ form.non_field_errors }}
<div class="fieldWrapper">
{{ form.subject.errors }}
<label for="{{ form.subject.id_for_label }}">Email subject:</label>
{{ form.subject }}
</div>
<div class="fieldWrapper">
{{ form.message.errors }}
<label for="{{ form.message.id_for_label }}">Your message:</label>
{{ form.message }}
</div>
As I said in the comments, see also Django Crispy Forms. You can achieve the same without so much markup.

RECaptcha with WTforms won't render

I am using wtforms-recaptcha in order to get the Recaptcha to show.
pip install wtforms-recaptcha
I guided myself on this site to make the installation:
https://pypi.python.org/pypi/wtforms-recaptcha
The problem is that the recaptcha code is being echoed into the form. That is, I see the recaptcha's code on the form and not the recaptcha itself:
<script type="text/javascript" src="https://www.google.com/recaptcha/api/challenge?k=6LeCJvUSAAAAAAvqwJEueVdV0wyNLPtX6KWSTdXp"> </script> <noscript> <iframe src="https://www.google.com/recaptcha/api/noscript?k=6LeCJvUSAAAAAAvqwJEueVdV0wyNLPtX6KWSTdXp" height="300" width="500" frameborder="0"></iframe><br> <textarea name="recaptcha_challenge_field" rows="3" cols="40"> </textarea> <input type="hidden" name="recaptcha_response_field" value="manual_challenge"> </noscript>
Form code on form.py:
from wtforms import PasswordField, StringField, validators, widgets
from wtforms.form import Form
from wtfrecaptcha.fields import RecaptchaField
class ContactForm(Form):
"""Enables the user to provide feedback."""
first_name = StringField('First Name', [
validators.DataRequired()
])
last_name = StringField('Last Name', [
validators.DataRequired()
])
captcha = RecaptchaField('Captcha', [], public_key='6LeCJvUSAAAAAAvqwJEueVdV0wyNLPtX6KWSTdXp', private_key='6LeCJvUSAAAAADcUvYyLv8kt9ARiTAluDGqHBumY', secure=True)
Calling the form from within the HTML:
<form method="post">
{% for field in form %}
<div class="form-group{% if field.errors %} has-error has-feedback{% endif %}">
<div class="row">
<div class="col-xs-12 col-md-4">
{{ field.label(class="control-label") }}
</div>
<div class="col-xs-12 col-md-8">
{{ field(class="form-control") }}
</div>
</div>
{% if field.errors %}
<span class="glyphicon glyphicon-remove form-control-feedback"></span>
{% endif %}
{% for error in field.errors %}
<p class="help-block text-danger">
<span class="glyphicon glyphicon-remove"></span>
{{ error }}
</p>
{% endfor %}
</div>
{% endfor %}
<br>
<button type="submit" class="btn btn-primary">{{ title }}</button>
</form>
Route call code:
#app.route('/contact', methods=['GET', 'POST'])
def contact():
"""Display the contact page."""
form = ContactForm(request.form, captcha={'ip_address': request.remote_addr})
if request.method == 'POST' and form.validate():
return "Thank you for contacting us."
return render_template(
...
)
The issue is that WTForms-RECAPTCH does not return a safe string, but instead returns a unicode string. The underlying issue needs to be fixed here (by returning an instance of wtforms.widgets.core.HTMLString or something else that provides an __html__ method).
To work around the problem for now you should simply mark the field as safe in your template:
<div class="col-xs-12 col-md-8">
{{ field(class="form-control") | safe }}
</div>
Or, alternately, only mark the re-captcha field as safe:
<div class="col-xs-12 col-md-8">
{% if field.short_name == "captcha" %}
{{ field(class="form-control") | safe }}
{% else %}
{{ field(class="form-control") }}
{% endif %}
</div>
There is a PR for this issue and this is fixed as of version 0.3.2

Categories

Resources