Django models choice textField mapping - python-3.x

I am building a website for myself I am updating my projects from django admin I wanted to create a custom field which is a map of choice(tag color) and tag text.
I want to make it look something like this
This is my model
class Project(models.Model):
projectTemplate = CloudinaryField('image')
projectTitle = models.TextField(default="Title ")
desc = models.TextField(default="not mentioned")
projectLink = models.URLField(max_length=200, default="not mentioned")
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f'{self.projectTitle} - {self.desc[:15]} ..'
views.py
def projects(request):
Projects = Project.objects.all()
return render(request, 'devpage/projects.html',{'Projects': Projects})
This is my current DTL
{% for project in Projects %}
<div class="col">
<div class="card shadow-sm">
<img src="{{ project.projectTemplate.url }}" height="225" width="100%">
<div class="card-body">
<h6 class="text-center">
{{ project.projectTitle }}
</h6>
<p class="card-text">{{ project.desc }}</p>
<div class="mb-3">
<span class="badge rounded-pill bg-secondary">Django</span>
<span class="badge rounded-pill bg-success">Python</span>
</div>
<div class="d-flex justify-content-between align-items-center">
<div class="btn-group">
<button type="button" class="btn btn-sm btn-warning btn-outline-secondary"><a
href="{{ project.projectLink }}" target="_blank" type="button"
class="btn">View</a></button>
</div>
<small class="text-muted">{{ project.created_at }}</small>
</div>
</div>
</div>
</div>
{% endfor %}
I want a custom model field which takes choice of label color and corresponding text with dynamic size I tried using json(field name tags) but its not interactive its like {"primary":"django","success":"Python","seconday":"webApp"}
This is JSON DTL
//Inner for loop for tags
<div class="mb-3">
{% for color,text in Project.tags.items %}
<span class="badge rounded-pill bg-{{ color }}">{{ text }}</span>
{% endfor %}
</div>

Assuming you have a Tag model which is a ManyToManyField, you could just store the color as an attribute to the model.
Your model:
class Tag(models.Model):
text = models.CharField(max_length=32)
color = models.CharField(max_length=32, default="bg-success")
class Project(models.Model):
...
tags = models.ManyToManyField(Tag)
Your template:
{% for tag in Project.tags %}
<span class="badge rounded-pill {{ tag.color }}">{{ tag.text }}</span>
{% endfor %}
Some future improvement to this could be a subclass that pre-defines all of the colors.

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 fetch data from database and show it in bootstrap's modal box ( pop up ) in django respectively?

