Django: Exception Value: The 'image' attribute has no file associated with it - python-3.x

Hi everyone I'm trying to create an auction system with Django.
But when I go to the item profile, Django sends me an error:
Exception Value:
The 'image' attribute has no file associated with it.
auction.html
{% extends "base.html" %}
{% block content %}
{% load static %}
<div class="page-header">
<h1>OPEN AUCTIONS</h1>
</div>
<div class="container">
<div class="row">
{% for item in auction %}
<div class="col-sm-4">
<div class="card border-secondary" style="width: 25rem;">
<div class="card-header">
Auction {{item.id}}
</div>
<img src="{{ item.image.url }}" class="card-img-top" width="250" height="180">
<div class="card-body">
<h3 class="card-title" style="text-align:center" >{{ item.object }}</h3>
<p class="card-text">{{item.description}}<br> Price: ${{ item.open_price}}<br>
End: {{ item.close_date }}</p>
<form method="POST">
{% csrf_token %}
<input type="number" name='auct_id' value={{item.id}} readonly>
<button type="submit" class="btn btn-primary btn-sm">Go</button>
</form>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock %}
If I remove item from <img src="{{ item.image.url }}" class="card-img-top" width="250" height="180"> the page work correctly but the image doesn't display. Like this:
view.py
#login_required(login_url="login")
def auction(request):
if request.user.is_superuser:
messages.error(
request, "super user can access to admin/ and new_auction page only"
)
return redirect("new_auction")
auction = Auction.objects.filter(active=True)
for data in auction:
check = check_data(data.close_date)
if check is False:
data.active = False
data.save()
check_winner(
request, data.id
)
check_prof = check_profile(
request
)
if check_prof is True:
return redirect("profile")
auctions_open = Auction.objects.filter(active=True)
if request.method == "POST":
form = request.POST
auct_ids = form["auct_id"]
auct_id = int(auct_ids)
request.session["selected_id"] = auct_id
return redirect("betting")
else:
return render(request, "auction/auction.html", {"auction": auctions_open})
models.py
from django.db import models
from django.contrib.auth.models import User
from datetime import datetime
# Create your models here.
class Auction(models.Model):
object = models.CharField(max_length=50)
description = models.CharField(max_length=256, default="")
image = models.ImageField(upload_to="media/", null=True, blank=True)
open_date = models.DateTimeField(auto_now_add=True)
close_date = models.DateTimeField()
total_bet = models.IntegerField(default=0)
open_price = models.FloatField(
default=0,
)
close_price = models.FloatField(default=0)
winner = models.CharField(max_length=256, default="")
active = models.BooleanField(default=True)
json_details_file = models.TextField(default="")
tx = models.CharField(max_length=256, default="")
def __str__(self):
return self.object
settings.py
MEDIA_ROOT = os.path.join((BASE_DIR), "media")
MEDIA_URL = "/media/"

According to your model field image, you must give different name instead of media to upload_to.
Let's give different name to upload_to:
image = models.ImageField(upload_to="images/", null=True, blank=True) #here added images instead of media
And in your template:
instead of this:
<img src="{{ item.image.url }}" class="card-img-top" width="250" height="180">
Try this way:
<img src="/media/{{ item.image }}" class="card-img-top" width="250" height="180">
And now that images will display.
Note: don't forget to migrate after modifying upload_to="images/"

Related

Show image name inside the image field in Django forms

