Django image dosen't show when searching? - python

I have an inventory app with products and its name, photo.
I query the records in HTML page and all works fine and the images showing.
when i try to search the result come without the photo.
View:
def inventory_search_view(request):
query = request.GET.get('q')
product_search = Inventory.objects.filter(name__icontains = query).values()
print(product_search)
context = {'object_list': product_search}
return render(request, 'inventory_search.html', context = context)
HTML:
{%for object in object_list %}
<div class="product-image">
<img src="{{object.image}}" alt="{{object.name}}" />
<div class="info">
<h2> Description</h2>
<ul>
{{object.description}}
</ul>
</div>
</div>
</div>
{%endfor%}
search form:
<form action="search/">
<input type="text" name="q">
<input type="submit" value="Search">
</form>
Thanks in advance.

Why are you using .values()? Why not pass the queryset to the page?
In the page you should also do object.image.url I believe.
def inventory_search_view(request):
query = request.GET.get('q')
product_search = Inventory.objects.filter(name__icontains=query)
print(product_search)
context = {'object_list': product_search}
return render(request, 'inventory_search.html', context=context)
And in your template:
{%for object in object_list %}
<div class="product-image">
<img src="{{object.image.url}}" alt="{{object.name}}" />
<div class="info">
<h2> Description</h2>
<ul>
<li>{{object.description}}</li>
</ul>
</div>
</div>
{% comment %} </div> This shouldn't be here, or you're missing some code in your question {% endcomment %}
{% endfor %}

Related

improperly configured at /18/delete, Django views issue

