obtain django dropdown menu item queryset - django

I am trying to make a calendar html page, that has a dropdown button to select the different months. How to get to this calendar page is via the nav bar that is created at base.html
base.html - how to get to the calendar page.
....
....
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" data-toggle="dropdown" data-target="scheduler_dropdown" href="#"><i class="fas fa-calendar"></i>Scheduler</a>
<div class="dropdown-menu" aria-labelledby="scheduler_dropdown">
<a class="dropdown-item" href="{% url 'view_schedule' %}"><i class="fas fa-calendar-alt"></i>View Schedule</a>
</div>
</li>
what i've build so far:
urls.py
urlpatterns = [
path('schedule/view-schedule/', views.view_schedule, name='view_schedule'),
path('schedule/view-schedule/?query=month<str:selected_month>', views.view_schedule,
name='view_schedule_selected_month'),
]
Views.py
def view_schedule(request, selected_month=None):
if request.method == 'POST':
print('post')
else:
current_month = date.today().month
current_year = date.today().year
# a = request.GET # How to get query set from dropdown menu???
# print(a)
args = {
'month_cal': monthcalendar(current_year, current_month),
'month_name': calendar.month_name[current_month],
'year_name': current_year,
}
return render(request, 'static/html/view_schedule.html', args)
view_schedule.html
<div class="card-header">
Schedule for {{ month_name }} {{ year_name }}
<form class="date-selector" method="post">
{% csrf_token %}
<div class="dropdown">
<button class="btn dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="far fa-caret-square-down"></i>
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<a class="dropdown-item" href={% url 'view_schedule_selected_month' selected_month=1 %}>Jan</a>
<a class="dropdown-item" href={% url 'view_schedule_selected_month' selected_month=2 %}>Feb</a>
<a class="dropdown-item" href={% url 'view_schedule_selected_month' selected_month=3 %}>Mar</a>
</div>
</div>
</form>
</div>
My problem is that, when I click on the drop down button and select the relevant month Jan, Feb, Mar, the url changes, but in my views.py, the query set doesn't appear. So I can't extract the query for processing.
Any thoughts?

Turns out I could have just done print(selected_month) and it would print the query result.. I got the idea when I was watching this video: https://www.youtube.com/watch?v=qmxoGYCFruM

Don't use urlpatterns to handle query strings. urlpatterns handles only the URL itself; query parameters are part of the GET data and are handled within the callback method. You'll need to change the way your HTML, urlpatterns, and the view work to accommodate this.
urlpatterns = [
path('schedule/view-schedule/', views.view_schedule, name='view_schedule'),
]
In your HTML, you'll want a form with a dropdown that GETs the data to the URL above. You can use the select tag for this.
And then in the view, you can extract GET data from request.GET. Specifically, if you used the select tag as suggested above, then the user's choice will be in request.GET[NAME] where NAME is the name of the select tag.
There are other ways to go about this, depending on aesthetic preferences, etc., but the method I've explained above is likely to be the easiest.
Also, query set (or QuerySet) has a very specific meaning in Django. It refers to a type of object used in database queries as explained here. The results of an HTML form are not "query sets."

Related

django include template repeated in all url but get data from main url

i have one html template for my main body and in every url this main body is fixed. but the data from this fixed body is show only in main url or in one url
like this i have a inbox and number of message on it
inbox message number
in every url i have this message but in main url or view i send data to template for example if yo go to main url the number on inbox show but if you go to another url because the data is not in your view yo dont have number
how can i fix this !!?
or my question is how include template get data from special url in every url in django!?
No, Django does not provide any special URL concepts, But you can archive those things like this...
views.py
def navbar_counters(request):
a={'inbox':10,'mesages':20}
return a
def Oneview(request):
counters= navbar_counters(request)
context = {'counters':counters}
return render(request,'index.html',context)
def Twoview(request):
counters= navbar_counters(request)
context = {'counters':counters}
return render(re
quest,'page2.html',context)
index.html
{% block body %}
<h1>Page - 1</h1>
<div class="container-fluid mt-5 ">
<div>
{% for i,j in counters.items %}
<button type="button" class="btn btn-primary position-relative ms-5 ">
{{i}}
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger">
{{j}}+
</span>
</button>
{% endfor %}
</div>
</div>
{% endblock body %}
browser Output
NOTE - You need to call navbar_counters(request) function in every view function, I mean you need to call below code snippet in every views function.
counters= navbar_counters(request)
context = {'counters':counters}