Technologies I'm using --> Back-end --> Python, Web Framework --> Django, Front-end --> HTML5, CSS3, Bootstrap 4, Database --> SQLite3.
What I want --> To display the data of each object in each bootstrap's modal box( popup ).
The problem --> Data of the first object is only being shown in all the modal boxes( popups ).
Files are as follows:
HTML template --> manage_requisition.html 👇
{% extends 'hod_template/base_template.html' %}
{% block page_title %}
Manage Requisitions
{% endblock page_title %}
{% block main_content %}
<!-- Main content -->
<section class="content">
<div class="container-fluid">
<div class="row">
<div class="col-md-12">
<!-- general form elements -->
<div class="card card-primary">
<div class="card-header">
<h3 class="card-title">Manage Requisitions</h3>
</div>
<!-- /.card-header -->
<!-- form start -->
<div class="table">
<table class="table">
<tr>
<th style="text-align: center;">Action</th>
<th>View Requisition</th>
</tr>
{% for requisition in requisitions %}
<tr>
<td style="text-align: center; vertical-align: middle;">
{% if requisition.requisition_status == 0 %}
<a style="width: 85px;" href="{% url 'supervisor_approve_requisition' requisition_id=requisition.id %}" class="btn btn-success inline" >Approve</a>
<a style="width: 85px;" class="btn btn-danger inline" href="{% url 'supervisor_rejected_requisition' requisition_id=requisition.id %}" >Reject</a>
{% elif requisition.requisition_status == 1 %}
<button class="btn btn-warning" disabled="disabled" data-toggle="modal" data-target="#reply_modal">Approved</button>
{% else %}
<button class="btn btn-danger" disabled="disabled" data-toggle="modal" data-target="#reply_modal">Rejected</button>
{% endif %}
</td>
<td>
<button type="button" class="btn btn-warning" data-toggle="modal" data-target="#reqModal">
View Requisition
</button>
<div class="modal" id="reqModal" tabindex="-1" aria-labelledby="reqModal" aria-hidden="true">
<div class="modal-dialog modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="reqModalTitle">Requisition Details</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p><strong>Position Required :</strong> {{ requisition.position_required }}</p>
<p><strong>Requirement :</strong> {{ requisition.requirement }}</p>
<p><strong>Candidate Name :</strong> {{ requisition.candidate_name }}</p>
<p><strong>Department :</strong> {{ requisition.department }}</p>
<p><strong>Post :</strong> {{ requisition.post }}</p>
<p><strong>Requirement Time Period :</strong> {{ requisition.requirement_time_period }}</p>
<p><strong>Work Type :</strong> {{ requisition.work_type }}</p>
<p><strong>Duration Start Date :</strong> {{ requisition.duration_start_date }}</p>
<p><strong>Duration End Date :</strong> {{ requisition.duration_end_date }}</p>
<p><strong>Requisition Reason :</strong> {{ requisition.requisition_reason }}</p>
<p><strong>Minimum Qualification :</strong> {{ requisition.min_qualification }}</p>
<p><strong>Maximum Qualification :</strong> {{ requisition.max_qualification }}</p>
<p><strong>Minimum Experience :</strong> {{ requisition.min_experience }}</p>
<p><strong>Maximum Experience :</strong> {{ requisition.max_experience }}</p>
</div>
<div class="modal-footer">
</div>
</div>
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
<!-- /.card -->
</div>
</div>
</div>
</section>
<!-- Modal -->
<!-- /.content -->
{% endblock main_content %}
Views file --> HODviews.py 👇
def Manage_Requisitions(request):
requisitions = Requisition.objects.all()
context = {"requisitions":requisitions}
return render(request, "hod_template/manage_requisition.html", context)
urls.py file --> urls.py 👇
path("manage_requisition/", HODviews.Manage_Requisitions, name="manage_requisition")
models.py file --> models.py 👇
class Requisition(models.Model):
id = models.AutoField(primary_key=True)
position_required = models.CharField(max_length=2000, default="")
requirement_choices = (
("New", "New"),
("BackFill", "BackFill")
)
requirement = models.CharField(max_length=100, choices=requirement_choices, default="")
candidate_name = models.CharField(max_length=2000, default="")
department = models.CharField(max_length=2000, default="")
post = models.CharField(max_length=2000, default="")
requirement_type = (
("Permanent", "Permanent"),
("Temporary", "Temporary"),
("Fixed Contract", "Fixed Contract")
)
requirement_time_period = models.CharField(max_length=500, choices=requirement_type, default="")
work_type = (
("Full-Time", "Full-Time"),
("Part-Time", "Part-Time")
)
work_type = models.CharField(max_length=500, choices=work_type, default="")
duration_start_date = models.DateField(blank=True)
duration_end_date = models.DateField(blank=True)
requisition_reason = models.TextField()
min_qualification = models.CharField(max_length=1000 ,default="")
max_qualification = models.CharField(max_length=1000 ,default="")
min_experience= models.CharField(max_length=1000 ,default="")
max_experience= models.CharField(max_length=1000 ,default="")
requisition_status = models.IntegerField(default=0)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now_add=True)
objects = models.Manager()
def __str__(self):
return self.candidate_name
Image of the UI 👇
Image of the first pop up 👇
Image of the second popup 👇
I'm getting the data of first objet in each popup. But I want the data of every object to be displayed in each popup.
You can contact me here 👇
Linkedin --> https://www.linkedin.com/in/precioushuzaifa/
Instagram --> https://www.instagram.com/precious_huzaifa/
The problem is all your modals have the same id and so your buttons are just going to open the first modal they find with the ID. You need to add some sort of id to each modal. you can use {{ forloop.counter }} to get the iteration number and attach that to the id.
<button type="button" class="btn btn-warning" data-toggle="modal" data-target="#reqModal-{{ forloop.counter }}">
View Requisition
</button>
<div class="modal" id="reqModal-{{ forloop.counter }}" tabindex="-1" aria-labelledby="reqModal" aria-hidden="true">

How add space between two cards - bootstrap?