I have searched through the other questions similar to my own problem and have come to no solution so im hoping someone can help me figure out where i went wrong.
I'm trying to implement a delete post option in my blog program but it is throwing the following error once you click the 'delete' button:
ImproperlyConfigured at /18/delete/
Deletepost is missing a QuerySet. Define Deletepost.model, Deletepost.queryset, or override Deletepost.get_queryset().
I am nearly sure its a problem with my URLS.py though what exactly i cannot figure out.
the following is the code in question:
Views.py
# delete post
class Deletepost(LoginRequiredMixin, DeleteView):
form_class = Post
success_url = reverse_lazy('blog:home')
template_name = 'templates/post.html'
def test_func(self):
post = self.get_object()
if self.request.user == post.author:
return True
return False
urls.py
urlpatterns = [
# home
path('', views.postslist.as_view(), name='home'),
# add post
path('blog_post/', views.PostCreateView.as_view(), name='blog_post'),
# posts/comments
path('<slug:slug>/', views.postdetail.as_view(), name='post_detail'),
# edit post
path('<slug:slug>/edit/', views.Editpost.as_view(), name='edit_post'),
# delete post
path('<int:pk>/delete/', views.Deletepost.as_view(), name='delete_post'),
# likes
path('like/<slug:slug>', views.PostLike.as_view(), name='post_like'),
]
post.html
{% extends 'base.html' %} {% block content %}
{% load crispy_forms_tags %}
<div class="masthead">
<div class="container">
<div class="row g-0">
<div class="col-md-6 masthead-text">
<!-- Post title goes in these h1 tags -->
<h1 class="post-title text-success">{{ post.title }}</h1>
<!-- Post author goes before the | the post's created date goes after -->
<p class="post-subtitle text-success">{{ post.author }} | {{ post.created_on }}</p>
</div>
<div class="d-none d-md-block col-md-6 masthead-image">
<!-- The featured image URL goes in the src attribute -->
{% if "placeholder" in post.featured_image.url %}
<img src="https://codeinstitute.s3.amazonaws.com/fullstack/blog/default.jpg" width="100%">
{% else %}
<img src=" {{ post.featured_image.url }}" width="100%">
{% endif %}
</div>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col card mb-4 mt-3 left top">
<div class="card-body text-dark">
<!-- The post content goes inside the card-text. -->
<!-- Use the | safe filter inside the template tags -->
<p class="card-text text-dark">
{{ post.content | safe }}
</p>
<div class="row">
<div class="col-1">
<strong>
{% if user.is_authenticated %}
<form class="d-inline" action="{% url 'post_like' post.slug %}" method="POST">
{% csrf_token %}
{% if liked %}
<button type="submit" name="blogpost_id" value="{{post.slug}}" class="btn-like"><i class="fas fa-heart"></i></button>
{% else %}
<button type="submit" name="blogpost_id" value="{{post.slug}}" class="btn-like"><i class="far fa-heart"></i></button>
{% endif %}
</form>
{% else %}
<span class="text-secondary"><i class="far fa-heart"></i></span>
{% endif %}
<!-- The number of likes goes before the closing strong tag -->
<span class="text-secondary">{{ post.number_of_likes }} </span>
</strong>
</div>
<div class="col-1">
{% with comments.count as total_comments %}
<strong class="text-dark"><i class="far fa-comments"></i>
<!-- Our total_comments variable goes before the closing strong tag -->
{{ total_comments }}</strong>
{% endwith %}
</div>
<div class="col-1">
<a class="btn btn-outline-danger" href="{% url 'delete_post' post.id %}">Delete It</a>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col">
<hr>
</div>
</div>
<div class="row">
<div class="col-md-8 card mb-4 mt-3 ">
<h3 class="text-dark">Comments:</h3>
<div class="card-body">
<!-- We want a for loop inside the empty control tags to iterate through each comment in comments -->
{% for comment in comments %}
<div class="comments text-dark" style="padding: 10px;">
<p class="font-weight-bold">
<!-- The commenter's name goes here. Check the model if you're not sure what that is -->
{{ comment.name }}
<span class=" text-muted font-weight-normal">
<!-- The comment's created date goes here -->
{{ comment.created_on }}
</span> wrote:
</p>
<!-- The body of the comment goes before the | -->
{{ comment.body | linebreaks }}
</div>
<!-- Our for loop ends here -->
{% endfor %}
</div>
</div>
<div class="col-md-4 card mb-4 mt-3 ">
<div class="card-body">
<!-- For later -->
{% if commented %}
<div class="alert alert-success" role="alert">
Your comment is awaiting approval
</div>
{% else %}
{% if user.is_authenticated %}
<h3 class="text-dark">Leave a comment:</h3>
<p class="text-dark">Posting as: {{ user.username }}</p>
<form class="text-dark" method="post" style="margin-top: 1.3em;">
{{ comment_form | crispy }}
{% csrf_token %}
<button type="submit" class="btn btn-signup btn-lg">Submit</button>
</form>
{% endif %}
{% endif %}
</div>
</div>
</div>
</div>
{% endblock content %}
Any ideas?
I think it should be model not form_class so:
class Deletepost(LoginRequiredMixin, DeleteView):
model = Post
success_url = reverse_lazy('blog:home')
template_name = 'templates/post.html'
def test_func(self):
post = self.get_object()
if self.request.user == post.author:
return True
return False
#SunderamDubey's answer is correct. The test_func will however not run, since this is method of the UserPassesTestMixin [Django-doc], not LoginRequiredMixin.
But using a test function as is done here is not efficient: it will fetch the same object twice from the database. You can simply restrict the queryset, like:
from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse_lazy
from django.views.generic import DeleteView
class DeletePostView(LoginRequiredMixin, DeleteView):
model = Post
success_url = reverse_lazy('blog:home')
template_name = 'templates/post.html'
def get_queryset(self, *args, **kwargs):
return (
super().get_queryset(*args, **kwargs).filter(author=self.request.user)
)
This will do filtering at the database side, and thus return a 404 in case the logged in user is not the author of the Post object you want to delete.
In the template, you will need to make a mini-form to make a POST request, for example:
<form method="post" action="{% url 'delete_post' post.id %}">
{% csrf_token %}
<button class="btn btn-outline-danger" type="submit">Delete</button>
</form>
In my opinion, you should change url to below
'path('delete/int:pk', views.Deletepost.as_view(), name='delete_post'),'
if didn't work you can do this
def delete_post(request, post_id):
post = Post.objects.get(pk=post_id)
post.delete()
return redirect('blog:home')

Django - Updating value only for the last item of list

