Django: Create a dynamic sidebar template and use it in other templates - django

NOTE: This question is not about creating or using a base template!
I'm creating a products app in my project, using only django and html/css, and all pages in this part has a sidebar nav menu that categorizes different product models and types. So this sidebar will be used in all other product pages.
Here is my views.py file:
from django.shortcuts import render
from .models import (
Product,
Usage,
SubUsage,
MainModel,
PumpType,
HeadFlowDataSet,
)
def products_usage_main(request):
product_queryset = Product.objects.all()
usage_queryset = Usage.objects.all()
sub_usage_queryset = SubUsage.objects.all()
main_model_queryset = MainModel.objects.all()
pump_type_queryset = PumpType.objects.all()
context = {
"product_queryset": product_queryset,
"usage_queryset": usage_queryset,
"sub_usage_queryset": sub_usage_queryset,
"main_model_queryset": main_model_queryset,
"pump_type_queryset": pump_type_queryset,
}
return render(request, "products/products_usage_main.html", context)
def sidebar_data(request):
usage_queryset = Usage.objects.all()
sub_usage_queryset = SubUsage.objects.all()
main_model_queryset = MainModel.objects.all()
pump_type_queryset = PumpType.objects.all()
context = {
"usage_queryset": usage_queryset,
"sub_usage_queryset": sub_usage_queryset,
"main_model_queryset": main_model_queryset,
"pump_type_queryset": pump_type_queryset,
}
return render(request, "products/products_sidebar.html", context)
And the sidebar template is as shown below:
<ul class="nav flex-column list-unstyled my-3 ms-3">
{% for usage_item in usage_queryset %}
<li class="nav-item p-2 ms-4">
<a href="#" class="text-decoration-none nm-text-color fw-semibold"
data-bs-toggle="collapse"
data-bs-target="#usage_{{ usage_item.usage_name_fa }}">
<i class="fa-solid fa-angle-left me-2 icon-selector"></i>
الکتروپمپ‌های {{ usage_item.usage_name_fa }}
</a>
<ul class="submenu collapse" id="usage_{{ usage_item.usage_name_fa }}"
data-bs-parent="#nav_accordion">
{% for sub_usage in sub_usage_queryset %}
{% if sub_usage.usage == usage_item %}
<li class="my-2 ms-4">
<a href="#" class="text-decoration-none nm-text-color fw-semibold">
{{ sub_usage }}
</a>
</li>
{% endif %}
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
And now I'm creating a proucts main page for example, which should implement this sidebar.
I included this sidebar template in my products page template as shown below:
<section>
<div class="container-fluid">
<div class="row">
<div class="col-6 col-lg-4 px-0">
{% include "products/products_sidebar.html" %}
</div>
<div class="col-6 col-lg-8">
content
</div>
</div>
</div>
</section>
Now, I know that without a URL, the view sidebar_data() won't be called, and for now my urls are as shown below:
urlpatterns = [
path("application/", products_usage_main, name="products_usage_main"),
path("application/<str:pk>", product_detail, name="product_detail"),
]
And as expected, context data sent in the sidebar_data() view, will not be sent and so my sidebar will not be populated with the data.
How am I supposed to acheive this?
There is one way, in which I have to send the queryset data sent to sidebar in all the different product pages, but I think there should be a more sufficient way.
Your help is appreciated in advance.

To achieve this you need to pass the same context in your all views. A simple demonstration of your views would be as follows:
views.py
# Since these context will be common to all views it would be written outside any view function
def get_common_queryset():
usage_queryset = Usage.objects.all()
sub_usage_queryset = SubUsage.objects.all()
main_model_queryset = MainModel.objects.all()
pump_type_queryset = PumpType.objects.all()
queryset_dictionary = {
"usage_queryset": usage_queryset,
"sub_usage_queryset": sub_usage_queryset,
"main_model_queryset": main_model_queryset,
"pump_type_queryset": pump_type_queryset,
}
return queryset_dictionary
# and in every other views
def products_usage_main(request):
...
context_of_view = {
...
}
common_context = get_common_queryset()
context = {**context_of_view, **common_context} # dictionary expansion
return render(request, "template_name.html", context)