I have this edit or update form in which I want to display only the image name in the form for a better user experience so that the user could know which image he has uploaded while creating the data.
I am storing the image name in the model as well,but i want to display the image name inside the image field.
forms.py
class MenuCategoryForm(forms.ModelForm):
image = forms.ImageField(allow_empty_file=True, required=False)
class Meta:
model = MenuCategory
fields = ['name', 'description', 'menu_options']
view
def menu_category_update(request, id):
item = MenuCategory.objects.get(id=id)
if request.method == 'POST':
form = MenuCategoryForm(request.POST, request.FILES, instance=item)
if form.is_valid():
if request.FILES['image']:
image = request.FILES['image']
image_url = upload_image(image, 'menu_category', image.name)
obj = form.save(commit=False)
obj.image_url = image_url
form.save()
else:
form.save()
return redirect('menu-category')
else:
form = MenuCategoryForm(instance=item)
context = {
'form': form,
'item': item
}
return render(request, 'menu/menu_category_update.html', context)
Template
{% extends 'partials/base.html' %} {% load crispy_forms_filters %} {% load
crispy_forms_tags %}
<!-- {% block title %}Menu category {% endblock %} -->
{% block content %}
<div class="container edit-form-flex">
<div class="row Edit-form-box">
<div class="form-inner-box bg-white">
<div class="heading-editing">
<h3>Edit menu category</h3>
</div>
<form method="POST" class="add-new-form edit-form" enctype="multipart/form-data">
{% csrf_token %} {{ form|crispy }}
<div class="update-buttons-container">
<button class="btn btn-info1" type="submit" value="Update">
Update
</button>
<a class="btn btn-secondary" href="{% url 'menu-category' %}"
>Cancel</a
>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
Well in other to get the name of the image in your form you will be better off in using a form initial like so:
def menu_category_update(request,id):
item = MenuCategory.objects.get(id=id)
if request.method == 'POST':
form = MenuCategoryForm(request.POST, request.FILES, instance=item)
if form.is_valid:
obj = form.save(commit=False)
# obj.username = request.user
form.save()
return redirect('menu-category')
else:
form = MenuCategoryForm(
initial={'image':item.image,
'name':item.name,
'description':iteem.description,
})# this are the fields that we want to show in the form
context = {
'form': form,
'item': item
}
return render(request, 'menu/menu_category_update.html', context)
In your form html you will apply the form initial to the field that you want to show in your form, by doing something like this: form.initial.name As i have illustrated below :
{% extends 'partials/base.html' %} {% load crispy_forms_filters %} {% load
crispy_forms_tags %}
<!-- {% block title %}Menu category {% endblock %} -->
{% block content %}
<div class="container edit-form-flex">
<div class="row Edit-form-box">
<div class="form-inner-box bg-white">
<div class="heading-editing">
<h3>Edit menu category</h3>
</div>
<form method="POST" class="add-new-form edit-form" enctype="multipart/form-data">
{% csrf_token %}
<label> Image name </label>
{{form.initial.name}}
<label> Description </label>
{{ form.initial.description }}
<label> Image </label>
{{ form.initial.image }}
<div class="update-buttons-container">
<button class="btn btn-info1" type="submit" value="Update">
Update
</button>
<a class="btn btn-secondary" href="{% url 'menu-category' %}"
>Cancel</a
>
</div>
</form>
</div>
</div>
</div>
{% endblock %}

saving image URL using django shell

I want to save the url of images in my database using django shell
here is my model
class Album(models.Model):
reference = models.IntegerField(null = True)
created_at = models.DateTimeField(auto_now_add=True)
available = models.BooleanField(default=True)
title = models.CharField(max_length=200)
picture = models.URLField()
artists = models.ManyToManyField(Artist, related_name='albums', blank=True)
here is what i did in the shell
album = Album.objects.create(title="Funambule", picture="/home/etali/Images/moi.png")
the url is correctly save in the database but it's impossible to load it in the view
here is the view
<div class="col-sm-4 text-center">
<a href="/">
<img class="img-responsive" src="{{ album.picture }}" alt="{{ album.title }}">
</a>
<h3>{{ album.title }}</h3>
{% for artist in album.artists.all %}
<p>{{ artist.name }}</p>
{% endfor %}
</div>
here is the error that appears when I inspect the code

Django: NoReverseMatch at /home/blog/ Reverse for 'post-detail' not found. 'post-detail' is not a valid view function or pattern name