Reverse for with no arguments not found for URL

I am attempting to create a view that allows users to delete a build log. On the view that shows the delete button with a link to the delete page I am getting the error
Reverse for 'build-log-delete' with no arguments not found. 1 pattern(s) tried: ['post/(?P<pk>[0-9]+)/build\\-log/(?P<pkz>[0-9]+)/delete$']
If I understand this error correctly its because I am not passing paramaters in the url.
<a class="delete-btn" href="{% url 'build-log-delete' %}">Delete</a>
However I do not understand why I need to pass parameters in the URL as I am not passing any new values into the URL and if so what parameters I would pass. Do I have to re pass the previous two?
urls
path('post/<int:pk>/build-log/<int:pkz>/', views.BuildLogDisplay, name='build-log-view'),
path('post/<int:pk>/build-log/<int:pkz>/delete', views.BuildLogDelete, name='build-log-delete') #error
views
def BuildLogDisplay(request, pk, pkz ):
post = BuildLog.objects.filter(post_id=pk)
log = BuildLog.objects.get(pk=pkz)
context = {
'post':post, 'log':log
}
return render(request, 'blog/buildlog.html', context)
def BuildLogDelete(request):
context = { }
return render(request, 'blog/BuildLogDelete.html', context)
full template
<div class="row">
<article class="cars-article">
<div class="flex">
<img class="rounded-circle article-img" src="{{ log.author.profile.image.url }}" />
<div>
<a class="article-title">{{ log.title }}</a>
</div>
</div>
<br>
<div>
{% if log.author == user %}
<a class="update-btn" href=""> Update</a>
<a class="delete-btn" href="{% url 'build-log-delete' %}">Delete</a>
{% endif %}
</div>
<hr class="solid">
<p class="article-content">{{ log.content | safe}}</p>
</article>
</div>
There are multiple errors in you code. You are not passing args in BuildLogDelete view but in url you are using those arguments. So the correct view should look like this.
def BuildLogDelete(request,pk,pkz):
# delete code
# write here
Next mistake which i can see is you are assigning queryset rather than object for the post key in BuildLogDisplay view. You should assign object.
post = BuildLog.objects.get(post_id=pk)
Lastly your original error mentioned in the question is because your build-log-delete url expects two arguments i.e pk and pkz but you haven't passed them in template. So it should be like this.
<a class="delete-btn" href='{% url "build-log-delete" pk=post.post_id pkz=log.pk %}'>Delete</a>
I would highly suggest you to look for already given generic views like ListView, TemplateView, CreateView, UpdateView and DeleteView. This will prevent you from reinventing the wheel
Ref: Django Class Based Generic Views

Django URL Page error when link is clicked twice

I have a url defined as:
path("home/projects/",project_view,name = "viewProject")
This render correctly when i click on the 'Details' link on project_view.html
<li>
<a href="projects" data-toggle="tooltip" class="tip-bottom" title="All Projects">
<i class="fa fa-list" aria-hidden="true">Details</i></a>
</li>
But while i am on the same page,if i click the same link again i get an error:
home/projects/ [name='viewProject']
"Page not found...The current path, home/projects/projects, didn't match any of these"
I understand what the error means,but how can i redirect the page to "home/projects/" if the link is clicked twice?
Instead of writing the url patterens you should use the django url template tag like this:
<a href="{% url 'viewProject' %}" data-toggle="tooltip" class="tip-bottom" title="All Projects">
<i class="fa fa-list" aria-hidden="true">Details</i></a>

Single page design - loading new content on link click

