Django - Reset all filters - django

I am trying to clear all filters on button click at once. This is what I have on filters.py file and filters class:
class Filters(django_filters.FilterSet):
id = django_filters.NumberFilter(label=_("ID"))
name = django_filters.TextFilter(label=_("Name"))
And in base template:
<form id="filters-filters-form" action="javascript:;" onsubmit="onSubmit(this)" class="form form-inline main-filter">
{% bootstrap_form filter.form layout='inline' %}
<div>
<button class="btn ml-auto mr-2" onclick="resetFilters()">Clear all</button>
{% trans "Apply" as button_text %}
{% bootstrap_button button_text button_class="btn-primary" %}
</div>
</form>
resetFilters() function:
var resetFilters = function() {
let formId = document.getElementById('filters-form')
let formChildren = formId.childNodes;
Array.from(formChildren).forEach(formChild => {
formChild.val(null).trigger('change')
});
}
Is there any easy way to reset all filters?
P.S: I need to reset these filters without any id of form-control because it will be reusable base template

you can just add a button and add the URL of your form :
<a class="btn ml-auto mr-2" href={<pass your URL here>} > Clear All </a>

Related

How Do You Trigger HTMX Page Refresh After User Updates Any Part of The Page?

I have been working with HTMX and it's pretty cool compared to the dreaded formsets and Javascript. I have it working....My only issue is when the user updates the form anywhere...you have to manually refresh the page to reset the list of todos. My issue is identical to this one...https://stackoverflow.com/questions/66664407/dynamically-update-table-when-creating-new-enty-using-htmx but there is no resolution listed.....
Here's a quick overview of my code...
My view...
def create_to_do(request):
user = User.objects.get(id=request.user.id)
to_dos = NewToDo.objects.filter(created_by=user)
form = ToDoForm(request.POST or None)
if request.method == "POST":
if form.is_valid():
to_do = form.save(commit=False)
to_do.created_by = user
to_do.creation_date = timezone.now()
to_do.save()
return redirect("MyToDoList:detail-to-do", pk=to_do.id)
else:
return render(request, "partials/to_do_form.html", {
"form":form
})
context = {
"form": form,
"user": user,
"to_dos": to_dos,
}
return render(request, "create_to_do.html", context)
Partial detailview....
<button class="button35" hx-get="{% url 'MyToDoList:update-to-do' to_do.id %}" hx-swap="outerHTML">
Update
</button>
<button class="button34" hx-post="{% url 'MyToDoList:delete-to-do' to_do.id %}" hx-swap="outerHTML">
Delete
</button>
</div>
Partial todo form....
<div hx-target="this" hx-swap="outerHTML" class="">
<form method="POST">
{% csrf_token %}
{% if to_do %}
<button class="button35" hx-post="{% url 'MyToDoList:update-to-do' to_do.id %}">
Save
</button>
<button class="button34" hx-get="{% url 'MyToDoList:detail-to-do' to_do.id %}">
Cancel
</button>
</div>
{% else %}
<button class="button35" hx-post=".">
Save
</button>
</div>
{% endif %}
</form>
</div>
My main create form html..
<button class="button36" hx-get="{% url 'MyToDoList:create-to-do-form' %}" hx-swap="beforeend" hx-target="#bookforms">Add Form</button>
<div id="bookforms" class=""></div>
<div class="">
{% if to_dos %}
{% for to_do in to_dos %}
{% include "partials/to_do_detail.html" %}
{% endfor %}
{% endif %}
After a day of playing and pulling my hair out..it's all working as I want...I just need to figure out how to incorporate a dynamic page load if anything changes so that the entire page gets reloaded....so that the records get sorted according to my number field...
Thanks in advance for any thoughts or suggestions.
So thanks to a kind soul on Facebook....I added this Javascript to my code and it works.
$(document).on("click", ".yourclass", function(){
location.reload();
});
In case you need this, I had the problem when I have to update two/mutliple parts of the page after post.
I manage to solve it by trigger_client_event
Thanks to this issue: How do I manually trigger a hx-get event of an element from JavaScript
HTMX rocks!

How to call a django function on click that doesn't involve changing page [duplicate]

