Image not updating django - django

In my edit.html I have a form where the user can edit information on a trainee. The user can add many trainees, edit them, delete them etc. Everything works fine there except the image. The imagefield of form appears in a very messy state. Also it does not update when I select a new image. Here is my code. I have cut down my code to make it more readable
models.py
class Trainee(models.Model):
TraineePic = models.ImageField(null=True, blank= True, upload_to="traineeImg/")
Name = models.CharField(max_length=50)
class Meta():
db_table = "Trainee"
forms.py
class TraineeForm(forms.ModelForm):
TraineePic = forms.ImageField(label="Image :", required=False)
Name = forms.CharField(widget=forms.TextInput(attrs={'class':'col-sm-4'}), label='Name :')
class Meta():
model = Trainee
fields = ("Name","TraineePic",)
views.py
class UpdateTrainee(UpdateView):
model = Trainee
template_name = 'MyTestApp/edit.html'
form_class = TraineeForm
success_url = reverse_lazy('show')
edit.html
{% extends "MyTestApp/base.html" %}
{% block body_block %}
{% load static %}
<link rel="stylesheet" href="{% static '/css/bootstrap.min.css'%}" />
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css">
<style>
ul#id_Gender li{
display: inline-block;
}
</style>
<body>
<div class="jumbotron">
<h2> Edit Trainee </h2>
<form method="post" class="form-group" type="multipart/form-data" data-ajax="false">
{%csrf_token%}
{{form.errors}}
<div class="form-group row">
<label class="col-sm-3 col-form-label">{{ form.TraineePic.label }}</label>
{{form.TraineePic}}
</div>
<div class="form-group row">
<label class="col-sm-3 col-form-label">{{ form.Name.label }}</label>
{{ form.Name }}
</div>
<input type="submit" value="Update" class="btn btn-dark">
</form>
</div>
</body>
{% endblock %}
Here is how the form.TraineePic looks like:
I also tried adding FileInput like this TraineePic = forms.ImageField(label="Image :", required=False,widget=forms.FileInput)
But then I don't get any image. Any help would be appreciated.

You must use #request.FILES to get image from frontend to backend and make it successfully save on database.
In views.py
Example:
Trainee_Pic= self.request.FILES.get('TraineePic') # Use request.FILES

I found the solution. Looks like there was a typo in my form in edit.html
I changed my form from
form method="post" class="form-group" type="multipart/form-data">
to
form method="post" class="form-group" enctype="multipart/form-data">
And the image field in the form which looked very bad previously, I put it in a div with style='display: inline-block' so now it looks pretty ok.

Related

Have issues getting data to display on my web application