I have been getting this error, and I didn't know what I did wrong in the code, I checked everything and I still cant figure it out. I also try getting the specific post object in the database by id, i mean doing something like "post = Post.objects.get(id=id)" in post function in my views.py, but i got the same error.
Any help will be appreciated.
this is my models.py
from django.db import models
from django.contrib.auth import get_user_model
from django.urls import reverse
User = get_user_model()
class Author(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
profile_pic = models.ImageField()
def __str__(self):
return self.user.username
class Category(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return self.name
class Post(models.Model):
title = models.CharField(max_length=200)
overview = models.CharField(max_length=200)
categories = models.ManyToManyField(Category)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
comment_count = models.IntegerField(default=0)
views_count = models.IntegerField(default=0)
timestamp = models.DateTimeField(auto_now_add=True)
thumbnail = models.ImageField()
featured = models.BooleanField(default=False)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={'id': self.id})
my urls
from django.urls import path
from blog.views import home, blog, post
app_name = 'blog'
urlpatterns = [
path('', home, name='home-page'),
path('blog/', blog, name='blogs'),
path('post/<id>/', post, name='post-detail'),
]
my blog.html template
<div class="container">
<div class="row">
{% for post in queryset %}
<div class="post col-xl-6">
<div class="post-thumbnail">
<img src="{{post.thumbnail.url}}" alt="..." class="img-fluid">
</div>
<div class="post-details">
<div class="post-meta d-flex justify-content-between">
<div class="category">
{% for cat in post.categories.all %}
{{cat}}
{% endfor %}
</div>
</div>
<a href="{{post.get_absolute_url}}">
<h3 class="h4">{{post.title}}</h3>
</a>
<p class="text-muted">{{post.overview}}</p>
<footer class="post-footer d-flex align-items-center">
<a href="#" class="author d-flex align-items-center flex-wrap">
<div class="avatar">
<img src="{{post.author.profile_pic.url}}" alt="..." class="img-fluid">
</div>
<div class="title">
<span>{{post.author.user.username}}</span>
</div>
</a>
<div class="date"><i class="icon-clock"></i>{{post.timestamp|timesince}} ago</div>
<div class="comments meta-last"><i class="icon-comment"></i>{{post.comment_count}}</div>
</footer>
</div>
</div>
{% endfor %}
</div>
<!-- Pagination -->
<nav aria-label="Page navigation example">
<ul class="pagination pagination-template d-flex justify-content-center">
{% if queryset.has_previous %}
<li class="page-item">
<a href="?page={{queryset.previous_page_number}}" class="page-link">
<i class="fa fa-angle-left"></i>
</a>
</li>
{% endif %}
<li class="page-item">{{queryset.number}}</li>
{% if queryset.has_next %}
<li class="page-item">
<a href="?page={{queryset.next_page_number}}" class="page-link">
<i class="fa fa-angle-right"></i>
</a>
</li>
{% endif %}
</ul>
</nav>
</div>
my views.py
from django.shortcuts import render, redirect
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from blog.models import Post, Category
from marketing.models import Signup
def home(request):
featured_posts = Post.objects.filter(featured=True)
latest_posts = Post.objects.order_by('-timestamp')[:3]
if request.method == 'POST':
email = request.POST['email']
new_signup = Signup()
new_signup.email = email
new_signup.save()
context = {
'featured_posts': featured_posts,
'latest_posts': latest_posts
}
return render(request, 'index.html', context)
def blog(request):
post_list = Post.objects.all()
latest_posts = Post.objects.order_by('-timestamp')[:3]
categories = Category.objects.all()
paginator = Paginator(post_list, 4)
page_number = request.GET.get('page')
try:
queryset = paginator.get_page(page_number)
except PageNotAnInteger:
queryset = paginator.get_page(1)
except EmptyPage:
queryset = paginator.get_page(paginator.num_pages)
context = {
'post_list': post_list,
'queryset': queryset,
'latest_posts': latest_posts,
'categories': categories,
}
return render(request, 'blog.html', context)
def post(request, id):
context = {}
return render(request, 'post.html', context)
In your models.py change the get_absolute_url as follow. You need to include the app name also before calling any specific url from an app.
def get_absolute_url(self):
return reverse('blog:post-detail', kwargs={'id': self.id})

Set instances of a Form without the User input

I am trying to set an instance of a Modelform that render through ListView.
Program Model:
class Program(models.Model):
patient = models.ForeignKey(User, on_delete=models.CASCADE, default=0)
program_name = models.CharField(max_length=1000, default="")
date_posted = models.DateTimeField(default=timezone.now)
def __str__(self):
return str(self.id) + " - " + self.patient.username + " - " + self.program_name + " - " + str(self.date_posted)
def get_absolute_url(self):
return reverse('program-detail', kwargs={'pk': self.pk})
Exercise Model:
class Exercise(models.Model):
program = models.ForeignKey(Program, on_delete=models.CASCADE, default=0)
date_posted = models.DateTimeField(default=timezone.now)
name = models.CharField(max_length=1000, default="")
description = models.TextField(default="")
load_share = models.TextField(default="")
breath_method = models.TextField(default="")
recovery_method = models.TextField(default="")
measure_method = models.TextField(default="")
notes = models.TextField(default="")
extra_info = models.TextField(default="")
reps = models.PositiveSmallIntegerField(default=0)
sets = models.PositiveSmallIntegerField(default=0)
def __str__(self):
return str(self.program_id) + " - " + str(self.pk) + " - " + " - " + self.name + " - " + str(self.date_posted)
Data Model:
exercise = models.ForeignKey(Exercise, on_delete=models.CASCADE, default="0")
set_number = models.PositiveSmallIntegerField(default=0)
spo2 = models.PositiveSmallIntegerField(default=0)
hr = models.PositiveSmallIntegerField(default=0)
physical_level = models.PositiveSmallIntegerField(default=0)
breath_level = models.PositiveSmallIntegerField(default=0)
sys = models.PositiveSmallIntegerField(default=0)
dia = models.PositiveSmallIntegerField(default=0)
misc_input = models.PositiveSmallIntegerField(default=0)
def __str__(self):
return self.exercise.name
My Exercise listView include the Data form that the User need to fill up, It is paginated to 1 exercise per page.
Exercise ListView:
# Exercise list inside each program + Data form
class ExerciseListView(LoginRequiredMixin, FormMixin, ListView):
model = Exercise
context_object_name = 'exercises'
form_class = DataForm
paginate_by = 1
def get_queryset(self):
program_num = get_object_or_404(Program, pk=self.kwargs.get('pk'))
return Exercise.objects.filter(program=program_num)
def form_valid(self, dataform):
program_num = get_object_or_404(Program, pk=self.kwargs.get('pk'))
exercises = Exercise.objects.filter(program=program_num)
for exe in exercises:
dataform.instance.exercise = exe.pk
print(dataform.instance.exercise)
return super(ExerciseListView, self).form_valid(dataform)
# Submit the Data form and redirect to the same page exercise
def add_data(request):
page = request.GET.get('page')
page = '?page={}'.format(page) if page else ''
if request.method == "POST":
form = DataForm(request.POST)
if form.is_valid():
data = form.save()
return redirect(reverse('program-detail', kwargs={'pk': data.exercise.program.pk}) + page)
forms.py:
class DataForm(forms.ModelForm):
class Meta:
model = Data
fields = ['set_number', 'spo2', 'hr']
I didn't add all the fields because it is too long for test stage.
template.py:
{% extends "program/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<h3> Program Exercises List </h3>
{% for exercise in exercises %}
<article class="media content-section">
<div class="media-body">
<div class="article-metadata">
{% if user.is_superuser %}
<a class="btn btn-secondary btn-sm mt-1 mb-1" href="{% url 'exercise-update' exercise.id %}">Update</a>
<a class="btn btn-danger btn-sm mt-1 mb-1" href="{% url 'exercise-delete' exercise.id %}">Delete</a>
<p class="article-content">{{ exercise.name }}</p>
{% else %}
<p class="article-content">{{ exercise.name }}</p>
{% endif %}
</div>
<div class="article-metadata">
<p class="article-content">{{ exercise.description }}</p>
<p class="article-content">{{ exercise.breath_method}}</p>
<p class="article-content">{{ exercise.recovery_method }}</p>
<p class="article-content">{{ exercise.measure_method }}</p>
<p class="article-content">{{ exercise.load_share }}</p>
<p class="article-content">{{ exercise.notes }}</p>
<p class="article-content">{{ exercise.extra_info }}</p>
<p class="article-content">{{ exercise.reps }}</p>
<p class="article-content">{{ exercise.sets }}</p>
</div>
<form action="{% url 'data-submit' %}{%if request.GET.page%}?page={{request.GET.page}}{%endif%}" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Exercise Measurements</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Save</button>
</div>
</form>
</div>
</article>
{% endfor %}
{% if is_paginated %}
{% if page_obj.has_previous %}
<a class="btn btn-outline-info mb-4" href="?page={{ page_obj.previous_page_number }}">Previous Exercise</a>
{% endif %}
{% if page_obj.has_next %}
<a class="btn btn-outline-info mb-4" href="?page={{ page_obj.next_page_number }}">Next Exercise</a>
{% else %}
<a class="btn btn-outline-info mb-4" href="{% url 'web-home' %}">Exit</a>
{% endif %}
{% endif %}
{% endblock content %}
The instances I am trying to pass (in the Data form) without the user input are:
exercise - each Data form will be connect to an exercise in the database. as I mention before, the exercises are paginated 1 per page, maybe its something i can use?
I tried to solve it by that way:
def form_valid(self, dataform):
program_num = get_object_or_404(Program, pk=self.kwargs.get('pk'))
exercises = Exercise.objects.filter(program=program_num)
for exe in exercises:
dataform.instance.exercise = exe.pk
print(dataform.instance.exercise)
return super(ExerciseListView, self).form_valid(dataform)
It didn't work, I am still receiving id error for this instance.
set_number - each exercise as few sets. what I want to build is that:
the exercise as "sets" that define the number of sets the user need to perform. I want to set a "for" loop that count the number of sets and pass this instance "set_number" accordingly.
Each time the user submit the form, it will have an exercise and set_number.
Thanks!

How to show filtered items only after adding to cart on home page in django?

i am practicing django by making an ecommerce app. I also share the video so that you can also check the problem.
https://youtu.be/crYlZ7Bo8y4
Application is working perfectly but when i filter the product according to selected category and press add to cart button then it will show all products of all categories instead of showing selected products under that category.
Can you please help me out in this.
index.html page:
{% extends 'base.html' %}
{% block content %}
{% load cart %}
{% load custom_filter %}
<!-- body -->
<div class="container-fluid mt-3">
<div class="row">
<!-- filter -->
<div class="col-lg-3 mx-auto">
<div class="list-group">
All Products
{% for category in categories %}
<a href="/?category={{category.id}}"
class="list-group-item list-group-item-action">{{category.name}}</a>
{% endfor %}
</div>
</div>
<!-- all products -->
<div id='products' class="col-lg-9 mx-auto">
<div class="row mx-auto">
{% for product in products %}
<div class="card mx-auto mb-3" id={{product.id}} style="width: 18rem;">
<img class="card-img-top" src="{{product.image.url}}" alt="Card image cap">
<div class="card-body">
<p class="card-title">{{product.name}}</p>
<p class="card-text"><b>{{product.price|currency}}</b></p>
<!-- {{product | is_in_cart:request.session.cart }} -->
</div>
<div class="card-footer p-0 no-gutters">
{% if product|is_in_cart:request.session.cart %}
<div class="row no-gutters">
<form action="/#{{product.id}}" class="col-2 " method="post">
{% csrf_token %}
<input hidden type="text" name='product' value='{{product.id}}'>
<input hidden type="text" name='remove' value='True'>
<input type="submit" value=" - " class="btn btn-block btn-light border-right">
</form>
<div class="text-center col">{{product|cart_quantity:request.session.cart}} in Cart</div>
<form action="/#{{product.id}}" class="col-2 " method="post">
{% csrf_token %}
<input hidden type="text" name='product' value='{{product.id}}'>
<input type="submit" value=" + " class="btn btn-block btn-light border-left">
</form>
</div>
{% else %}
<form action="/#{{product.id}}" method="POST" class="btn-block">
{% csrf_token %}
<input hidden type="text" name='product' value='{{product.id}}'>
<input type="submit" class="float-right btn btn-light form-control"
value="Add To Cart">
</form>
{% endif %}
</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
{% endblock %}
index.py:
from django.shortcuts import render , redirect , HttpResponseRedirect
from user.models.product import Product
from user.models.category import Category
from django.views import View
# Create your views here.
class Index(View):
def post(self , request):
product = request.POST.get('product')
remove = request.POST.get('remove')
cart = request.session.get('cart')
if cart:
quantity = cart.get(product)
if quantity:
if remove:
if quantity<=1:
cart.pop(product)
else:
cart[product] = quantity-1
else:
cart[product] = quantity+1
else:
cart[product] = 1
else:
cart = {}
cart[product] = 1
request.session['cart'] = cart
print('cart', request.session['cart'])
return redirect('user:homepage')
def get(self , request):
return HttpResponseRedirect(f'/store{request.get_full_path()[1:]}')
def store(request):
cart = request.session.get('cart')
if not cart:
request.session['cart'] = {}
products = None
categories = Category.get_all_categories()
categoryID = request.GET.get('category')
if categoryID:
products = Product.get_all_products_by_categoryid(categoryID)
else:
products = Product.get_all_products();
data = {}
data['products'] = products
data['categories'] = categories
print('you are : ', request.session.get('email'))
return render(request, 'index.html', data)
urls.py:
from django.urls import path
from .views.index import Index,store
from .views.signup import Signup
from .views.login import Login,logout
app_name = 'user'
urlpatterns = [
path('', Index.as_view(), name='homepage'),
path('store', store, name='store'),
path('signup', Signup.as_view(), name='signup'),
path('login', Login.as_view(), name='login'),
path('logout', logout, name='logout'),
]
cart.py template tag:
from django import template
register = template.Library()
#register.filter(name='is_in_cart')
def is_in_cart(product , cart):
keys = cart.keys()
for id in keys:
if int(id) == product.id:
return True
return False;
#register.filter(name='cart_quantity')
def cart_quantity(product , cart):
keys = cart.keys()
for id in keys:
if int(id) == product.id:
return cart.get(id)
return 0;
#register.filter(name='price_total')
def price_total(product , cart):
return product.price * cart_quantity(product , cart)
#register.filter(name='total_cart_price')
def total_cart_price(products , cart):
sum = 0 ;
for p in products:
sum += price_total(p , cart)
return sum
Custom_filter.py template tag:
from django import template
register = template.Library()
#register.filter(name='currency')
def currency(number):
return "₹ "+str(number)
#register.filter(name='multiply')
def multiply(number , number1):
return number * number1
referer = request.META['HTTP_REFERER']
return redirect(referer)
You can get the referring page of request instead of redirecting a constant link.You can also check META

Resources