Create a vanilla JavaScript confirm delete modal when deleting a Django object - javascript

Most answers for this on Stack Overflow are written using Ajax and or jQuery. For an assignment I need it to be vanilla JS. This is what I have so far. Strangely I have a working delete button with a GET request method. Not a POST method as it normally would be. I'm not sure why and honestly got it working without the confirmation modal with trial and error.
This is what I have so far:
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.home, name='vgHome'), # relative path to VideoGames homepage
path('about/', views.about, name='vgAbout'), # relative path to VideoGames about page
path('news/', views.news, name='vgNews'), # realtive path to VideoGames news page
path('gallery', views.gallery, name='vgGallery'), # relative path to VideoGames gallery page
path('library/', views.library, name='vgLibrary'), # relative path to VideoGames user library
path('library/create', views.create_game, name='addGame'), # realative path to game create form
path('library/<int:game_id>/game_info', views.game_info, name='gameInfo'), # realative path to each games info page
path('library/<int:game_id>/update', views.update_game, name='updateGame'), # relative path to update selected game
path('library/<int:id>/delete', views.delete_game, name='deleteGame'), # relative path to delete selected game
]
views.py
from django.shortcuts import render, get_object_or_404, HttpResponseRedirect, redirect
from django.contrib import messages
from .forms import GameForm
from .models import Game
# Displays VideoGames app homepage
def home(request):
return render(request, 'VideoGames/videogames_home.html')
# Displays VideoGames about page
def about(request):
return render(request, 'VideoGames/videogames_about.html')
# Displays VideoGames news page
def news(request):
return render(request, 'VideoGames/videogames_news.html')
# Displays VideoGames gallery page
def gallery(request):
return render(request, 'VideoGames/videogames_news.html')
# Displays VideoGames user library page
def library(request):
games_list = Game.objects.all()
context = {
'games_list': games_list,
}
return render(request, 'VideoGames/videogames_library.html', context)
# Displays each games details page, linked from library
def game_info(request, game_id):
game = get_object_or_404(Game, pk=game_id)
return render(request, 'VideoGames/game_details.html', {'game': game})
def create_game(request):
if request.method == 'POST':
form = GameForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, 'Game successfully added!')
return redirect('vgLibrary')
else:
messages.error(request, 'Please fix fields with errors!')
else:
form = GameForm()
return render(request, 'VideoGames/game_form.html', {'form': form})
def update_game(request, game_id):
game = get_object_or_404(Game, pk=game_id)
form = GameForm(request.POST or None, instance=game)
context = {'form': form}
if form.is_valid():
form.save(commit=False)
form.save()
messages.success(request, 'Game successfully updated!')
return redirect('vgLibrary')
return render(request, 'VideoGames/game_update.html', context)
def delete_game(request, id=None):
game = get_object_or_404(Game, id=id)
if request.method == 'GET':
game.delete()
messages.success(request, 'Game successfully deleted!')
return redirect('vgLibrary')
else:
return render(request, 'VideoGames/game_details.html', {'game': game})
Template where delete button is located (game_details.html)
{% extends 'VideoGames/videogames_base.html' %}
{% load staticfiles %}
{# Page/Tab Title #}
{% block title %}Video Games | Library | {{ game.game_title }}{% endblock %}
{# Using parent stylesheet + adding page specific css file as well #}
{% block stylesheets %}
{{ block.super }}
<link rel="stylesheet" type="text/css" href="{% static 'VideoGames/css/vg_details.css' %}">
{% endblock %}
{# Homepage background image #}
{% block pagetop-css %}{% endblock %}
<!-- Showcase text for homepage -->
{% block page-title %}<h1>{{ game.game_title }}</h1>{% endblock %}
{% block page-subtitle %}{%endblock %}
{% block appcontent %}
<h4 class="info-head">Developer</h4>
<ul class="details">
<li>{{ game.game_developer }}</li>
</ul>
<h4 class="info-head">Release Date</h4>
<ul class="details">
<li>{{ game.game_release }}</li>
</ul>
<h4 class="info-head">Your Rating</h4>
<ul class="details">
<li>{{ game.rating }}</li>
</ul>
<h4 class="info-head">Genre</h4>
<ul class="details">
<li>{{ game.game_genre }}</li>
</ul>
<h4 class="info-head">Platform</h4>
<ul class="details">
<li>{{ game.game_platform }}</li>
</ul>
{% endblock %}
{% block button1 %}Update{% endblock %}
{% block button2 %}Delete
{% endblock %}
{% block button3 %}Library{% endblock %}
{% block javascript %}
{{ block.super }}
<script>
function myFunction() {
window.confirm("Do you really want to delete {{ game.game_title }} from your library?")
}
</script>
{% endblock %}
As you can see from the template I am just using a basic confirm function to give some sort of confirmation, but that doesn't even work as if I click cancel it still goes through. My guess is it has something to do with the delete view using a GET method instead of a Post method.

window.confirm returns a Boolean indicating whether the user clicked confirm. This value is false if the user clicked cancel. You need to only open deleteGame if the user confirmed.
function myFunction() {
if (window.confirm("Do you really want to delete {{ game.game_title }} from your library?")) {
window.location.href="{% url 'deleteGame' game.id %}";
}
}

Related

What do I need to do if I want to use database data conditionally in Django templates?

I am working on an ecommerce store in Django. I want to know that how do I use the database data passed to templates using render() method, conditionally through JavaScript or AJAX or JSON?
For example, let's say I have a following models.py:
from django.db import models
class Suit(models.Model):
title = models.CharField(max_length = 100, verbose_name = "Title")
img = models.FileField(upload_to = 'suit-products/', null = True, verbose_name = "Picture")
def __str__(self):
return f"{self.title}"
class Buttoning(models.Model):
title = models.CharField(max_length = 100, verbose_name = "Title")
img = models.FileField(upload_to = 'buttonings/', null = True, verbose_name = "Picture")
def __str__(self):
return f"{self.title}"
and following views.py
from django.shortcuts import render
def index(request):
suit_prods = Suit.objects.all()
buttoning = Buttoning.objects.all()
context {
"suit_prods": suit_prods,
"buttoning": buttoning
}
return render(request, "index/index.html", context)
and following index.html (template):
{% for element in suit_prods %}
<li>
<a href="#">
<div id="menu">
<img src="{{ element.img.url }}" />
<span>{{ element.title }}</span>
<span></span>
</div>
</a>
</li>
{% endfor %}
Now what I want is, if the clicked element in the list items in index.html has the title as "two_piece_suit" then show items of {{ buttoning }} as a list, otherwise pass.
If I explain it more using some JS syntax, then I want following kind of behaviour:
<scrip>
var suit_menu = document.getElementsByClassName("menu");
for(var i = 0; i < suit_menu.length; i++) {
if(suit_menu.text == "two_piece_suit") {
{% for element in buttoning %}
<li>
<a href="#">
<div id="buttoning">
<img src="{{ element.img.url }}" />
<span>{{ element.title }}</span>
<span></span>
</div>
</a>
</li>
{% endfor %}
}
}
</script>
If I understand correctly, you don't necessarily need JavaScript to achieve this. Also, <script> is missing a t, and your for loop doesn't seem to add the HTML to the document at all.
You can achieve that purely with the Django Template Language by integrating the buttons for loop with an if condition like this:
{% if element.title == 'two_piece_suit' %}
{% for button in buttoning %}
<Some HTML>{{ button.title }}</Some HTML>
{% endfor %}
{% endif %}
That way, the list of buttons is only displayed if the title is two_piece_suit.

How to pass some data to Django views.py?

I want send product id to my views.
Templates
<div class="products__header--search-result">
<ul>
{% for product in products %}
<li onclick="change('{{ product.id }}')">{{ product.name }}</li>
{% endfor %}
</ul>
</div>
<script>
function change(foo) {
$.ajax({
url: {% url 'dashboard' %},
data: {
'foo': foo,
},
});
}
</script>
views.py
myRequets = request.GET.get('foo')
But myRequets return 'None'
How can I fix this?
Is there a better way to pass values to views.py?
You don't need JS to do this because Django allows parameters in urls:
# URLconf
from django.urls import path
from . import views
urlpatterns = [
path('product/', views.product),
path('product/<int:product_id>/', views.product),
]
views.py
# View (in product/views.py)
def product(request, product_id=None):
products = None
if product_id:
# Output the appropriate page of product entry, according to product_id.
return ...
# Output the appropriate page when product_id is None
return ...
Source:
https://docs.djangoproject.com/en/3.2/topics/http/urls/#example (adapted)
Then in your template:
{% if products %}
<div class="products__header--search-result">
<ul>
{% for product in products %}
<li>{{ product.name }}</li>
{% endfor %}
</ul>
</div>
{% endif %}

Django-bootstrap-datepicker-plus is not rendering datepicker properly

I am facing with the problem that my datetimepicker is not loading at all.
Just in my template, the datetime field loads the current date and time when i press the calendar icon as the image shows.
Despite following the installation steps from here : https://pypi.org/project/django-bootstrap-datepicker-plus/ and checking other answers in stackoverflow i did not manage to find the solution.
I think the problem has to do with the imports and their priority.
my template
{% extends 'base.html' %}
{% load render_table from django_tables2 %}
{% load bootstrap4 %}
{% bootstrap_css %}
{% bootstrap_javascript jquery='full' %}
{% block page-title %}Creation of Process Note{% endblock %}
{% block content %}
<div class="row">
<div class="col-md-6 col-xl-6 offset-md-3">
<form class="well" method="post" action="">
{% csrf_token %}
{% bootstrap_form form %}
<br>
{% buttons %}
<button type="submit" class="btn btn-primary">
Submit
</button>
{% endbuttons %}
</form>
{{ form.media }}
</div>
</div>
{% endblock %}
in settings.py
BOOTSTRAP4 = {
'include_jquery': True,
}
In my base.html the appearence of the imports is:
Inside head
<link href="/static/theme/assets/css/bootstrap.min.css" rel="stylesheet" type="text/css">
<script src="/static/theme/assets/js/jquery.min.js"></script>
...
Inside footer
<script src="/static/theme/assets/js/bootstrap.bundle.min.js"></script>
...
my model
class Case_Notes(models.Model):
date_created = models.DateTimeField("Creation Date", null=True,blank=True, default=datetime.datetime.now)
date = models.DateTimeField("Appointment Date", null=True,blank=True)
notes = models.CharField("Notes",max_length=500, blank=True, null=True)
def __str__(self):
return self.notes
my form
class ProcessNotesForm(ModelForm):
notes= CharField(required=False,widget=Textarea(attrs={"rows":5, "cols":20}))
class Meta:
model = Case_Notes
fields = ("date","notes",)
widgets = {
'date': DateTimePickerInput(), # default date-format %m/%d/%Y will be used
}
Why datepicker widget in the form field is not rendering?
According to the documentation, the {{ form.media }} needs to follow right under the {% bootstrap_javascript jquery='full' %} in your template file.
{% load bootstrap4 %}
{% bootstrap_css %}
{% bootstrap_javascript jquery='full' %}
{{ form.media }}
Addition to {{ form.media }} you use tuple instead of an array in the fields Meta in the ModelForm:
class ProcessNotesForm(ModelForm):
notes= CharField(required=False,widget=Textarea(attrs={"rows":5, "cols":20}))
class Meta:
model = Case_Notes
fields = ["date", "notes" ] # change this ("date","notes",)
widgets = {
'date': DateTimePickerInput(), # default date-format %m/%d/%Y will be used
}

Django: Jquery click function not working in Ajax

I have been working through the Tango with Django exercises to cut my teeth into Django. Almost done but having a problem with the Ajax part.
Ajax function to auto_add a page is not being called. Idk what the problem is since the other functions are being called.
On the shell prompt, there is no call to the ajax function at all. Help needed.
Pertinent code attached. It is the same as on the website link above.
static/rango-ajax.js
$('.rango-add').click(function(){
var catid = $(this).attr("data-catid");
var title = $(this).atrr("data-title");
var url = $(this).attr("data-url");
$.get('/rango/auto_add_page/', {category_id: catid, url: url, title: title}, function(data){
$('#pages').html(data);
me.hide();
});
});
templates/rango/category.html
{% if user.is_authenticated %}
<button data-catid="{{category.id}}" data-title="{{ result.title }}" data-url="{{ result.link }}" class="rango-add btn btn-mini btn-info" type="button">Add</button>
{% endif %}
rango/views.py
#login_required
def auto_add_page(request):
context = RequestContext(request)
cat_id = None
url = None
title = None
context_dict = {}
if request.method == 'GET':
cat_id = request.GET['category_id']
url = request.GET['url']
title = request.GET['title']
if cat_id:
category = Category.objects.get(id=int(cat_id))
p = Page.objects.get_or_create(category=category, title=title, url=url)
pages = Page.objects.filter(category=category).order_by('-views')
#Adds our results list to the template context under name pages.
context_dict['pages'] = pages
return render_to_response('rango/page_list.html', context_dict, context)
rango/urls.py
urlpatterns = patterns('',
url(r'^$', views.index, name='index'),
url(r'^goto/$', views.track_url, name='track_url'),
url(r'^add_category/$', views.add_category, name='add_category'),
url(r'^auto_add_page/$', views.auto_add_page, name='auto_add_page'),
Complete code is at this link.
your code is good, the only thing what you have to do is to define your template in /tango/templates/rango/page_list.html. This template have the following code:
{% if pages %}
<ul>
{% for page in pages %}
<li>
{{ page.title}}
{% if page.views > 1 %}
({{page.views}} views)
{% elif page.views == 1 %}
({{page.views}} view)
{% endif %}
</li>
{% endfor %}
</ul>
{% else %}
<strong> No Pages currently in category. </strong>
{% endif %}
And inside of your category template you must define the following code:
% if category %}
{% if user.is_authenticated %}
Add a new Page <br>
{% endif %}
{% if pages %}
<div id="pages">
<ul>
{% for page in pages %}
<li>
{{ page.title}}
{% if page.views > 1 %}
({{page.views}} views)
{% elif page.views == 1 %}
({{page.views}} view)
{% endif %}
</li>
{% endfor %}
</ul>
</div>
{% else %}
<strong> No Pages currently in category. </strong>
{% endif %}
{% else %}
The specified category {{ category_name }} does not exist!
{% endif %}
I'm working through this section of the tutorial now and just want to add to Héctor's answer. To avoid duplicating the code to display the list of pages I did the following:
I added a get_page_list() method to tango/rango/templatetags/rango_extras.py, similar to the get_category_list() method used to display a list of categories in an earlier section of the tutorial.
from rango.models import Page
#register.inclusion_tag("rango/page_list.html")
def get_page_list(category):
pages = Page.objects.filter(category=category) if category else []
return {'pages': pages}
Then we just need to load rango_extras and call the get_page_list() method in tango/templates/rango/category.html.
{% extends 'rango/base.html' %}
{% load rango_extras %}
<!-- Existing code -->
{% if category %}
<!-- Existing code to show category likes and like button -->
<div id="page_list">
{% get_page_list category %}
</div>
<!-- Existing code to show search if user is authenticated -->
{% else %]
The specified category {{ category_name }} does not exist!
{% endif %}
This allows you to display the list of pages when a category page is first loaded and then refresh it if a category is added from the search area, without having to duplicate any code.

Django Infinite scroll using Django Paginate repeating the queryset

Intro: I am using the the below link to add infinite scroll to my project https://simpleisbetterthancomplex.com/tutorial/2017/03/13/how-to-create-infinite-scroll-with-django.html
below is the github code for that link
https://github.com/sibtc/simple-infinite-scroll
The link shows how to add infinite scroll to both function based views and class based views. I have added this to my function based view and it works perfect.
The problem: I have 8 posts in my post-list which is a class-based view. After I add paginate_by = 3 I can only see 3 posts of the 8 posts. Everytime I scroll down these 3 posts keep repeating in an infinite loop
My Views:
class Postlist(SelectRelatedMixin, ListView):
model = Post
select_related = ('user', 'group')
paginate_by = 3
context_object_name = 'post_list'
template_name = 'posts/post_list.html'
def get_queryset(self):
queryset = super(Postlist, self).get_queryset().order_by('-created_at')
query = self.request.GET.get('q')
if query:
queryset = queryset.filter(
Q(title__icontains=query)|
Q(user__username__iexact=query)|
Q(user__first_name__iexact=query)|
Q(user__last_name__iexact=query)
)
return queryset
My Base.html: (I have the below files in JS folder they worked for my FBV)
<script src="{% static 'js/jquery-3.1.1.min.js' %}"></script>
<script src="{% static 'js/jquery.waypoints.min.js' %}"></script>
<script src="{% static 'js/infinite.min.js' %}"></script>
{% block javascript %}{% endblock %}
My post_list.html:
<div class="col-md-8">
<div class="infinite-container">
{% for post in post_list %}
<div class="infinite-item">
{% include "posts/_post.html" %} <!---This code is good---->
</div>
{% empty %}
some code
{% endfor %}
</div>
<div class="loading" style="display: none;">
Loading...
</div>
{% if page_obj.has_next %}
<a class="infinite-more-link" href="?page={{ post_list.next_page_number }}">More</a>
{% endif %}
</div>
{% block javascript %}
<script>
var infinite = new Waypoint.Infinite({
element: $('.infinite-container')[0],
onBeforePageLoad: function () {
$('.loading').show();
},
onAfterPageLoad: function ($items) {
$('.loading').hide();
}
});
</script>
{% endblock %}
In the templates I replaced post_list with page_obj see below code. That did it
{% if post_list.has_next %}
<a class="infinite-more-link" href="?page={{page_obj.next_page_number }}">More</a>
{% endif %}

Categories

Resources