Related

How to add data to Django's database by the click of a button using JS and AJAX

I'm trying to add data that I rendered on a page from an API endpoint, to my database when I click "Add to my records" button, as can be seen in the image below, and I'm only trying to store "Date and Country" into the database (my model table has only date and country)
enter image description here
I've seen many resources talking about how JS and AJAX are useful in this case but I'm lost with logic of it all. Is there any way someone could explain how it's supposed to be done.
models.py
from django.db import models
class CountryData(models.Model):
country = models.CharField(max_length=100)
date = models.DateTimeField()
def __str__(self):
return self.country
views.py
def all_countries(request):
first_response = requests.get("https://api.covid19api.com/summary").json()
results = len(first_response["Countries"])
my_new_list = []
data_list = []
for i in range(0, results):
my_new_list.append(first_response["Countries"][i])
# print(my_new_list)
if request.method == "POST":
if request.POST.get("country") and request.POST.get("date"):
added_record = CountryData()
added_record.country = request.POST.get("country")
# 2022-12-19T08:53:48.179Z
added_record.date = datetime.datetime.strptime(
request.POST.get("date"), "%Y-%m-%dT%I:%M:%S.%fZ"
)
added_record.save()
return render(request, "allcountries.html")
else:
return render(request, "allcountries.html", )
context = {"my_new_list": my_new_list}
return render(request, "allcountries.html", context)
urls.py
from django.urls import path, include
from .views import home, all_countries
urlpatterns = [
path("", home, name="home"),
path("allcountries", all_countries, name="all_countries")
]
allcountries.html
{% extends '_base.html' %}
{% block page_title %} Covid19 Statistics For All Countries {% endblock %}
{% block content %}
<h3 class="text-center">Covid19 Statistics For All Countries </h3>
{% for object in my_new_list %}
<div class="row justify-content-center">
<div class="col-sm-10 d-flex justify-content-center">
<div class="card text-dark text-center" style="width: 20rem;">
<div class="card-block card-body">
<form method="POST" action="">
{% csrf_token %}
<h5 class="card-header" name="country">Country: {{object.Country}}, {{object.CountryCode}}</h5>
<br>
<p class="card-text">Total Confirmed Cases: {{object.TotalConfirmed}} </p>
<p class="card-text">Total Deaths Cases: {{object.TotalDeaths}} </p>
<p class="card-text">Total Recovered Cases: {{object.TotalRecovered}} </p>
<p class="card-text" name="date">Date: {{object.Date}}</p>
<button class="btn btn-success" type="submit">ADD TO MY RECORDS </button>
</form>
</div>
</div>
<br>
</div>
</div>
{% endfor %}
{% endblock %}
You can use the following ajax snippet to send data in the backend:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
<script>
$.ajax({
type: 'POST',
url: 'url', #leave blank if URL is same as the current one
data: {
'country': 'county_name',
'date': 'date_value',
},
success: function(response) {
# depending upon the response from the server you can make an alert here.
},
error: function(response){
# If some error occurred on the backend you can show error message from here
}
});
</script>

For loop inside a IF condition to show right category on django template

I'm trying to show the correct articles in the category section using an if condition with a for loop inside, so far I'm displaying all the articles and not the only ones that supposed to be in the category.
home.html screeenshot
home.html
{% if articles.category == Sports %}
{% for article in articles %}
<div class="position-relative">
<img class="img-fluid w-100" src="{{article.cover.url}}" style="object-fit: cover;">
<div class="overlay position-relative bg-light">
<div class="mb-2" style="font-size: 13px;">
{{article.title}}
<span class="px-1">/</span>
<span>{{article.created_at}}</span>
</div>
<a class="h4 m-0" href="">{{article.description}}</a>
</div>
</div>
{% endfor %}
{% endif %}
views.py
def home (request):
cats = Category.objects.all()
articles = Article.objects.filter( is_published=True).order_by('-category')
return render (request,'pages/home.html',
context={
'cats': cats,
'articles': articles
})
Instead of hardcoding it like that, you could let the users search for categories with something like this:
articles = Article.objects.filter(category__icontains=q).values('title')
where q would be the user input in the form.

