Show image name inside the image field in Django forms - python-3.x

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 %}

Related

In Django website even if I add an item by pressing add to cart button the status of True for the product added is not shown and still false is visibl

I have made a django e-comm website , when I press the add to cart button on my home page I have written a function which should change the status of a product from false to true once it is added in the cart but it does not work
I have given my cart.py and index.html code
Thank you
cart.py
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:
print(id , product.id)
if int(id) == product.id:
return True
return False
index.html
{% extends 'main/base.html'%}
{% block title %}
index
{% endblock %}
{% block content %}
{% load cart %}
<div class="container-fluid">
<div class="row">
<div class="col-lg-3">
<div class="list-group mt-3">
{% for items in category %}
{{items.Category_name}} <!--i first used a small c for category but it did not pick the words from my category.py fle-->
{% endfor %}
</div>
</div>
<div class="col-lg-9">
<div class="row">
{% for items in product %}
<div class="card mx-auto mb-3 mt-3" style="width: 18rem;">
<img class="card-img-top" src="{{items.product_image.url}}" alt="Card image cap">
<div class="card-body">
<h5 class="card-title">{{items.product_name}}</h5>
<p class="card-text"><b>{{items.product_price}}</b></p>
<p class="card-text"><b>{{items.product_detail}}</b></p>
{{product | is_in_cart:request.session.cart }}
<form action="/" mthod="POST">
{% csrf_token %}
<input hidden type="text" name='product' value='{{items.id}}'>
<input href="#" type="submit" class="float-right btn btn-light border btn-sm" value="Add to Cart">
</form>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
{% endblock %}

How to display extra context and form fields at the same time on django template using class based view?