My application currently flows through 3 pages:
User selects question in index page
User submits answer in answer page
User is presented with result in results page.
I want to compress that down to a single page where the user submits an answer to the question and result is shown on the same page.
The following django-template code separates questions with Bootstrap accordion. How do I post the form without refreshing the whole page? I want to be able to display the result on the page, update CSS styling with Javascript etc.
<h2>{{ category.title }}</h2>
<div class="accordion" id="accordion{{category.title}}">
{% for challenge in category.challenge_set.all %}
<div class="card">
<div class="card-header" id="heading{{challenge.id}}">
<h2 class="mb-0">
<button class="btn btn-link btn-block text-left" type="button" data-toggle="collapse" data-target="#collapse{{challenge.id}}" aria-expanded="true" aria-controls="collapse{{challenge.id}}">
{{ challenge.question_text }} - {{ challenge.point_value }} points
</button>
</h2>
</div>
<div id="collapse{{challenge.id}}" class="collapse in" aria-labelledby="heading{{challenge.id}}" data-parent="#accordion{{category.title}}">
<div class="card-body">
<p>{{ challenge.description }}</p>
<form action="{% url 'challenges:answer' challenge.id %}" method="post">
{% if challenge|is_answered:request %}
<label for="answered">Answer</label>
<input type="text" name="answered" id="answered" value="{{ challenge.answer_text }}" readonly>
{% else %}
{% csrf_token %}
<label for="answer">Answer</label>
<input type="text" name="answer" id="answer">
<input type="submit" value="Submit">
{% endif %}
</form>
</div>
</div>
{% endfor %}
</div>
Here is the view:
def index(request):
context = {'challenges_by_category_list': Category.objects.all()}
return render(request, 'challenges/index.html', context)
def detail(request, challenge_id):
challenge = get_object_or_404(Challenge, pk=challenge_id)
return render(request, 'challenges/detail.html', {'challenge': challenge})
def results(request, challenge_id, result):
challenge = get_object_or_404(Challenge, pk=challenge_id)
return render(request, 'challenges/results.html', {'challenge':challenge, 'result':result})
def answer(request, challenge_id):
challenge = get_object_or_404(Challenge, pk=challenge_id)
result = "Incorrect, try again!"
if challenge.answer_text.lower() == request.POST['answer'].lower():
current_user = request.user
session = User_Challenge(user=current_user, challenge=challenge, answered=True)
session.save()
points = Profile(user=current_user, points=challenge.point_value)
points.save()
result = "Correct!"
return HttpResponseRedirect(reverse('challenges:results', args=(challenge.id, result)))
You can try this:
Add the below script in your template:
<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
write a script and a function inside it to submit the form data.
<script type="text/javascript">
function submitData( challenge_id ){
// Get answer from the input element
var answer = document.getElementById("answer").value;
// add the url over here where you want to submit form & challenge_id is also taken as a parameter.
var url = "<your_url>";
$.ajax({
url: url,
data: {
'answer': answer,
},
dataType: 'JSON',
success: function(data){
// show an alert message when form is submitted and it gets a response from the view where result is provided and if url is provided then redirect the user to that url.
alert(data.result);
if (data.url){
window.open(data.url, '_self');
}
}
});
}
</script>
Change type of the submit button and add an onclick event to call the submitData() function and pass the challenge id to it. And remove the action attr from the form.
see below:
<form method="post">
{% csrf_token %}
{% if challenge|is_answered:request %}
<label for="answered">Answer</label>
<input type="text" name="answered" id="answered" value="{{ challenge.answer_text }}" readonly>
{% else %}
<label for="answer">Answer</label>
<input type="text" name="answer" id="answer">
// over here
<button type="button" onclick="submitData({{ challenge.id }})">
Submit
</button>
{% endif %}
</form>
Return a JsonReponse to the ajax call from the views.
views.py
def answer(request, challenge_id):
answer = request.GET.get('answer', False)
url = False
if challenge.objects.filter(id=challenge_id).exists() and answer:
challenge = Challenge.objects.get(id=challenge_id)
if challenge.answer_text.lower() == answer.lower():
current_user = request.user
session = User_Challenge(user=current_user, challenge=challenge, answered=True)
session.save()
points = Profile(user=current_user, points=challenge.point_value)
points.save()
result = "Correct!"
# specify the url where you want to redirect the user after correct answer
url = ""
else:
result = "Incorrect, try again!"
data = {
'result': result,
'url': url
}
return JsonResponse(data)