I was creating a simple blog page using Django. When I added cards for the articles it came like this
There is no space between the cards.
{% extends 'base.html' %}
{% block content %}
<div class="card mt-3" style="width: 100%;">
{% for post in posts %}
<div class="card-header">
<cite title="Source Title">{{ post.author }}</cite>
<small class="text-muted float-right">{{ post.date_posted | date:"F d, Y" }}</small>
</div>
<div class="card-body">
<div class="card-title">{{ post.title }}</div>
<p class="card-text">{{ post.content }}</p>
</div>
{% endfor %}
</div>
{% endblock content %}
How do I add space between these cards?
your for loop is not in correct place change code from
{% extends 'base.html' %}
{% block content %}
<div class="card mt-3" style="width: 100%;">
{% for post in posts %}
<div class="card-header">
<cite title="Source Title">{{ post.author }}</cite>
<small class="text-muted float-right">{{ post.date_posted | date:"F d, Y" }}</small>
</div>
<div class="card-body">
<div class="card-title">{{ post.title }}</div>
<p class="card-text">{{ post.content }}</p>
</div>
{% endfor %}
</div>
{% endblock content %}
to bellow code
{% extends 'base.html' %}
{% block content %}
{% for post in posts %}
<div class="card mt-3" style="width: 100%;">
<div class="card-header">
<cite title="Source Title">{{ post.author }}</cite>
<small class="text-muted float-right">{{ post.date_posted | date:"F d, Y" }}</small>
</div>
<div class="card-body">
<div class="card-title">{{ post.title }}</div>
<p class="card-text">{{ post.content }}</p>
</div>
</div>
{% endfor %}
{% endblock content %}
Firstly, you need to do the loop for every card, instead of doing it for the inner divs 'card-header' and 'card-body'. Secondly, to answer you question, you should use a spacing by either a margin or a padding.
I would suggest to make the cards a standard width and use a 'margin right 3':
{% for post in posts %}
<div class="card mt-3 mr-3" style="width: 250px">
<div class="card-header">
...
</div>
<div class="card-body">
...
</div>
</div>
{% endfor %}
Besides this solution, I suggest you read the Bootstaps Grid Layout documentation, so you can place the cards nicely within your content block.

django related object reference not displaying items

I have two models SubCategory and Product i created a listview with model set to SubCategory and reference its related product set in template but items are not being loaded don't know what I have missed
models
class SubCategory(models.Model):
name = models.CharField(max_length=200)
description = models.CharField(max_length=300)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=120)
price = models.FloatField()
image = models.ImageField(upload_to='pdt_imgs/')
sku = models.IntegerField()
available = models.BooleanField(default=True)
discount = models.IntegerField(default = 0)
category = models.ForeignKey(SubCategory, on_delete=models.CASCADE)
seller = models.ForeignKey(Seller, on_delete=models.CASCADE)
def __str__(self):
return self.name
Template in which I tried to reference product items related to subcategories
<div class="ps-block__categories">
<h3>Clothing & <br> Apparel</h3>
<ul>
{% for subcategory in object_list %}
<li>{{ subcategory.name }}</li>
{% endfor %}
</ul><a class="ps-block__more-link" href="#">View All</a>
</div>
<div class="ps-block__slider">
<div class="ps-carousel--product-box owl-slider" data-owl-auto="true" data-owl-loop="true"
data-owl-speed="7000" data-owl-gap="0" data-owl-nav="true" data-owl-dots="true" data-owl-item="1"
data-owl-item-xs="1" data-owl-item-sm="1" data-owl-item-md="1" data-owl-item-lg="1" data-owl-duration="500"
data-owl-mousedrag="off"><img src="{% static 'img/slider/home-3/clothing-1.jpg' %}" alt=""><a href="#"><img
src="{% static 'img/slider/home-3/clothing-2.jpg' %}" alt=""></a><a href="#"><img
src="{% static 'img/slider/home-3/clothing-3.jpg' %}" alt=""></a></div>
</div>
<div class="ps-block__product-box">
{% for product in object.product_set.all %}
<div class="ps-product ps-product--simple">
<div class="ps-product__thumbnail"><a href="product-default.html"><img src="{{ product.image.url }}"
alt=""></a>
{% if product.discount > 0 %}
<div class="ps-product__badge">-{{ product.discount }}%</div>
{% endif %}
{% if product.available == False %}
<div class="ps-product__badge out-stock">Out Of Stock</div>
{% endif %}
<ul class="ps-product__actions">
<li><a href="#" data-toggle="tooltip" data-placement="top" title="Read More"><i
class="icon-bag2"></i></a></li>
<li><a href="#" data-placement="top" title="Quick View" data-toggle="modal"
data-target="#product-quickview"><i class="icon-eye"></i></a></li>
<li><a href="#" data-toggle="tooltip" data-placement="top" title="Add to Whishlist"><i
class="icon-heart"></i></a></li>
<li><a href="#" data-toggle="tooltip" data-placement="top" title="Compare"><i
class="icon-chart-bars"></i></a></li>
</ul>
</div>
<div class="ps-product__container">
<div class="ps-product__content" data-mh="clothing"><a class="ps-product__title"
href="product-default.html">{{ product.name }}</a>
<div class="ps-product__rating">
<select class="ps-rating" data-read-only="true">
<option value="1">1</option>
<option value="1">2</option>
<option value="1">3</option>
<option value="1">4</option>
<option value="2">5</option>
</select><span>01</span>
</div>
<p class="ps-product__price sale">UGX{{ product.price }}</p>
</div>
</div>
</div>
{% endfor %}
</div>
For now I cant load product items despite trying reference them as related objects of subcategory

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