I am trying to display some extra context on the page, but when I adding get_context_data method it is displayed context but not a forms fields. This is because when I click ulr that triggers view below there is get method by default or prior to forms fields? I don't understand why forms disappear when this method present in SolutionCreate view, indeed all context data displayed
template
{% extends "base.html" %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-sm">
<form action="" method="POST">
<table>
{% csrf_token %}
{{ form.as_p }}
</table>
<input type="submit" class="btn btn-primary" value="Submit">
</form>
</div>
<div class="col-sm">
{{ context }}
<h5>Problem:</h5>
{% for pr in prb %}
<h5>Problem: {{ pr.title }}</h5>
<h6>Description</h6>
<li class="list-group-item">{{ pr.description }}</li>
<p>
</p>
<h6>Risks</h6>
<li class="list-group-item">{{ pr.risks }}</li>
<p>
</p>
<h6>Parts</h6>
<li class="list-group-item">{{ pr.parts }}</li>
<p>
</p>
<h6>Causes</h6>
<li class="list-group-item">{{ pr.causes }}</li>
<p>
</p>
<h6>Published</h6>
<li class="list-group-item">{{ pr.published }}</li>
<p>
</p>
<a href="{% url 'delete_problem' pr.pk %}"
class="btn btn-warning"
role="button"
aria-pressed="true">Delete</a>
<a href="{% url 'update_problem' pr.pk %}"
class="btn btn-warning"
role="button"
aria-pressed="true">Update</a>
<p>
</p>
{% endfor %}
</div>
</div>
</div>
{% endblock content %}
view
class SolutionCreate(CreateView):
model = Solution
template_name = 'analysis/create_solution.html'
fields = [
'problem',
'research',
'solutions',
'resources',
'plan',
'test'
]
def post(self, request, *args, **kwargs):
form = SolutionForm(request.POST)
if form.is_valid():
form.save(commit=True)
return HttpResponseRedirect('/saved/')
return render(request, self.template_name, {'form': form})
def get_context_data(self, *args, **kwargs):
prb = Problem.objects.select_related()
return {'prb': prb}
get_context_data is a method on the parent class. If you override it, you still need to call the parent method which is what adds the form to the context. You do this by calling super() inside your own method, to obtain the context data, and then add your own:
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context['prb'] = Problem.objects.select_related()
return context
Refer to the documentation on adding extra context to see how you should use get_context_data.
This worked for me in a similar scenario
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(**kwargs)
prb = Problem.objects.select_related()
context.update({'prb': prb})
return context

django not displaying error_messages in forms

i am new to django and i have this form i am working on i have tried everything possible i cant seem to display the form error messages. i have tried using a def clean method nothing happens when i try to submit an empty form..i have tired switing to using FormView i have also tried using function view i have tried using a for loop and adding {{ form.non_field_errors }} in my template nothing pops up.
my app/forms.py
from django import forms
class ContactForm(forms.Form):
name = forms.CharField( label='Your Name', min_length=2, max_length=25, required=True, error_messages ={'required':'Please tell Oluwafemi your name'})
email = forms.EmailField(label='Your Email', required=True, error_messages={'invalid':'Please fill in a valid email'})
subject = forms.CharField(label='Subject', min_length=4, max_length=100, required=True)
message = forms.CharField(widget=forms.Textarea(attrs={'placeholder':'Write Oluwafemi a Message'}), error_messages ={'required':'Please write something for Oluwafemi'})
my app/views.py
from django.views.generic import TemplateView
from django.shortcuts import render
from django.core.mail import send_mail
from .forms import ContactForm
from django.http import HttpResponseRedirect
# Create your views here.
class ProfilePageView(TemplateView):
template_name = 'femi_profile.html'
form_class = ContactForm
success_url = 'femiir'
def get(self, request, *args, **kwargs):
form = self.form_class()
return render(request, self.template_name, {'form': form})
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
name = form.cleaned_data['name']
email = form.cleaned_data['email']
subject = form.cleaned_data['subject']
message = form.cleaned_data['message']
# Send the email
send_mail(
f"{subject} - message from {name} ", # message subject
message, # Message Body
email, # Sender's mail (From mail)
['d4rahl#gmail.com'], # Reciever's mail(To mail)
)
return HttpResponseRedirect('femiir')
return render(request, self.template_name, {'form': form})
snippet of my html template
<div class="col-lg-7 mt-5 mt-lg-0 d-flex align-items-stretch">
<form method="post">
{% csrf_token %}
<div class="form-row">
<div class="form-group col-md-6">
{{ form.name|as_crispy_field }}
</div>
<div class="form-group col-md-6">
{{ form.email|as_crispy_field }}
</div>
</div>
<div class="form-group">
{{ form.subject|as_crispy_field }}
{{ form.message|as_crispy_field }}
</div>
<div class="text-center"><button type="submit" class="btn btn-primary ">Send Message</button></div>
</form>
</div>
please what i my doing wrong
Did you try looping through form.errors in template?
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
{{ error }}
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
{% endif %}
When you are rendering fields manually you would have to use error tags.
{{ form.name_of_field.errors }}
<form method="post">
{% csrf_token %}
<div class="form-row">
<div class="form-group col-md-6">
{{ form.name|as_crispy_field }}
{{ form.name.errors}}
</div>
<div class="form-group col-md-6">
{{ form.email|as_crispy_field }}
{{ form.email.errors}}
</div>
</div>
<div class="form-group">
{{ form.subject|as_crispy_field }}
{{ form.subject.errors}}
{{ form.message|as_crispy_field }}
{{ form.message.errors}}
</div>
<div class="text-center"><button type="submit" class="btn btn-primary ">Send Message</button></div>
</form>
https://docs.djangoproject.com/en/dev/topics/forms/#rendering-fields-manually

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

How to add Bootstrap Validation to WTForms

I am using WTForms in conjunction with Flask and I would like to integrate the Bootstrap Form Validation for errors in my form. I have a basic login form setup something like this:
class LoginForm(FlaskForm):
"""Login form."""
email = EmailField(
"Email Address", validators=[DataRequired(), Email(), Length(min=6, max=40)]
)
password = PasswordField(
"Password", validators=[DataRequired()]
)
def __init__(self, *args, **kwargs):
"""Create instance."""
super(LoginForm, self).__init__(*args, **kwargs)
self.user = None
def validate(self):
"""Validate the form."""
initial_validation = super(LoginForm, self).validate()
if not initial_validation:
return False
self.user = User.query.filter_by(email=self.email.data).first()
if not self.user:
self.email.errors.append("Unknown email address!")
return False
if not self.user.check_password(self.password.data):
self.password.errors.append("Invalid password!")
return False
if not self.user.verified:
self.email.errors.append("Please verify your email address!")
return False
return True
My login.html template is setup like this:
<form method="POST" action="{{ url_for('public.login') }}" role="form">
{{ form.csrf_token }}
<div class="form-group">
{{ form.email.label(class_="form-control-label") }}
<div class="input-group input-group-merge">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-user"></i></span>
</div>
{{ form.email(placeholder="name#example.com", class_="form-control") }}
</div>
</div>
<div class="form-group mb-4">
<div class="d-flex align-items-center justify-content-between">
<div>
{{ form.password.label(class_="form-control-label") }}
</div>
<div class="mb-2">
Lost password?
</div>
</div>
<div class="input-group input-group-merge">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-key"></i></span>
</div>
{{ form.password(placeholder="Password", class_="form-control") }}
<div class="input-group-append" onclick="togglePassword()">
<span class="input-group-text">
<i class="fas fa-eye"></i>
</span>
</div>
</div>
</div>
<div class="row mt-4">
<div class="col-md-auto mt-1 mb-2" align="center">
<button type="submit" class="btn btn-sm btn-primary btn-icon rounded-pill">
<span class="btn-inner--text">Sign in</span>
<span class="btn-inner--icon"><i class="fas fa-long-arrow-alt-right"></i></span>
</button>
</div>
<div class="col-md-auto text-center mt-2">
<p class="text-secondary-dark">or</p>
</div>
<div class="col-md-auto" align="center">
<button type="button" class="btn btn-md btn-secondary btn-icon-only">
<span class="btn-inner--icon">
<i class="fab fa-google"></i>
</span>
</button>
<button type="button" class="btn btn-md btn-secondary btn-icon-only">
<span class="btn-inner--icon">
<i class="fab fa-linkedin"></i>
</span>
</button>
</div>
</div>
</form>
I would like to display the errors that I validate using WTForms, but I am unsure of how to change the class of the original form element to is-invalid or is-valid, and how to create the labels for each error. I have looked into macros, but they don't seem to be able to modify the form element either.
Can someone point me in the right direction?
I faced the same problem and I wanted to avoid the use of any third package (flask-bootstrap), so I came up with this simple solution:
<div class="form-group">
{{ form.email.label }} <span class="text-danger">*</span>
{# her #}
{{ form.email(class="form-control" + (" is-invalid" if form.email.errors else "") + " rounded-0 shadow-none", **{"placeholder": "Your Email", "aria-describedby": "emailHelp", "autocomplete": "off"}) }}
<small id="emailHelp" class="form-text text-muted">We'll never share your data with anyone else.</small>
{% if form.email.errors %}
{% for error in form.email.errors %}
<div class="invalid-feedback">{{ error }}</div>
{% endfor %}
{% endif %}
</div>
The trick is to use a simple ternary expression combined with string concatenation.
#cizario's answer is a great start. However, I found a better implementation for the errors. Using WTForm's Custom Widgets, you get the following widgets:
from wtforms.widgets import PasswordInput, CheckboxInput, TextInput
from wtforms.widgets.html5 import EmailInput
class BootstrapVerifyEmail(EmailInput):
"""Bootstrap Validator for email"""
def __init__(self, error_class=u"is-invalid"):
super(BootstrapVerifyEmail, self).__init__()
self.error_class = error_class
def __call__(self, field, **kwargs):
if field.errors:
c = kwargs.pop("class", "") or kwargs.pop("class_", "")
kwargs["class"] = u"%s %s" % (self.error_class, c)
return super(BootstrapVerifyEmail, self).__call__(field, **kwargs)
class BootstrapVerifyPassword(PasswordInput):
"""Bootstrap Validator for password"""
def __init__(self, error_class=u"is-invalid"):
super(BootstrapVerifyPassword, self).__init__()
self.error_class = error_class
def __call__(self, field, **kwargs):
if field.errors:
c = kwargs.pop("class", "") or kwargs.pop("class_", "")
kwargs["class"] = u"%s %s" % (self.error_class, c)
return super(BootstrapVerifyPassword, self).__call__(field, **kwargs)
class BootstrapVerifyBoolean(CheckboxInput):
"""Bootstrap Validator for boolean"""
def __init__(self, error_class=u"is-invalid"):
super(BootstrapVerifyBoolean, self).__init__()
self.error_class = error_class
def __call__(self, field, **kwargs):
if field.errors:
c = kwargs.pop("class", "") or kwargs.pop("class_", "")
kwargs["class"] = u"%s %s" % (self.error_class, c)
return super(BootstrapVerifyBoolean, self).__call__(field, **kwargs)
class BootstrapVerifyText(TextInput):
"""Bootstrap Validator for text"""
def __init__(self, error_class=u"is-invalid"):
super(BootstrapVerifyText, self).__init__()
self.error_class = error_class
def __call__(self, field, **kwargs):
if field.errors:
c = kwargs.pop("class", "") or kwargs.pop("class_", "")
kwargs["class"] = u"%s %s" % (self.error_class, c)
return super(BootstrapVerifyText, self).__call__(field, **kwargs)
This will add the invalid tag so that bootstrap can mark it as invalid. In the HTML, do something like this to add the error message:
{{ login_user_form.email.label(class_="form-control-label") }}
<div class="input-group input-group-merge">
<div class="input-group-prepend">
<span class="input-group-text" id="user"><i class="fas fa-user"></i></span>
</div>
{{ login_user_form.email(placeholder="name#example.com", class_="form-control", **{"aria-describedby": "inputGroupPrepend3", "required": ""}) }}
{% for error in login_user_form.email.errors %}
<div class="invalid-feedback">{{ error }}</div>
{% endfor %}
</div>
I ended up using a different library that provides Bootstrap widgets:
https://github.com/agdsn/wtforms-widgets
The usage gets really simple really fast:
from wtforms import validators
from wtforms.validators import Email
from wtforms_widgets.base_form import BaseForm
from wtforms_widgets.fields.core import StringField, PasswordField
class RegisterForm(BaseForm):
email = StringField('Email Address', [Email(), validators.DataRequired(message='Forgot your email address?')])
password = PasswordField('Password', [validators.DataRequired(message='Must provide a password. ;-)')])
<form method="POST" action="{{ url_for('auth.register') }}" accept-charset="UTF-8" role="form">
{% for field in form %}
{{ field(render_mode='horizontal', autocomplete='off') }}
{% endfor %}
<input type="submit" value="submit">
</form>
But this doesn't include validation.
To add validation, I put this in Jinja:
<form method="POST" action="{{ url_for('auth.register') }}" accept-charset="UTF-8" role="form">
{% for field in form %}
{{ field() }}
{% for error in field.errors %}
<div class="invalid-feedback">{{ error }}</div>
{% endfor %}
{% endfor %}
<input type="submit" value="submit">
</form>
And for flashed messages I use this in my base layout.html that I extend everywhere:
<div>
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
{% if category == 'message' %}
<div class="alert alert-warning" role="alert">
{% else %}
<div class="alert alert-{{ category }}" role="alert">
{% endif %}
{{ message }}
</div>
{% endfor %}
{% endif %}
{% endwith %}
</div>
When rendering your template using render_template, pass the 'is-valid' class to all the elements you want. Use this
class = '{{email_valid_class}} all other classes here'
Then in python return render_template('login.html',email_valid_class='is-valid')

Resources