Django: objects are not showing at index page

This is my first project with Django and I got a problem. In the backend I created news, but I have an issue displaying the news on the frontpage. Models should be fine since I can create news into the admin panel. But I can't figure out where is my mistake.
I have app 'pages'>views.py
from django.shortcuts import render, redirect, get_object_or_404
from mainnews.models import Mainnews
# Create your views here.
def home_view(request):
main = Mainnews.objects.all()
context = {
'main' : main
}
return render(request, 'index.html', context)
root>urls.py
from pages.views import home_view
urlpatterns = [
path('admin/', admin.site.urls),
path('', home_view, name = 'home'),
]
and app mainnews>views.py
from django.shortcuts import render, get_object_or_404
from .models import Mainnews
# Create your views here.
def index(request):
main = Mainnews.objects.all()
context = {
'main' : main
}
return render(request, 'index.html', context)
and the template mainnewsandevents.html that extends to index
{% block content %}
<!-- Section 2 News and Events -->
<div id="news-container">
<div class="jumbo-news">
<img id = 'jumboImgUrl' class='jumbo-img' src="{{ main.image.url }}">
<h2 id = 'jumboTitle' class='jumbo-title'>{{ main.title }}</h2>
<h4 id = 'jumboDescription' class='jumbo-parag'>{{ main.description }}</h4>
</div>
{% endblock %}
Fix it like this:
def home_view(request):
main = Mainnews.objects.first()
# or main = Mainnews.objects.last()
# other code
or if you need to show all objects on your template use something like it:
{% block content %}
<!-- Section 2 News and Events -->
<div id="news-container">
<div class="jumbo-news">
{% for article in main %}
<img id = 'jumboImgUrl' class='jumbo-img' src="{{ main.image.url }}">
<h2 id = 'jumboTitle' class='jumbo-title'>{{ main.title }}</h2>
<h4 id = 'jumboDescription' class='jumbo-parag'>{{ main.description }}</h4>
{% endfor %}
</div>
{% endblock %}
Depends on your needs.
Also you shouldn't use not obvious names for variables so you shall use main_news instead of main.
main is an array of objects right so you need a for loop to get every object
{% block content %}
<!-- Section 2 News and Events -->
<div id="news-container">
<div class="jumbo-news">
{% for obj in main %}
<img id = 'jumboImgUrl' class='jumbo-img' src={{ obj.image.url }}>
<h2 id = 'jumboTitle' class='jumbo-title'>{{ obj.title }}</h2>
<h4 id = 'jumboDescription' class='jumbo-parag'>{{ obj.description }}</h4>
{% endfor %}
</div>
{% endblock %}

redirecting with primary key from views.py