Checkbox inside the "for" (loop), Django

my checkbox html :
<form method="GET">
{% for subcategory in subcategories %}
<div class="filter-items filter-items-count">
<div class="filter-item">
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" value="{{subcategory.id}}" name="subcategory" id="{{subcategory.id}}" {% if subcategory in subcategories1 %} checked {% endif %}>
<label class="custom-control-label" for="{{subcategory.id}}">{{subcategory}}</label>
</div><!-- End .custom-checkbox -->
<span class="item-count">{{subcategory.products.all|length}}</span>
</div><!-- End .filter-item -->
</div><!-- End .filter-items -->
{% endfor %}
<button type="submit" class="btn btn-primary w-100 mt-3">Filter!</button>
</form>
it work correctly to make filter.
views :
subcatid = request.GET.getlist('subcategory')
query string:
?subcategory=5&subcategory=6
it can be one or more than one, depends on number of subcategories.
but when I go next page i suppose it become like :
?page=2&subcategory=5&subcategory=6
but it remove earliest subcategory i choose and keep the last one, just one, like :
?page=2&subcategory=5
acutely when i put Manually ?page=2&subcategory=5&subcategory=6 in url field it works but not from pagination buttons.
so while all checkboxes in filter has same names, name="subcategory" i made them unique by changing to name="{{subcategory}}", now each checkbox has unique name, now after tapping next page, Everything is kept, and there is no problem like before,
but in views, I don't know how to get them with deafferents names
subcatid = request.GET.getlist('subcategory')
You can add a QueryDict to the object that does not contain any page parameter with:
def subcategory(request, category_url):
# …
reqget = request.GET.copy()
reqget.pop('page', None)
ctx = {
# …
'reqget': reqget
}
return render(request, 'products/subcategory.html', ctx)
Then in the template, the links to go to the previous/next page will urlencode the reqget:
<a href="?page={{ products.previous_page_number }}&{{ reqget.urlencode }}" aria-label="Previous" tabindex="-1" class="page-link page-link-prev" aria-disabled="true">

return different queryset with different radio button in template in the same page django

I want to render different queryset when user click radio button without submitting the radio button input.
My models are these:
class A(models.Model):
name = models.CharField(max_length=10)
def get_a_list(self):
return self.b_set.filter(name__endswith='lorem')
def get_b_list(self):
return self.b_set.filter(name='blah')
class B(models.Model):
dept = models.ForeignKey(A, on_delete=models.CASCADE)
In template I can do something like this:
<ul>
{% for a in a.objects.all %}
{% for b in a.b_set.all %} <!-- instead of returning all I can do a.get_a_list or b.get_b_list -->
<li></li>
{% endfor %}
{% endfor %}
</ul>
If I have a group of radio buttons in the same template like this:
<div>
<input type="radio" id="a-list" value="a-list" name="filter">
<label for="a-list">a_list</label>
</div>
<div>
<input type="radio" id="b-list" value="b-list" name="filter">
<label for="b-list">b_list</label>
</div>
<div>
<input type="radio" id="all" value="all" name="filter">
<label for="all">all</label>
</div>
When user select a-list button, I want to call get_a_list, and for b-list button, get_b_list. I want to display the result without changing url.
I managed to get those different list by putting custom method in models class, but I'm lost. And I know I might lose some reputation for this question, for it might be so easy for somebody.
Any suggestion would be so grateful. Thank you in advance.
Something like:
template.html:
<div id='a_set'>
{% for a in a.objects.all %}
...
{% endfor %}
</div>
<div id='b_set'>
{% for b in a.b_set.all %}
...
{% endfor %}
</div>
script.js:
function change_sets() {
if ($('#a-list').is(':checked')) {
$('#a_set').show();
$('#b_set').hide();
}
else if ($('#b-list').is(':checked')) {
$('#a_set').hide();
$('#b_set').show();
}
}
$('#a-list').click(change_sets);
$('#b-list').click(change_sets);

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)