This is how my ToDoapp looks like
The date change works only for the last item in the list but for other items it throws the error:
ValidationError at /
['“” value has an invalid date format. It must be in YYYY-MM-DD format.']
I see that irrespective of "Update" button I press, it passes only the last item's id and date.
Find my code below:
Index.html
{% extends 'base.html' %}
{% block content %}
<h3 style = "margin-bottom: 20px"><strong>To Do List App</strong></h3>
<form method="POST">
{%csrf_token%}
<ul class="list-group">
{% for task in tasklist %}
<li class="list-group-item d-flex justify-content-between align-items-center">
<input type='hidden' name = 'task_id' value='{{task.id}}'>{{task.tasks}}
<span class="badge bg-primary rounded-pill">{{task.duedate}}
<input type="date" name="datepick" />
<input type='submit' value ='Update'>
</span>
</li>
{% endfor %}
</form>
Views.py
def index(request):
if request.method == "POST":
task_id = request.POST.get('task_id')
task=Task.objects.get(id=task_id)
datepick = request.POST.get('datepick')
task.duedate = datepick
task.save()
tasklist = Task.objects.all()
return render(request, 'index.html', {'tasklist':tasklist})
Models.py
class Task(models.Model):
tasks = models.CharField(max_length=200)
duedate = models.DateField(blank=True)
I feel that mistake is in the HTML file and I'm not familiar with HTML.
Each task on the list should have its own form.
{% extends 'base.html' %}
{% block content %}
<h3 style = "margin-bottom: 20px"><strong>To Do List App</strong></h3>
<ul class="list-group">
{% for task in tasklist %}
<li class="list-group-item d-flex justify-content-between align-items-center">
<form method="POST">
{%csrf_token%}
<input type='hidden' name = 'task_id' value='{{task.id}}'>{{task.tasks}}
<span class="badge bg-primary rounded-pill">{{task.duedate}}
<input type="date" name="datepick" />
<input type='submit' value ='Update'>
</span>
</form>
</li>
{% endfor %}
</ul>
Each row shall be in an independent form as currently the form has 3 elements with the same name
You should provide a unique name for each element in a form. As it is inside an iterator you can use {{ forloop.counter }} as name.
The link below would be helpful:
Django - iterate number in for loop of a template

Search bar no content is returned

Hey i am new to Django and I am trying to make a search bar to my first site.
My problem here is when I search for any value that I/user entered and on the site, the site only refreshes and doesn't give me anything back but the empty option that i gave the site to display when there is no content to match the search.
(That's not all of the Topic model)
model.py
class Topic(models.Model):
content = models.CharField(max_length=200)
views.py
def search(request):
query = request.GET.get('q')
if query:
result = Topic.objects.filter(content__icontains=query)
context = { 'query': query, 'result': result}
return render(request, 'learning_logs/topics.html', context)
(that's all of the topics.html i am sorry of how it turned this not what it really looks like on the original topics.html but that's the full topics.html )
topics.html
% extends "leaning_logs\base.html" %}
{% block page_header %}
<h1>Topics </h1>
<br>Add a new topic</br>
{% endblock page_header %}
{% block content %}
<form method="GET" action="{% url 'learning_logs:search' %}">
{% csrf_token %}
<input name="q" value="{{ request.GET.q }}" placeholder="search..">
<button class="btn btn-success" type="submit">
Search</button>
</form>
{% for topic in topics %}
<div class="card-mb3">
<div class="card-header" style="background-color:lightgrey">
<table class="table">
<tr>
<th>Image</th>
<th>Title of the topic</th>
<th>Edit</th>
<th>Delete</th>
</tr>
<div class="card-body" style="background- color:white">
<tr>
<td>
{% if topic.image %}
<image src="{{topic.image.url}}" style="width:200px">
{% else %}
<span class="text-muted">No Image have been added</span>
{% endif %}
<td><h3>
{{topic}}
</td></h3>
<td><small><a href="{% url 'learning_logs:edit_topic' topic.id %}">
<button method="submit" class="btn btn-primary">
Edit topic</button></a></small></td>
<td><small><form method="post" action="{% url 'learning_logs:delete_topic' topic.id %}">
<button type="submit" class="btn btn-danger btn-primary" >
Delete topic</button></form></small></td>
</tr>
</div>
</div>
</div>
{% empty %}
<h3><li>No topics have been added yet.</li></h3>
{% endfor %}
{% endblock content %}
This:
{% for topic in topics %}
should be that:
{% for topic in result %}

linking search results to a its own detail page