I have a view
(user_list.html)
{% extends "base.html" %}
{% load static %}
{% block content %}
<div class="list_main">
<div class="container">
{% for user in user_list %}
<ul>
<li><a href="{% url 'myapp:detail' pk=user.pk %}">
<div class="jumbotron">
<h4 class="list_content">{{user.name}}</h4>
</div>
</a></li>
</ul>
{% endfor %}
<div class="bttn">
<p><a type="button" class="btn btn-primary" href="{% url 'myapp:user' %}">Add</a></p>
</div>
</div>
</div>
{% endblock %}
Here with the help of
<p><a type="button" class="btn btn-primary" href="{% url 'myapp:user' %}">Add</a></p>
I am calling (views.py --> UserView)
def UserView(request):
response = requests.get('https://randomuser.me/api')
data = response.json()
title = data['results'][0]['name']['title']
first = data['results'][0]['name']['first']
last = data['results'][0]['name']['last']
final_name = " ".join([first,last])
#############################################
final_name = ". ".join([title, final_name]) #Final name of the user
#############################################
agee = data['results'][0]['dob']['age'] # age of the user
user = UserData.objects.create( name = final_name, age= agee, gender = gender)
user.save()
return redirect('detail', pk=user.pk) #This is not working
what I want to do is whenever the button from template (user_list.html) is clicked.
I want to enter this function in my views.py file perform the operations and redirect to
(path('detail/<int:pk>/', views.UserDetailView.as_view(), name='detail'),)
My views.UserDetailView
class UserDetailView(DetailView):
model = UserData
context_object_name = 'user_detail'
template_name = 'user_detail.html'
As shown in the code in( UserView(request) ), I have tried "return redirect('detail', pk=user.pk) "
this does not work.
Also please tell me if there is more neat and efficient way available to perform operations present in
( UserView(request) ) when button is clicked in ( user_list.html ) and then redirect from "UserView" to ((path('detail//', views.UserDetailView.as_view(), name='detail'),))
You missed app name myapp when using redirect:
return redirect('myapp:detail', pk=user.pk)

Reverse for 'user_review_list' not found. 'user_review_list' is not a valid view function or pattern name

Even after going through similar STACKOVERFLOW solutions this doubt was not solved.
I have also been through other resources.
Been engaged in django since 2 days only !! :)
project -> winerama
app ->reviews
my views.py
def review_list(request):
latest_review_list =Review.objects.order_by('-pub_date')[:9]
context ={'latest_review_list': latest_review_list}
return render(request, 'reviews/review_list.html',context)
def wine_list(request):
wine_list =Wine.objects.order_by('-name')
context ={'wine_list':wine_list}
return render(request, 'reviews/wine_list.html',context)
def review_detail(request , review_id):
review = get_object_or_404(Review , pk = review_id)
context = {'review':review}
return render(request,'reviews/review_detail.html',context)
def wine_detail(request , review_id):
wine = get_object_or_404(Wine, pk = wine_id)
context = {'wine':wine}
return render(request,'reviews/wine_detail.html',context)
def add_review(request,wine_id):
wine = get_object_or_404(Wine , pk = wine_id)
form = ReviewForm(request.POST)
if form.is_valid():
rating = form.cleaned_data['rating']
comment = form.cleaned_data['comment']
user_name=form.cleaned_data['user_name']
review =Review()
review.wine = wine
review.user_name = user_name
review.user_name = user_name
review.rating =rating
review.comment = comment
review.pub_date = datetime.datetime.now()
review.save()
return HttpRespponseRedirect(reverse('reviews:wine_detail',args = (wine.id,)))
return render(request,'reviews/wine_detail.html',{'wine':wine,'form':form})`
reviews/urls.py
urlpatterns = [
# ex: /
url(r'^$', views.review_list, name='review_list'),
# ex: /review/5/
url(r'^review/(?P<review_id>[0-9]+)/$', views.review_detail, name='review_detail'),
# ex: /wine/
url(r'^wine$', views.wine_list, name='wine_list'),
# ex: /wine/5/
url(r'^wine/(?P<wine_id>[0-9]+)/$', views.wine_detail, name='wine_detail'),
url(r'^wine/(?P<wine_id>[0-9]+)/add_review/$', views.add_review, name='add_review'),
]
reviews/templates/reviews/base.html
{% block bootstrap3_content %}
<div class="container">
<nav class="navbar navbar-default">
<div class="navbar-header">
<a class="navbar-brand" href="{% url 'review_list' %}">Winerama</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li>Wine list</li>
<li>Home</li>
</ul>
</div>
</nav>
<h1>{% block title %}(no title){% endblock %}</h1>
{% bootstrap_messages %}
{% block content %}(no content){% endblock %}
</div>
{% endblock %}
THANKS IN ADVANCE.
PLEASE HELP ME FOR THE SAME.
The error is self explanatory:
Somewhere in your template html you have written
{% url 'user_review_list' %}
That means you are calling user_review_list function, but it is not defined in views. Instead you have defined review_list function.