I'm new in Django and I'm creating a CRUD. However I want to show a Success message in a Toast for successfully submit, but I don't know how to do it exactly.
The view class once is inserted, redirect correctly to List, but no messages showed.
This is my view class
class AlmacenesCreateView(SuccessMessageMixin, CreateView):
model = Almacen
form_class = AlmacenesForm
template_name = 'pages/create.html'
success_url = reverse_lazy('almacenes')
success_message = "Bien!!!!"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['title'] = "New Almacen"
return context
And this is the script for the toast
$(function () {
let mensaje ="{{ messages.0 }}";
const Toast = Swal.mixin({
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 3000
});
if (mensaje != "") {
Toast.fire({
icon: 'success',
title: mensaje,
})
}
});
My doubt is how I can show the success message
You have to loop over messages and then print icon accordingly
{% for message in messages %}
<script>
$(function () {
let mensaje ="{{ message }}";
const Toast = Swal.mixin({
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 3000
});
if (mensaje != "") {
Toast.fire({
icon: "{% if message.tags %}{{ message.tags }}{% endif %}",
title: mensaje,
})
}
});
</script>
{% endfor %}
You can even consider using things like this
Swal.fire({
title: "Thank you?",
text: "success message here",
type: "success",
showCancelButton: true,
confirmButtonColor: "#DD6B55",
confirmButtonText: "Yes, delete it!",
closeOnConfirm: false
}, function() {
swal("Successful!", "success message here", "success");
});
});
Did you follow the documentation here and there :
In your template, use something like:
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
Then you can check in your console if you don't have any Javascript errors for your code. I've never used Swal library.
Related
Trying to keep selected icon in product cards active after page refresh
when the user refresh the page I want that the icon to remain a full heart and not an empty heart. How could I do that?
views.py
#login_required
def add_wishlist (request):
if request.is_ajax() and request.POST and 'attr_id' in request.POST:
if request.user.is_authenticated:
data = Wishlist.objects.filter(customer = request.user,product_id= int(request.POST['attr_id']))
if data.exists():
data.delete()
else:
Wishlist.objects.create(customer= request.user,product_id = request.POST['attr_id'])
else:
print("No Product is Found")
return redirect("products:product_all")
product_all.html
<div id='alCarrito' class="like-container">
{% if product in wishlisted_list %}
<span class="like heart " id="id" attr_id="{{product.id}}" action_url="{% url 'products:add_wishlist' %}">
<i class="fas fa-heart"></i> </span>
{% else %}
<span class="like" id="id" attr_id="{{product.id}}" action_url="{% url 'products:add_wishlist' %}"><i class="far fa-heart"></i></span>
{% endif %}
</div>
wishlist.js
$(document).ready(function(){
$(".like").click(function(){
var attr_id = $(this).attr('attr_id')
var action_url = $(this).attr('action_url')
var that = $(this)
$.ajax({
url: action_url,
type: "POST",
data: {'attr_id': attr_id },
headers: { "X-CSRFToken": $.cookie("csrftoken") },
success: function (response) {
console.log("Success")
that.toggleClass("heart");
},
});
});
});
On site exists form where users able to comment products. Comments are connected with products. jQuery is used from Bootstrap base.html (it's worked with another ajax-call). I'm fighting with ajax comment during the week). Trying to do it only for one product to understand how it works. Without ajax system of comments works fine, but I decided to add smooth in comment add without refreshing of the page and I do task with POST and ajax for the first time (before I did two pretty simple examples with get and form reset after successful response to ajax from back-end). Could somebody advice what should be add in template and view ? I suppose problem is connected with my poor knowledge of js.
I am using
is_ajax = request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest'
because this is working with django 4.0, and old function is_ajax() was removed.
views.py
def ajax_test(request):
product = Product.objects.get(id=4)
comments = product.comment_set.order_by('-created_at')
form = UserCommentForm
context = {'product':product,'comments':comments,'form': form}
return render(request, 'store/ajax_test.html', context)
def ajax_receiver(request):
is_ajax = request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest'
if request.method == 'POST' and is_ajax:
product = Product.objects.get(id=4)
form = UserCommentForm(data=request.POST)
user = Comment.objects.get(author=user)
if form.is_valid() and request.user.is_authenticated:
new_comment = form.save(commit=False)
new_comment.author = request.user
new_comment.product = product
new_comment.save()
comment_info = {
"author": new_comment.author,
"new_comment": new_comment.content,
"created_at": new_comment.created_at,
}
return JsonResponse({"comment_info": comment_info}, status=200)
else:
return JsonResponse({"success": False}, status=400)
template
{% extends "store/base.html" %}
{% load bootstrap4 %}
{% block page_header %}
<h1>тестирую аякс</h1>
{% endblock page_header %}
{% block content %}
<div class="container">
<div class="row py-3">
<div class="col-3 order-2" id="sticky-sidebar">
<div class="sticky-top">
<form id="UserCommentForm" method='post' class="form">
{% csrf_token %}
{% bootstrap_form form %}
{% buttons %}
<button name="submit" class="btn btn-primary" name="comment">Добавить комментарий</button>
{% endbuttons %}
</form>
</div>
</div>
<div class="col" id="main">
<h3>Комментарии:</h3>
{% for comment in comments %}
<h6 class="card-header">
{{ comment.author }}<small> добавлен {{ comment.created_at|date:'M d, Y H:i' }} </small>
</h6>
<div class="card-body">
<h4>{{ comment }}</h4>
<form action="" method="POST">
{% csrf_token %}
</form>
</div>
{% empty %}
<p>Для данного товара ещё нет комментариев.</p>
{% endfor %}
</div>
</div>
</div>
{% block javascript %}
<script type="text/javascript">
$(document).ready(function(){
$("#UserCommentForm").submit(function(e) {
// prevent from normal form behaviour
e.preventDefault();
// serialize the form data
var serializedData = $(this).serialize();
$.ajax({
type : 'POST',
url : "{% url 'store:ajax_receiver' %}",
data : serializedData,
success : function(response){
??? what should be there to post ???
},
error : function(response){
console.log(response)
}
});
});
});
</script>
{% endblock javascript %}
{% endblock content %}
Finally I found the decision, it's just to reload block of comments without refreshing, there is the code, the space before ' #main' is important!:
<script type="text/javascript">
$(document).ready(function(){
$("#UserCommentForm").submit(function(e){
// prevent from normal form behaviour
e.preventDefault();
// serialize the form data
var serializedData = $(this).serialize();
$.ajax({
type : 'POST',
url : "{% url 'store:ajax_receiver' %}",
data : serializedData,
success : function(response){
$('#main').load(' #main', function(){
/// can add another function here
});
$("#UserCommentForm")[0].reset();
},
error : function(response){
console.log(response)
}
});
});
});
</script>
In your ajax success write the following code to show new comment:
let comment_info = response["comment_info"];
let author = comment_info["author"];
let comment = comment_info["comment"];
let created_at = comment_info["created_at"];
html = "<h6 class='card-header'> "+author+"</h6>"
// i have writting only part of html write the full just like you do when you show comments
$("#main").append(html);
I have a django website, and I would like to implement drag&drop to my form. This part is looking very old compare to the rest of site. Problem is that I don't know javascript, I have tried to make if from tutorials but did not make any sense. Can you help me to get simple solution for this. Any ideas how to do this with zero knowledge of js?
cal.py
def OnlyCAL(request):
if request.method == "POST":
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
output = io.BytesIO()
newdoc = request.FILES['docfile']
#pandas calculations
response = HttpResponse(
output, content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename=%s' % filename
return response
else:
form = DocumentForm()
return render(request, 'cal.html', { 'form': form, 'page_title':page_title })
forms.py
class DocumentForm(forms.Form):
docfile = forms.FileField(label='Select a file')
cal.html
{% extends "base.html" %}
{% load static %}
{% block content %}
<form action="{% url "cal" %}" method="post" enctype="multipart/form-data" class="dropzone">
{% csrf_token %}
{{ message }}
<p>{{ form.non_field_errors }}</p>
<p>{{ form.docfile.label_tag }} {{ form.docfile.help_text }}</p>
<p>
{{ form.docfile.errors }}
{{ form.docfile }}
</p>
<p><input type="submit" value="Upload and Download!"/></p>
</form>
{% endblock content %}
urls.py
urlpatterns = [
path('', views.home, name='home'),
path('cal/', cal.OnlyCAL, name='cal'),
]
Like this:
I had to do this for one of my projects.
Take for example an Exam. Students were required to upload their exam file via a drop box system. As I do not know your models per say, Hopefully you can re-apply the method to your own project.
Firstly, the backend:
Backend
The form was simple. a form with just the file field.
forms.py
class ExamFileForm(forms.ModelForm):
class Meta:
model= Exam
fields= ('file',)
The view. simple FBV which extracts the header from the AJAX call to pull through the id of the exam. I then search for the Exam instance, validate the form and save the file to the instance, then return a positive JSON response back to the AJAX call. Else I return a failed response.
views.py
from django.http import JsonResponse
def load_exam_file(request):
exam_id = dict(request.headers.copy()).pop('exam_id', None)
exam= Exam.objects.get(id=exam_id)
form = ExamFileForm(data=request.POST, files=request.FILES)
if form.is_valid():
exam.file = form.cleaned_data['file']
exam.save()
return JsonResponse({
'uploaded':True,
})
return JsonResponse({'uploaded':False})
Template
The html is similar to your a simple drag box design to allow users to drop element inside.
HTML:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<form class="box" method="post" action="" enctype="multipart/form-data">
{% csrf_token %}
<div class="box__dragbox">
<div class="box__dragbox_background"></div>
<p class="box__dragtext jlrFontMediumBold">Drag files to upload here</p>
</div>
<div class="box__uploading">Uploading…</div>
<div class="box__success">Done!</div>
<div class="box__error">Error! <span></span>.</div>
</form>
The JQuery, a variety of different event handlers to change the behaviour of the box as I drag over and away from the box. The main event is the drop in which, when you drop the file an AJAX call is created and sent back to the backend for evaluation (This also brings the form data and id is registered in the header.
Note: Ensure you pass the id into the template. For example I passed exam_id into the args of the view, then called {{ exam_id }} in the header
JQuery:
$(document).on("dragover", 'html', function(e) {
e.preventDefault();
e.stopPropagation();
});
$(document).on("drop", 'html', function(e) {
e.preventDefault();
e.stopPropagation();
});
// Drag enter
$(document).on('dragenter','.box__dragbox', function (e) {
e.stopPropagation();
e.preventDefault();
$(".box__dragtext").text("Drop here!");
$(".box__dragbox_background").css({'opacity':'1'})
});
// Drag over
$(document).on('dragover','.box__dragbox', function (e) {
e.stopPropagation();
e.preventDefault();
$(".box__dragtext").text("Drop here!");
$(".box__dragbox_background").css({'opacity':'1'})
});
$(document).on('dragleave','.box__dragbox', function (e) {
e.stopPropagation();
e.preventDefault();
$(".box__dragtext").text("Drag files to upload here");
$(".box__dragbox_background").css('opacity','0')
});
// Drop
$(document).on('drop','.box__dragbox', function (e) {
e.stopPropagation();
e.preventDefault();
$(".box__dragtext").text("Uploaded!");
var file = e.originalEvent.dataTransfer.files;
var fd = new FormData();
fd.append('file', file[0])
uploadData(fd);
});
function uploadData(formdata){
$.ajax({
type: 'POST',
headers: {'X-CSRFToken': $.cookie('csrftoken'),'id':{{ exam_id }},
url: window.location.href,
data: formdata,
success: function(response){
if (response.uploaded) {
console.log("Uploaded!");
}
else {
console.log("Did not upload :(")
}
},
async: false,
cache: false,
contentType: false,
processData: false,
});
}
The CSS is just a design I put together for a simple dropbox.
CSS:
.box__dragndrop,
.box__uploading,
.box__success,
.box__error {
display: none;
}
.box__dragbox_background {
background-color:#ebebeb;
opacity:0;
position: absolute;
width: 100%;
height: 100%;
transition:'opacity 0.5s ease-in-out'
}
.box__dragbox {
border: 3px dashed #c1c1c1;
height: 200px;
border-radius: 10px;
justify-content: center;
display: flex;
align-items: center;
position: relative;
}
.box__dragtext {
color: grey;
z-index: 1;
}
after 2 days trying to do it by myself, I need some help please
I'm using GeoDjango and Leaflet. I have a model "listing" having a field location as PointField, my form uses LeafletWidget as per below.
As it is, it is working but when I create a new listing, there is nothing in location, so it shows a default world map.
I would like in my template to setup the following:
CENTER: ({{ user.lat }}, {{ user.lng }}) and zoom: 10
since I know that the New listing will be in the same geographical area as the user.
And I have NO idea how to do it!!!
Model.py
location = models.PointField(null=True, blank=True)
forms.py
from leaflet.forms.fields import PointField
from leaflet.forms.widgets import LeafletWidget
...
LEAFLET_WIDGET_ATTRS = {
'map_height': '600px',
'map_width': '50%',
'display_raw': 'true',
'map_srid': 4326,
}
...
class ListingForm(forms.ModelForm):
required_css_class = 'required'
...
location = forms.PointField(
widget=LeafletWidget(attrs=LEAFLET_WIDGET_ATTRS))
...
template.html
<!-- form start -->
<form action="{% url 'listing_new' %}" method="POST" class="listing-form" role="form" novalidate enctype="multipart/form-data" id="listingform">
{% csrf_token %}
<div class="box-body">
{{ form.non_field_errors }}
{% for field in listingform %}
<div class="fieldWrapper form-group {% if field.errors %} field_error{% endif %} ">
<label for="{{ field.id_for_label }}">
{{ field.label }}{% if field.field.required %}<span class="required-asterisk">*</span>{% endif %}
</label>
{{ field }}
{% for error in field.errors %}
<span class="help-block">{{ error }}</span>
{% endfor %}
</div>
{% endfor %}
</div>
<div class="box-footer">
<button type="submit" class="btn btn-primary" form="listingform">Submit</button>
</div>
</form>
I tried to use the following:
<script type="text/javascript">
window.addEventListener("map:init", function (e) {
var detail = e.detail;
detail.options.djoptions['center']=[{{ listing_lat }}, {{ listing_lng }}];
detail.options.djoptions['zoom']=10;
console.log(detail.options);
console.log(detail.loadmap);
}, false);
</script>
BUT it doesn't modify the code auto-generated by the leaflet widget:
<div id="id_location-map" class="leaflet-container-default"></div>
<script type="text/javascript">
(function () {
function loadmap() {
var djoptions = {"srid": null, "extent": [[-90, -180], [90, 180]], "fitextent": true, "center": null, "zoom": null, "minzoom": null, "maxzoom": null, "layers": [["OSM", "//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", "\u00a9 OpenStreetMap contributors"]], "overlays": [], "attributionprefix": null, "scale": "metric", "minimap": false, "resetview": true, "tilesextent": []},
options = {djoptions: djoptions, initfunc: loadmap,
globals: false, callback: id_location_map_callback},
map = L.Map.djangoMap('id_location-map', options);
}
var loadevents = ["load"];
if (loadevents.length === 0) loadmap();
else if (window.addEventListener) for (var i=0; i<loadevents.length; i++) window.addEventListener(loadevents[i], loadmap, false);
else if (window.jQuery) jQuery(window).on(loadevents.join(' '), loadmap);
})();
</script>
So, the solution is to add this piece of JS in the template:
<script type="text/javascript">
window.addEventListener("map:init", function (e) {
var detail = e.detail;
detail.map.setView([{{user_lat}},{{user_lng}}], 10);
}, false);
</script>
in simple JS, you'd set it up like:
map.setView([{{ user.lat }}, {{ user.lng }}], 10);
But with GeoDjango, you could try:
LEAFLET_WIDGET_ATTRS = {
'map_height': '600px',
'map_width': '50%',
'display_raw': 'true',
'map_srid': 4326,
}
LEAFLET_CONFIG {
'DEFAULT_CENTER': ({{ user.lat }}, {{ user.lng }}),
'DEFAULT_ZOOM': 10,
}
See this documentation: https://buildmedia.readthedocs.org/media/pdf/django-leaflet/latest/django-leaflet.pdf
In your Django.settings files add these lines:
LEAFLET_CONFIG = { 'DEFAULT_CENTER': (41.25 ,20), # Latitude , Longitude
'DEFAULT_ZOOM': 8,
'MAX_ZOOM': 28,
'MIN_ZOOM': 1,
'SCALE':'both',
'TILES': [], }
Trying to put those notification system on my templates.
I use a:
{% for message in messages %}
<<What I need to put here to create a notifiy for each error message??>>
{% endfor %}
Solved with:
<script>
{% for message in messages %}
$(document).ready(function() {
$.pnotify({
title: '{{ message.tags|upper }}',
text: '{{ message }}.',
type: '{{ message.tags }}',
hide: false,
styling: 'bootstrap',
closer_hover: false,
sticker_hover: false
});
});
{% endfor %}
</script>