I am trying to get the "About us" information from my database to my web application but its not displaying, what could be wrong...
here is the code from the database
class About(models.Model):
about_us = models.TextField()
achieve = models.TextField(blank=True)
image_abt = models.ImageField(upload_to="admin_pics", null=True)
class Meta:
verbose_name_plural = "About Us"
def __str__(self):
return self.about_us
and here is the Html code `
{% extends 'jtalks/base.html' %}
{% load static %}
{%block content%}
<section id="about-home">
<h2>About Us</h2>
</section>
<section id="about-container">
{% for about in abouts %}
<div class="about-img">
<img src="{{ about.image_abt.url }}" alt="">
</div>
<div class="about-text">
<h2>Welcome to TechEduca, Enhance your skills with best Online Courses</h2>
<p>{ about.about_us}</p>
<div class="about-fe">
<img src="images/fe1.png" alt="">
<div class="fe-text">
<h5>400+ Courses</h5>
<p>You can start and finish one of these popular courses in under our site</p>
</div>
</div>
<div class="about-fe">
<img src="images/fe2.png" alt="">
<div class="fe-text">
<h5>Lifetime Access</h5>
<p>You can start and finish one of these popular courses in under our site</p>
</div>
</div>
</div>
{% endfor %}
</section>
{% endblock %}
Nothing is displaying in the frontend of the website.
Thanks for sharing the view. You forgot to pass data to your template. To do that you have to create the queryset and pass that into a dictionary like below. Add the context variable to your render method so you can access the data in the template.
def about(request):
about = About.objects.all()
context = {
'abouts': about,
}
return render(request, 'jtalks/about.html', context)
also, in your html code i see { about.about_us}, but you have to use double curly brackets: {{ about.about_us }}

i cant specify a user to access my post in django

its a bit tricky for i tried solving it but cant,i am using class based views with customuser model, i have a blog post with multiple user i want to make it in a way only the main authour of a post should be allowed to delete or update post but i dont seems to know what to do or how to set it,here is my code kindly take a glance and release me from debugging,instead i get what i want wont get nothing and inatead i get something every author has the right to delete each other's post plus this is how i want it to look like when the user view its blog_detail but for non user it should be blank [![enter image description here][1]][1]
views.py
class BlogUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
model = Blog
fields = ['title', 'categories', 'overview', 'thumbnail', 'summary']
def form_valid(self, form):
form.instance.user = Doctor.objects.get(user=self.request.user)
return super().form_valid(form)
def test_func(self):
blog = Doctor.objects.get(user=self.request.user)
if self.request.user == blog.user:
return True
return False
class BlogDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
model = Blog
success_url = reverse_lazy('blog')
def test_func(self):
blog = Doctor.objects.get(user=self.request.user)
if self.request.user == blog.user:
return True
return False
blog_detail.html
{% extends "pages/base.html" %}
{% load static %}
{% block title %}Jazeera Blog{% endblock title %}
{% block meta %} the best medical-service website in Abuja {% endblock meta %}
{% block content %}
<br><p></p>
<section class="ftco-section bg-light" id="blog-section">
<div class="container">
<div class="row justify-content-center mb-5 pb-5">
<div class="col-md-10 heading-section text-center ftco-animate">
<h2 class="mb-4">Gets Every Single Updates Here</h2>
<p>Far far away, behind the word mountains, far from the countries Vokalia and Consonantia</p>
</div>
</div>
<div class="container">
<div class="row justify-content-center mb-5 pb-5">
<div class="col-lg-8 ftco-animate">
<h2 class="text-center">{{ object.title }}</h2>
<div class="meta mb-3 text-center">
<div><h6><span><a href = "">written By {{ object.user }}</span><small class="date"><i class="icon-clock"></i> {{ object.timestamp|timesince }} ago</small><a/></h6>
</div>
</div>
<div><small class="icon-eye text-danger">{{ object.view_count }}</small></div>
<div class="meta mb-3 text-center">
<h5>{% for cat in object.categories.all %}<span class="btn btn-dark">{{ cat }}</span> {% endfor %}</h5>
</div>
<p class="text-center">{{ object.overview }}</p>
{% if object.created_by == user %}
<a class="btn btn-secondary btn-sm mt mb-2" href="{% url 'blog-update' blog.id %}">Update</a>
<a class="btn btn-danger btn-sm mt mb-2" href="{% url 'blog-delete' blog.id %}">Delete</a>
{% endif %}
</div>
</div>
</div>
</div>
</section>
{% endblock content %}
##urls.py
path('blog/', BlogListView.as_view(), name='blog'),
path('blog/<int:pk>/', BlogDetailView.as_view(), name='blog-detail'),
path('blog/<int:pk>/update/', BlogUpdateView.as_view(), name='blog-update'),
path('blog/new/', BlogCreateView.as_view(), name='blog-create'),
path('blog/<int:pk>/delete/', BlogDeleteView.as_view(), name='blog-delete'),
[1]: https://i.stack.imgur.com/aojDX.jpg
You can restrict the set of Blog objects in the queryset to the ones that are written by the request.user:
class BlogDeleteView(LoginRequiredMixin, DeleteView):
model = Blog
success_url = reverse_lazy('blog')
def get_queryset(self, *args, **kwargs):
return super().get_queryset(*args, **kwargs).filter(
user=self.request.user
)
This will return a HTTP 404 error, if a user aims to remove a Blog object post where the post.user is not the logged in user.
In your views (BlogUpdateView and BlogDeleteView), update test_func to become;
def test_func(self):
blog = Doctor.objects.get(pk=self.kwargs.pk)
return self.request.user == blog.user
If you're testing for one condition in multiple views as you just did, it will be better creating a separate class for the test. Say, IsOwnerMixin where you perform the test and then inherit it in the required view(s).
Additionally, you can change {% if object.user == user %} in your blog_detail.html to become {% if user.is_authenticated and object.user == request.user %}
Good luck!

django-jinja href not downloading file

Hey guys I was making a page where people can download my stuff.I made a model of thta and It is succesfull in uploading that but the problem i swhen I click on the download button front end I t doesn,t download that stuff .Instead of that it downloads the copy of the page.
Here,s the models.py
class Upload(models.Model):
image = models.ImageField(upload_to = 'images',)
file = models.FileField(upload_to = 'images/%Y/%M/%d/')
name = models.CharField(max_length = 200)
def __str__(self):
return self.name
Here,s the views.py
def upload(request):
upload = Upload()
return render(request,'app/download.html',{'upload':upload})
Here,s the html file
{% block content %}
<div class="container">
<div class="download">
<p style="text-align: center;">
<img src="{{upload.image}}" alt="Image containing link to you,r success">
</p>
</div>
<h2>Click on the button below</h2>
<button class="btn btn-primary"><a href="{{upload.file.id}}" download>Yeah do it</a></button>
</div>
{% endblock %}
try
{% block content %}
<div class="container">
<div class="download">
<p style="text-align: center;">
<img src="{{upload.image}}" alt="Image containing link to you,r success">
</p>
</div>
<h2>Click on the button below</h2>
Yeah do it
</div>
{% endblock %}
Changes explained:
{{upload.file.url}} will give you the url to your uploaded file.
directly add "btn btn-primary" to your anchor tag. It'll display as button. You don't need seperate <button> tag

Django Crispy Forms - Checkbox not being displayed

I'm trying to add a boolean field on my form and render it with crispy forms tags. And everything is showed except for the checkbox.
My project works with django 2.1, python 3.6 and Bootstrap-4. My version of Django Crispy Forms is: 1.7.2
The field is investment.
Model field not working:
investment = models.BooleanField(default=False, help_text='Want to accept Investments?')
My form:
class CreateProjectForm(forms.ModelForm):
class Meta:
model = Project
fields = ('name', 'short_description', 'category', 'investment')
widgets = {
'name': forms.TextInput(attrs={'placeholder': 'enter the project name here...'}),
'short_description': forms.Textarea(attrs={'rows': '2', 'maxlength': '135', 'class': 'textarea-limited',
'placeholder': 'enter a short description of your project limited to 135 characters'}),
}
def __init__(self, *args, **kwargs):
# first call parent's constructor
super(CreateProjectForm, self).__init__(*args, **kwargs)
# there's a `fields` property now
self.fields['investment'].required = True
self.fields['investment'].widget = forms.CheckboxInput()
self.fields['name'].widget = forms.TextInput(
attrs={'placeholder': 'enter the project name here...'})
self.fields['short_description'].widget = forms.Textarea(
attrs={'rows': '2',
'maxlength': '135',
'class': 'textarea-limited',
'placeholder': 'enter a short description of your project limited to 135 characters'})
# evade all labels and help text to appear when using "as_crispy_tag"
self.helper = FormHelper(self)
self.helper.form_show_labels = False
self.helper._help_text_inline = True
My View:
class ProjectCreateView(SuccessMessageMixin, generic.CreateView):
template_name = 'webplatform/project_create_form.html'
model = Project
form_class = CreateProjectForm
success_message = 'Project created! Now try to add all the details and then publish it!'
def get_success_url(self):
return reverse_lazy('project-edit-general', args=(self.object.id,))
# Set field as current user
def form_valid(self, form):
form.instance.user = self.request.user
form.instance.start_date = timezone.now()
form.instance.history_change_reason = 'Project Created'
return super(ProjectCreateView, self).form_valid(form)
And for the template I tried two methods, but none of them worked:
My template 01:
This is the method I want to use at the end. Displaying each fiend individually so I can make the layout directly on the template.
...
{% load crispy_forms_tags %}
...
<form id="my_form" method="post" enctype="multipart/form-data" novalidate>
{% csrf_token %}
<div class="row">
<div class="col-md-5 col-sm-5">
<h6>Name
<span class="icon-danger">*</span>
</h6>
{{ form.name|as_crispy_field }}
<h6>Categories
<span class="icon-danger">*</span>
</h6>
{{ form.category|as_crispy_field }}
</div>
<div class="col-md-7 col-sm-7">
<h6>Short Description
<span class="icon-danger">*</span>
</h6>
{{ form.short_description|as_crispy_field }}
<h5>
<small>
<span id="textarea-limited-message" class="pull-right">135 characters left</span>
</small>
</h5>
<h6>Investment
<span class="icon-danger">*</span>
</h6>
{{ form.investment|as_crispy_field }}
</div>
</div>
<div class="row buttons-row">
<div class="col-md-4 col-sm-4">
<button type="submit" class="btn btn-outline-primary btn-block btn-round">Create</button>
</div>
</div>
</form>
My template 02:
This one is using directly the {{ form|crispy }} to show all the elements automatically.
...
{% load crispy_forms_tags %}
...
<form id="my_form" method="post" enctype="multipart/form-data" novalidate>
{% csrf_token %}
{{ form|crispy }}
<div class="row buttons-row">
<div class="col-md-4 col-sm-4">
<button type="submit" class="btn btn-outline-primary btn-block btn-round">Create</button>
</div>
</div>
</form>
I checked the rendered HTML and I found where the problem seems to be, but I don't know how to solve it:
Crispy forms create an element adding the corresponding divs and other necessary elements, like for example on the name input:
<div id="div_id_name" class="form-group">
<label for="id_name" class="col-form-label requiredField">Name
<span class="asteriskField">*</span>
</label>
<div class="">
<input type="text" name="name" placeholder="enter the project name here..." class="textinput textInput form-control" required="" id="id_name">
<small id="hint_id_name" class="form-text text-muted">Add a title to your project.</small>
</div>
</div>
But for the checkbox creates the following structure:
<div class="form-group">
<div id="div_id_investment" class="form-check">
<label for="id_investment" class="form-check-label requiredField">
<input type="checkbox" name="investment" class="checkboxinput form-check-input" required="" id="id_investment">
Investment
<span class="asteriskField">*</span>
</label>
<small id="hint_id_investment" class="form-text text-muted">Want to accept Investments?</small>
</div>
</div>
As you can see, the div with the id is inside another div. Well, so if I delete the class of this extra div (form-group) and change the class of the div with id: form-check for form-group, the checkbox appears and is fully functional.
So my idea is try to change the template that crispy forms created for the checkbox, But I don't know how to do that. Also, if there is another better option, I'm open to them.
Try to change self.fields['investment'].required = False, 'cause it seems that because the field is not specified as optional Django ignores it.
Their is an open issue in django-crispy-forms github see : https://github.com/django-crispy-forms/django-crispy-forms/issues/787
According to this the issue is the way bootsrap handle this form element in the last version.
Here is a js hack to make it work :
$(document).ready(function() {
$( ":checkbox" ).each(function( index ) {
$(this).prependTo($("#div_" + $(this).attr('id')))
});
});
I could make a half hack for this by the element I needed by using the following JS:
$(window).on('load',function(){
$('#div_id_investment').addClass('form-group').removeClass('form-check');
});
But this just let the user see and interact with the checkbox, it does not solve that if the field is required and you don't click it, the error message it doesn't appear.
If anyone have an improved JS to make this to all checkboxes and solve the problem with the error message, I'll appreciate it.
note: I'm not marking this as a valid answer for the question because the bug still there and this 'hack' doesn't solve all the problems.

Django: How save partial filled form state

I don't know exactly how to ask this question.
The thing is that I have a main view to create new entries in a model. This model has some 1-many relations, so I added a + button to add new entries of this fields (secondary model) in case they did not exist. When I submit this new data I redirect to the previous page (main view), and if you already filled some fields in the main view, that information is lost.
Can someone suggest me what the best way to deal with this would be?
Thanks in advance!
UPDATE:
'main model view'
class OrganismCreate(LoginRequiredMixin,CreateView):
"""Template: //catalog/templates/catalog/organism_form.html"""
model = Organism
fields = '__all__'
'main model template' (part)
<form action="" method="post">
{% csrf_token %}
<div class="panel-group">
<div class="panel panel-default">
<div class="panel-heading">Add a new entry: </div>
<div class="panel-body">
<hr>
<div class="row">
<div class="form-group col-sm-4 col-md-3">
<div class="form-group col-sm-4 col-md-3">
<label for="id_inst_own">Owner:</label>
{% render_field form.inst_own class="form-control" %}
<i class="fa fa-plus-circle "></i> Add new
</div>
<div class="panel panel-default">
<div class="panel-body">
...........................................
<button type="submit" class="btn btn-primary"> <span class="glyphicon glyphicon-filter"></span> submit </button>
</div>
</div>
</div>
Then the related model view:
def test_f(request):
if request.method == "GET":
Form = InstitutionForm()
render(request, 'catalog/institution_form.html')
if request.method == "POST":
Form = InstitutionForm(request.POST)
if Form.is_valid():
Form.save()
next = request.POST.get('next', '/')
return redirect(next)
pre=request.META.get('HTTP_REFERER')
return render(request, 'catalog/institution_form.html',{"form" : Form, "pre": pre})
And the related model template
{% block content %}
<form action="" method="post">
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<input type="hidden" name="next" value="{{ pre }}">
<input type="submit" class="btn btn-success" value="Submit" />
</form>
{% endblock %}
There are a number of ways to solve this problem. Here's some suggestions. Not an exclusive list:
Save the incomplete model data in the database as as a 'draft' version of the final data. This could be a totally different model or else using the same model (assuming the related fields are nullable) and giving it a 'draft' flag or similar.
Use an inline formset to create the related objects in the same view. Django Extra Views has some useful tools for this (https://github.com/AndrewIngram/django-extra-views).
Using JavaScript, save the unfinished form data to local storage and then recover it when the original form is loaded again.
I have implemented a draft system to do this along the lines of 1. in #ChidG's answer.
In models I have something like
class AbstractThing(models.Model):
field = models.CharField()
class Meta:
abstract = True
class CompleteThing(AbstractThing):
class Meta:
managed = True
db_table = 'complete_thing'
class IncompleteThing(AbstractThing):
fields_to_not_blank = [AbstractThing._meta.get_field(x) for x in []] #if you don't want to change some fields
for f in AbstractThing._meta.fields:
if f not in fields_to_not_blank:
f.blank = True
f.null = True
class Meta:
managed = True
db_table = 'incomplete_thing'
Then you can use model forms and handle the cases in your views.