This is a django related question:
I am doing an assignment where we are playing around making a search bar then afterwards letting each individual search result linked to its own page with more details. In this context we are doing a job search engine and I need assistance in when you click each jobs posting, it takes you to a separate page with more info about the job. We already made templates for all the pages. I understand that we have to make a request to the api again after doing it for the view function in the search bar and also use templating got fill up out the detailed search results.Im just not sure how would I apply these concepts to the html file that w ehave.
here's the code
View function code
import requests
from django.shortcuts import render
def home(request):
context = {
'example_context_variable': 'Change me.',
}
return render(request, 'pages/home.html', context)
def search_results(request):
search_query = request.GET['searchterm']
context = {
'result_count': 0,
'search_term': search_query,
}
context['results_count'] = 0
url = 'https://jobs.github.com/positions.json?location=bay+area&description='
url += search_query
response = requests.get(url)
results_data = response.json()
job_list =[]
for result in results_data:
job_list.append(result)
context['job_results'] = job_list
return render(request, 'pages/search_results.html', context)
Search Results Page
{% extends "base.html" %}
{% block title %}
Search Results
{% endblock title %}
{% block additional_styles %}
<style>
body {
background-color: white;
}
</style>
{% endblock %}
{% block content %}
<div id="home-content" class="container">
<div class="row">
<div class="col-lg-3"></div> <!-- Column for spacing -->
<div class="col-lg-6">
<div class="mt-5 mb-3 text-center">
<h1>Search Results</h1>
</div>
<form method="GET" action="/search-results/">
<div class="input-group mb-2">
<input name="searchterm" type="text" class="form-control form-control-lg" placeholder="Let's find a job..." />
<div class="input-group-append">
<button class="btn btn-primary btn-lg">Search</button></a>
</div>
</div>
</form>
<!-- 2start -->
<p>You Searched for: {{search_term}}</p>
{% for job in job_results %}
<div class="list-group">
<a href="/detailed-search-results/" class="list-group-item list-group-item-action flex-column align-items-start">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">{{job.title}}</h5>
</div>
<div>
<small class="text-muted">{{job.location}}</small>
</div>
</a>
</div>
<br>
{% endfor %}
<!-- End -->
{% endblock content %}
**detailed Search Results Html file **
So far when you click on a posting it takes you to the detailed search result page without anything on it.
That is because you have hyperlinked each job posting to /detailed-search-results/.
Looking at the API response, you need to change it to job.url
Replace your for loop with this:
{% for job in job_results %}
<div class="list-group">
<a href="{{ job.url }}" class="list-group-item list-group-item-action flex-column align-items-start">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">{{job.title}}</h5>
</div>
<div>
<small class="text-muted">{{job.location}}</small>
</div>
</a>
</div>
<br>
{% endfor %}

i am getting an error saying category matching query does not exist

The voting proceess is working fine with this code. The problem is only when redirecting after voting the options.
Exception Type:DoesNotExist
Exception Value:
Category matching query does not exist.
category = Category.objects.get(slug=slug)
urls.py
path('<slug>/',views.options,name='options'),
path('<slug>/vote/', views.vote, name='vote'),
views.py
def home(request):
categories = Category.objects.filter(active=True)
return render(request,'rank/base.html',{'categories': categories,'title':'TheRanker'})
def options(request,slug):
category = Category.objects.get(slug=slug)
options = Option.objects.filter(category=category)
return render(request,'rank/options.html',{'options':options,'title':'options'})
def vote(request,slug):
option = Option.objects.get(slug=slug)
if Vote.objects.filter(slug=slug,voter_id=request.user.id).exists():
messages.error(request,'You Already Voted!')
return redirect('rank:options',slug)
else:
option.votes += 1
option.save()
voter = Vote(voter=request.user,option=option)
voter.save()
messages.success(request,'Voted!')
return redirect('rank:options',slug)
options.html
{% extends "rank/base.html" %}
<title>{% block title %}{{title}}{% endblock title%}</title>
{% load bootstrap4 %}
{% block content %}
<center><br>
<center>{% bootstrap_messages %}</center>
<ol type="1">
{% for option in options %}
<div class="col-lg-6 col-md-6 mb-6">
<div class="card h-100">
<div class="card-body">
<b><li>
<img src="/media/{{option.image}}" width="200" height="100">
<h4>{{option.name}}
</h4>
<h5 class="card-text">{{ option.details}}</h5>
<h5>{{ option.votes }} votes</h5>
<form action="{% url 'rank:vote' option.slug %}" method="post">
{% csrf_token %}
<input type="submit" class="btn btn-success" value="Vote" >
</form>
</li></b>
</div>
<div class="card-footer">
<small class="text-muted"></small>
</div>
</div>
</div>
{% endfor %}
</ol>
</center>
{% endblock content%}
You're confusing categories and options. The form sends the slug of the option, but then you redirect to the categories view using the same slug. But those are two different models.

Categories