I'm working on a django webpage using single page design approach. Generally what I'm trying to achieve is to have some new content being loaded (picture gallery) to my main webpage after clicking certain links.
What I have already achieved is that the new content is being loaded on a link click but unfortunately it seems like the whole page is being reloaded and not rendered correctly. My current implementation is based on having main index.html template and extension template, both using {% block content %} relation.
views.py
def index(request):
categories = Category.objects.all().order_by('name')
return render(request, 'index.html', {'categories': categories})
def gallery(request, id):
category = Category.objects.get(id=id)
return render(request, 'gallery.html', {'category': category})
urls.py
urlpatterns = [
path('', views.index, name='index'),
path('view_gallery/<int:id>/', views.gallery, name='view_gallery')
]
index.html
<div class="collapse navbar-collapse" id="collapsibleNavbar">
<ul class="navbar-nav">
{% for category in categories%}
<li class="nav-item">
<a class="nav-link" href="{% url 'view_gallery' category.id %}">{{ category.name }}</a>
</li>
{% endfor %}
</ul>
</div>
<div>
{% block content %}
{% endblock %}
</div>
gallery.html
{% extends 'index.html' %}
{% block content %}
<p>{{ category.name }}</p>
{% endblock %}
I hope I have explained clearly what I'm trying to achieve. Could you please point me in the right direction?
Requests and page changes in single page sites work quite differently than those for normal web pages. Single page sites use JavaScript to change the page content rather than requesting a new page from the server. Single page sites can request content from the server, but generally that content is just data while the structure (HTML) of the page is decided by the client in JavaScript. The only time a full HTML page is sent by the server is on the initial request, which should be responded to with index.html.
In your example, you could have this work by adding a script that requests content from the server and modifies the DOM when a link is clicked.
For example:
const a1 = document.querySelector("a.link1");
const a2 = document.querySelector("a.link2");
a1.addEventListener("click", () => {
setContent("<p>Content from link 1</p>")
});
a2.addEventListener("click", () => {
setContent("<p>Content from link 2</p>")
});
function setContent(content) {
const contentDiv = document.querySelector("div.content");
contentDiv.innerHTML = content;
}
a {
text-decoration: underline;
color: blue;
}
a:hover {
cursor: pointer;
}
<h1>My Page</h1>
<a class="link1">link 1</a>
<a class="link2">link 2</a>
<div class="content">
</div>
And the click event callbacks could request content from your server instead of having the content hard-coded as in this example. Note that then the server should respond with just a snippet of HTML rather than an entire new page.
For example, you could use the following function to get content for the div.content element:
function fetchData() {
const response = fetch("/gallery");
return response;
}
If you're new to single page sites, you might checkout a framework like React, Vue, or Angular to get started and gain a better understanding or even use for this project.

Submitting button inside a form selenium + python

I have this form which contains a button with some dynamic value, when I click on it it should add the product to the checkout page.
Here is the html form :
{%for p in product %}
<div class="single-product">
<div class="product-f-image">
<img src="data:image/png;base64,{{p.image_medium}}" alt="">
<div class="">
{% if not user.is_authenticated %}
<form action="/login/">
<button class="add-to-cart-link" type="submit"> Add to cart</button>
</form>
{%else%}
<form id="form-id" action="" method="POST">
{% csrf_token %}
<button class="add-to-cart-link" type="submit" name="product" value="{{p.id}}" >
<input type="hidden" name="product_name" value="{{p.name}}">
<input type="hidden" name="product_price" value="{{p.lst_price}}">
Add to cart</button>
</form>
{%endif%}
<i class="fa fa-link"></i> See details
</div>
</div>
<h2>{{p.id}}</h2>
<div class="product-carousel-price">
<ins>{{p.lst_price}} €</ins>
</div>
</div>
{%endfor%}
And here is my what I am doing with selenium:
bon_commande = self.selenium.find_element_by_xpath("//button[#name='product' and #value='37']/parent::form")
bon_commande.submit()
And thanks for the help !
You don't need to locate Submit button to submit a form - use any element inside form or form element itself:
self.selenium.find_element_by_id("form-id").submit()
self.selenium.find_element_by_class_name("add-to-cart-link").submit()
Update
Try to wait until django variable "{{p.id}}" is replaced with generated value:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
WebDriverWait(self.selenium, 10).until(EC.presence_of_element_located((By.XPATH, "//button[#name='product' and #value='37']"))).submit()
Change to click the submit button:
// add some sleep to wait the JS files of page
// load completely to register click event to the submit button
// otherwise nothing to response to the click
// (because the `action` of the form is empty.)
self.selenium.sleep(15); // sleep 15 seconds
self.selenium.find_element_by_xpath("//button[#name='product' and #value='37']").click()
To click on the button with text as Add to cart you can use the following line of code :
self.selenium.find_element_by_xpath("//form[#id='form-id']/button[#class='add-to-cart-link' and #name='product']").submit()
#or
self.selenium.find_element_by_xpath("//form[#id='form-id']/button[#class='add-to-cart-link' and #name='product']").click()