Compare dictionary in template django - python

views.py :
#login_required(login_url='/account/login/')
def TaskCreateView(request,pk,todo_id):
completed={}
if not request.user.is_authenticated:
return redirect('accounts:index')
elif User.objects.filter(pk=request.user.pk,mentor__isnull=True).exists():
instance = get_object_or_404(Level, pk=pk)
messages.warning(request, 'You have not added a trainer yet')
print("TRAINER ILADA")
return HttpResponseRedirect(instance.get_absolute_url())
else:
instance = get_object_or_404(Level, pk=pk)
qs = instance.todo_set.get(id=todo_id)
#user = Task.objects.filter(student=request.user)
todo = Task.objects.filter(todo=qs, student=request.user)
if todo.exists():
messages.warning(request,"ALready completed")
return HttpResponseRedirect(instance.get_absolute_url())
form = StudentTaskForm(request.POST or None, request.FILES or None)
if form.is_valid():
form.instance.user =
User.objects.get(id=request.user.id)
obj = form.save(commit=False)
obj.student = request.user
obj.todo = qs
obj.level = instance
obj.save()
ImageFormSet = modelformset_factory(Images,form=ImageForm,min_num=0,max_num=3,validate_min=True,extra=3)
if request.method == 'POST':
formset = ImageFormSet(request.POST, request.FILES,
queryset=Images.objects.none())
if formset.is_valid():
for form in formset.cleaned_data:
try:
image = form['image']
Images.objects.create(post=todo[0],image=image)
except KeyError:
pass
return redirect('student:dashboard')
else:
formset = ImageFormSet(queryset=Images.objects.none())
notifications = Notification.objects.filter(receiver=request.user)
context={
'form': form,
"qs": qs,
'formset': formset,
'notifications': notifications,
'completed':completed,
'hubnotify': hubnotifications,
'acceptnotify': acceptnotify,
'follownotify': follownotify,
}
return render(request,'task_form.html',context)
inside tempate:
{% for key,value in completed.items }
{% if {{value}} == True %}
<script type="text/javascript">
$('[data-click="swal-taskcompleted"]').click(function (e) {
e.preventDefault(), swal({
title: "Already Completed",
text: "You have already completed this task!",
icon: "error",
buttons: {
cancel: {
text: "Cancel",
value: null,
visible: !0,
className: "btn btn-default",
closeModal: !0
},
}
})
});
</script>
{% endif %}
{% endfor %}
{% for obj in task.todo_set.all %}
<div class="card">
<div class="card-header" id="headingOne">
<h5 class="mb-0">
<button style="width: 100%;" class="btn" data-toggle="collapse" data-target="#{{ obj.id }}" aria-expanded="true">
<span class="mytaskbutton"><i class="fas fa-check"></i></span></i> {{ obj.name }}
</button>
</h5>
</div>
<div id="{{ obj.id }}" class="collapse" aria-labelledby="headingOne" data-parent="#accordion">
<div class="card-body">
{{ obj.description }}
<div>
<a data-click="swal-taskcompleted" href="{% url 'student:task-form' task.id obj.id %}" style="width: 100%;" type="button" class="btn btn-primary">Proceed</a>
</div>
</div>
</div>
</div>
{% endfor %}
I want show a popup message if an todo object already exists. What do I pass to the template to load script based on this condition?
if todo.exists(): I want to show the popup instead of messages using django messages ,else go the task_form which enables user to submit the form. todo is a task object. Task objects gets
saved only if the form is valid.

Please refer this link for flash message setup in django.
Note: You have to pass success, warning and info according to the your requiremnent

Related

ValueError: while trying to use the crispy forms

I am trying to make use of the crispy forms to display the form for inserting the data. I have a model as:
class Athlete(models.Model):
athlete_name=models.CharField(max_length=50)
GENDER_CHOICES=(
('M','Male'),
('F','Female'),
('O','Others')
)
gender=models.CharField(choices=GENDER_CHOICES,max_length=100)
age=models.IntegerField()
athlete_category=models.ForeignKey(Category,on_delete=models.CASCADE)
image=models.FileField(upload_to='static/athlete_img', null=True)
COUNTRY_CHOICES=(
('np','nepal'),
('in','india'),
('uk','united kingdom'),
('sp','spain'),
('ch','china')
)
medals=models.IntegerField
country=models.CharField(choices=COUNTRY_CHOICES,max_length=100)
def __str__(self):
return self.athlete_name
In the forms.py...I have modelform as:
class AthleteForm(ModelForm):
class Meta:
model:Athlete
fields='__all__'
In my views.py I have the following function:
def add_athlete(request):
if request.method == 'POST':
form = AthleteForm(request.POST, request.FILES)
if form.is_valid():
form.save()
messages.add_message(request, messages.SUCCESS,
'Athlete added sucessfully')
return redirect('/admin/athletes')
else:
messages.add_message(request, messages.ERROR,
'Enter the appropriate values')
return render(request, 'forgame/addathletes.html', {
'form': form
})
context = {
'form': AthleteForm
}
return render(request, 'forgame/addathletes.html', context)
Inside my templates/forgame I have created addathletes.html
{% extends 'layouts.html' %}
{% load crispy_forms_tags %}
{% block title %}
<title>Game Category</title>
{%endblock%}
{% block main_content %}
<div class="container-fluid mt-4">
<div class="d-flex justify-content-center">
<div class="col-md-6">
<h2>Add Categories Here!</h2>
{% for msg in messages %}
{% if msg.level == DEFAULT_MESSAGE_LEVELS.SUCCESS %}
<div class="alert alert-success">
{{msg}}
</div>
{%endif%}
{% if msg.level == DEFAULT_MESSAGE_LEVELS.ERROR %}
<div class="alert alert-danger">
{{msg}}
</div>
{%endif%}
{%endfor%}
<form action="" method="post" class="shadow-lg p-3">
{%csrf_token%}
{{form | crispy}}
<div class="mt-3">
<input type="submit" value="Add Category" class="btn btn-primary">
</div>
</form>
</div>
</div>
</div>
{% endblock %}
My urls looks fine but I have been getting this error:
Along with this:
It should be = not : so:
class AthleteForm(ModelForm):
class Meta:
model = Athlete
fields='__all__'
I'd also recommend you to maintain gaps between template tags like it should be {% endblock %} not {%endblock%} same goes for every tag.

Reverse for 'add_review' with arguments '('',)' not found. 1 pattern(s) tried: ['addreview/(?P<id>[0-9]+)/$']

I am getting an error after i have added Review model in django... on admin page model is created but on my site it is not working.I don't know where i am going wrong ...please guide me
Getting an error on line 28 of base.html
Its also showing an error on views.py line 21
views.py
from django.shortcuts import render, redirect
from django.http import HttpResponse
from .models import *
from .forms import *
# Create your views here.
def home(request):
allbooks= book.objects.all()
context= {
"books": allbooks,
}
return render(request,'main/index.html',context) #error line
def detail (request,id):
bk=book.objects.filter(id=id)
reviews=Review.objects.filter(book=id)
context ={
"book":bk,
"reviews":reviews
}
return render (request,'main/details.html',context)
def addBooks(request):
if request.user.is_authenticated:
if request.user.is_superuser:
if request.method== "POST":
form=BookForm (request.POST or None)
if form.is_valid():
data=form.save(commit=False)
data.save()
return redirect("main:home")
else:
form=BookForm()
return render (request, 'main/addbooks.html',{"form":form,"controller":"Add Books"})
else:
return redirect("main:home")
else:
return redirect("accounts:login")
def editBooks(request,id):
if request.user.is_authenticated:
if request.user.is_superuser:
bk=book.objects.get(id=id)
if request.method== "POST":
form=BookForm (request.POST or None,instance=bk)
if form.is_valid():
data=form.save(commit=False)
data.save()
return redirect("main:detail",id)
else:
form=BookForm(instance=bk)
return render (request, 'main/addbooks.html',{"form":form,"controller":"Edit Books"})
else:
return redirect("main:home")
else:
return redirect("accounts:login")
def deleteBooks(request,id):
if request.user.is_authenticated:
if request.user.is_superuser:
bk=book.objects.get(id=id)
bk.delete()
return redirect("main:home")
else:
return redirect("main:home")
else:
return redirect("accounts:login")
def add_review(request,id):
if request.user.is_authenticated:
bk=book.objects.get(id=id)
if request.method == "POST":
form= ReviewForm(request.POST or None)
if form.is_valid():
data=form.save(commit=False)
data.comment=request.POST["comment"]
data.rating=request.POST["rating"]
data.user=request.user
data.book=bk
data.save()
return redirect("main:detail",id)
else:
form=ReviewForm()
return render(request,'main/details.html',{"form":form})
else:
return redirect("accounts:login")
base.html
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="{%url 'main:home'%}">Home<span class="sr-only">(current)</span></a> <!--error line-->
</li>
{% if request.user.is_authenticated %}
{% if request.user.is_superuser %}
<li class="nav-item">
<a class="nav-link" href="{% url 'main:add_books'%}">Add Books</a>
</li>
{% endif %}
{% endif %}
details.html
<div class="card">
<div class="card-body">
<h3 class="text-center">Reviews</h3>
<form action="{%url 'main:add_review' book.id%}"method="POST">
{% csrf_token %}
<label for="comment">Review</label>
<textarea name="comment" id="comment" cols="30" rows="5" class="form-control"></textarea>
<label for="rating">Rating</label>
<input type="text" name="rating" class="form-control">
<br>
<input type="submit" class="btn btn-danger" value="Add Review">
</form>
</div>
</div>
<div class="card">
<div class="card-body">
<ul>
{% for review in reviews %}
<li>{{review.comment}} <i>{{review.user}}</i></li>
{% endfor %}
</ul>
</div>
</div>
models.py
class Review(models.Model):
book=models.ForeignKey(book,on_delete=models.CASCADE)
user=models.ForeignKey(User,on_delete=models.CASCADE)
comment=models.TextField(max_length=10000)
rating=models.FloatField(default=0)
def __str__(self):
return self.user.username
The problem is here:
def detail(request,id):
bk=book.objects.filter(id=id)
filter() will return a queryset of books. You want to fetch the actual book, so use get() instead:
def detail(request,id):
bk=book.objects.get(id=id)
This should solve the error, but you'd get a BookDoesNotExist exception if the book with that id doesn't exist in the database. You can use get_object_or_404 to handle this:
from django.shortcuts import get_object_or_404
def detail(request,id):
bk=get_object_or_404(book, id=id)
...

Heroku adds an extra "/checkout" in the URL when completing order with Stripe using Django

I have a small ecommerce project hosted on Heroku that I've built using Django, when clicking "complete order" on the checkout page I should be taken to the template "checkout_success" but instead I get stuck on the same page due to the URL trying to find a path with an extra "/checkout". I've posted some screenshots below to further explain.
Checkout app URLS.py:
from django.urls import path
from . import views
from .webhooks import webhook
urlpatterns = [
path('', views.checkout, name='checkout'),
path('checkout_success/<order_number>',
views.checkout_success, name='checkout_success'),
path('cache_checkout_data/', views.cache_checkout_data,
name='cache_checkout_data'),
path('wh/', webhook, name='webhook'),
]
Checkout apps view for checkout:
def checkout(request):
stripe_public_key = settings.STRIPE_PUBLIC_KEY
stripe_secret_key = settings.STRIPE_SECRET_KEY
if request.method == 'POST':
bag = request.session.get('bag', {})
form_data = {
'full_name': request.POST['full_name'],
'email': request.POST['email'],
'phone_number': request.POST['phone_number'],
'country': request.POST['country'],
'postcode': request.POST['postcode'],
'town_or_city': request.POST['town_or_city'],
'street_address1': request.POST['street_address1'],
'street_address2': request.POST['street_address2'],
'county': request.POST['county'],
}
order_form = OrderForm(form_data)
if order_form.is_valid():
order = order_form.save(commit=False)
pid = request.POST.get('client_secret').split('_secret')[0]
order.stripe_pid = pid
order.original_bag = json.dumps(bag)
order.save()
for item_id, item_data in bag.items():
try:
product = Product.objects.get(id=item_id)
if isinstance(item_data, int):
order_line_item = OrderLineItem(
order=order,
product=product,
quantity=item_data,
)
order_line_item.save()
else:
for size, quantity in item_data['items_by_size'].items():
order_line_item = OrderLineItem(
order=order,
product=product,
quantity=quantity,
product_size=size,
)
order_line_item.save()
except Product.DoesNotExist:
messages.error(request, (
"One of the products in your bag wasn't found in our database. "
"Please call us for assistance!")
)
order.delete()
return redirect(reverse('view_bag'))
request.session['save_info'] = 'save-info' in request.POST
return redirect(reverse('checkout_success', args=[order.order_number]))
else:
messages.error(request, 'There was an error with your form. \
Please double check your information.')
else:
bag = request.session.get('bag', {})
if not bag:
messages.error(
request, "There's nothing in your bag at the moment")
return redirect(reverse('products'))
current_bag = bag_contents(request)
total = current_bag['grand_total']
stripe_total = round(total * 100)
stripe.api_key = settings.STRIPE_SECRET_KEY
intent = stripe.PaymentIntent.create(
amount=stripe_total,
currency=settings.STRIPE_CURRENCY,
)
if request.user.is_authenticated:
try:
profile = UserProfile.objects.get(user=request.user)
order_form = OrderForm(initial={
'full_name': profile.user.get_full_name(),
'email': profile.user.email,
'phone_number': profile.default_phone_number,
'country': profile.default_country,
'postcode': profile.default_postcode,
'town_or_city': profile.default_town_or_city,
'street_address1': profile.default_street_address1,
'street_address2': profile.default_street_address2,
'county': profile.default_county,
})
except UserProfile.DoesNotExist:
order_form = OrderForm()
else:
order_form = OrderForm()
if not stripe_public_key:
messages.warning(request, 'Stripe public key is missing. \
Did you forget to set it in your environment?')
template = 'checkout/checkout.html'
context = {
'order_form': order_form,
'stripe_public_key': settings.STRIPE_PUBLIC_KEY,
'client_secret': intent.client_secret,
}
return render(request, template, context)
Checkout apps views.py for successful checkout:
def checkout_success(request, order_number):
"""
Handle successful checkouts
"""
save_info = request.session.get('save_info')
order = get_object_or_404(Order, order_number=order_number)
if request.user.is_authenticated:
profile = UserProfile.objects.get(user=request.user)
# Attach the user's profile to the order
order.user_profile = profile
order.save()
# Save the user's info
if save_info:
profile_data = {
'default_phone_number': order.phone_number,
'default_country': order.country,
'default_postcode': order.postcode,
'default_town_or_city': order.town_or_city,
'default_street_address1': order.street_address1,
'default_street_address2': order.street_address2,
'default_county': order.county,
}
user_profile_form = UserProfileForm(profile_data, instance=profile)
if user_profile_form.is_valid():
user_profile_form.save()
messages.success(request, f'Order successfully processed! \
Your order number is {order_number}. A confirmation \
email will be sent to {order.email}.')
if 'bag' in request.session:
del request.session['bag']
template = 'checkout/checkout_success.html'
context = {
'order': order,
}
return render(request, template, context)
checkout template:
<form action="{% url 'checkout' %}" method="POST" id="payment-form">
{% csrf_token %}
<fieldset class="rounded px-3 mb-5">
<legend class="fieldset-label small text-black px-2 w-auto">Details</legend>
{{ order_form.full_name | as_crispy_field }}
{{ order_form.email | as_crispy_field }}
</fieldset>
<fieldset class="rounded px-3 mb-5">
<legend class="fieldset-label small text-black px-2 w-auto">Delivery</legend>
{{ order_form.phone_number | as_crispy_field }}
{{ order_form.street_address1 | as_crispy_field }}
{{ order_form.street_address2 | as_crispy_field }}
{{ order_form.town_or_city | as_crispy_field }}
{{ order_form.county | as_crispy_field }}
{{ order_form.postcode | as_crispy_field }}
{{ order_form.country | as_crispy_field }}
<div class="form-check form-check-inline float-right mr-0">
{% if user.is_authenticated %}
<label class="form-check-label" for="id-save-info">Save this delivery information to my
profile</label>
<input class="form-check-input ml-2 mr-0" type="checkbox" id="id-save-info" name="save-info"
checked>
{% else %}
<label class="form-check-label" for="id-save-info">
<a class="text-info" href="{% url 'account_signup' %}">Create an account</a> or
<a class="text-info" href="{% url 'account_login' %}">login</a> to save this information
</label>
{% endif %}
</div>
</fieldset>
<fieldset class="px-3">
<legend class="fieldset-label small text-black px-2 w-auto">Payment</legend>
<!-- A Stripe card element will go here -->
<div class="mb-3" id="card-element"></div>
<!-- Used to display form errors -->
<div class="mb-3 text-danger" id="card-errors" role="alert"></div>
<input type="hidden" value="{{ client_secret }}" name="client_secret">
</fieldset>
<div class="submit-button text-right mt-5 mb-2">
<a href="{% url 'view_bag' %}" class="btn btn-outline-black rounded-0">
<span class="icon">
<i class="fas fa-chevron-left"></i>
</span>
<span class="font-weight-bold">Adjust Bag</span>
</a>
<button id="submit-button" class="btn btn-black rounded-0">
<span class="font-weight-bold">Complete Order</span>
<span class="icon">
<i class="fas fa-lock"></i>
</span>
</button>
<p class="small text-danger my-0">
<span class="icon">
<i class="fas fa-exclamation-circle"></i>
</span>
<span>Your card will be charged <strong>${{ grand_total|floatformat:2 }}</strong></span>
</p>
</div>
</form>
JS for Stripe payment
// Handle form submit
var form = document.getElementById('payment-form');
form.addEventListener('submit', function (ev) {
ev.preventDefault();
card.update({
'disabled': true
});
$('#submit-button').attr('disabled', true);
$('#payment-form').fadeToggle(100);
$('#loading-overlay').fadeToggle(100);
var saveInfo = Boolean($('#id-save-info').attr('checked'));
// From using {% csrf_token %} in the form
var csrfToken = $('input[name="csrfmiddlewaretoken"]').val();
var postData = {
'csrfmiddlewaretoken': csrfToken,
'client_secret': clientSecret,
'save_info': saveInfo,
};
var url = '/checkout/cache_checkout_data/';
$.post(url, postData).done(function () {
stripe.confirmCardPayment(clientSecret, {
payment_method: {
card: card,
billing_details: {
name: $.trim(form.full_name.value),
phone: $.trim(form.phone_number.value),
email: $.trim(form.email.value),
address: {
line1: $.trim(form.street_address1.value),
line2: $.trim(form.street_address2.value),
city: $.trim(form.town_or_city.value),
country: $.trim(form.country.value),
state: $.trim(form.county.value),
}
}
},
shipping: {
name: $.trim(form.full_name.value),
phone: $.trim(form.phone_number.value),
address: {
line1: $.trim(form.street_address1.value),
line2: $.trim(form.street_address2.value),
city: $.trim(form.town_or_city.value),
country: $.trim(form.country.value),
postal_code: $.trim(form.postcode.value),
state: $.trim(form.county.value),
}
},
}).then(function (result) {
if (result.error) {
var errorDiv = document.getElementById('card-errors');
var html = `
<span class="icon" role="alert">
<i class="fas fa-times"></i>
</span>
<span>${result.error.message}</span>`;
$(errorDiv).html(html);
$('#payment-form').fadeToggle(100);
$('#loading-overlay').fadeToggle(100);
card.update({
'disabled': false
});
$('#submit-button').attr('disabled', false);
} else {
if (result.paymentIntent.status === 'succeeded') {
form.submit();
}
}
});
}).fail(function () {
// just reload the page, the error will be in django messages
location.reload();
})
Heroku Logs Error:
**notice the extra "/checkout" in the POST URL.
Same in the browser console URL
I've tried an array things from adding and taking away "/" in my settings.py file and other URL paths. I'm sure this is something im overlooking but i've been stuck with this bug for days now. If anyone could help that would be great! And if any additional info is needed i'll be happy to provide. Thanks!
In your views.py in checkout_success view You should use
return HttpResponseRedirect(reverse('checkout_success',args=(order)))
instead of
template = 'checkout/checkout_success.html'
context = {
'order': order,
}
return render(request, template, context)
thanks I solved this, I problems, this problems was in js

How can I avoid repetition of code within a function-based view in Django?

I have been researching how can I avoid using snippet of code over and over. The answer probably will involve using (generic) Class-based functions. However, I am a beginner in Django and this seems confusing. Here is my view in views.py:
#login_required(login_url='/login')
def view_list(request, listing_id):
bid = Bid.objects.all().filter(listing=listing_id).order_by('-id')
b_u = bid[0].user
listing = Listing.objects.get(pk=listing_id)
if request.method == "GET":
return render(request, "auctions/view_list.html", {
"form": BidForm(),
"total_bids": bid.count(),
"bid": None if bid == 0 else bid[0].bid,
"listing": listing,
"bid_user": "Your bid is the current bid." if request.user == b_u else None
})
else:
form = BidForm(request.POST)
if form.is_valid():
value = form.cleaned_data
if value['bid'] <= bid[0].bid:
error_check = True
return render(request, "auctions/view_list.html", {
"error_check": error_check,
"alert": f"Your bid is lower than the current bid $({bid[0].bid})! Try placing a higher one.",
"form": BidForm(),
"total_bids": bid.count(),
"bid": None if bid == 0 else bid[0].bid,
"listing": listing,
"bid_user": "Your bid is the current bid." if request.user == b_u else None
})
else:
error_check = False
new_bid = form.save(commit=False)
new_bid.user_id = request.user.id
new_bid.listing_id = listing.id
new_bid.save()
return render(request, "auctions/view_list.html", {
"error_check": error_check,
"alert": "Your bid was successfully placed!",
"form": BidForm(),
"total_bids": bid.count(),
"bid": None if bid == 0 else bid[0].bid,
"listing": listing,
"bid_user": "Your bid is the current bid." if request.user == b_u else None
})
And here is my template code:
{% extends "auctions/layout.html" %}
{% load humanize %}
{% load crispy_forms_tags %}
{% block body %}
{% if error_check == True %}
<div class="alert alert-warning" role="alert">
{{ alert }}
</div>
{% elif error_check == False %}
<div class="alert alert-success" role="alert">
{{ alert }}
</div>
{% endif %}
<div>
<h3>Listing: {{ listing.title }}</h3>
<img src="{{ listing.image }}" alt="Listings' Images">
<p>{{ listing.description }}</p>
{% if not bid %}
<strong>${{ listing.price|stringformat:"1.2f" }}</strong>
{% else %}
<strong>${{ bid|stringformat:"1.2f" }}</strong>
{% endif %}
<p> {{ total_bids }} bid(s) so far. {% if bid_user %} {{ bid_user }} {% endif %}</p>
<form method="POST" name="bidding" action="{% url 'view_list' listing.id %}">
{% csrf_token %}
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">$</span>
</div>
<div style="margin: 0; padding: 0 2px; height: 6px;">
{% crispy form %}
</div>
<div class="input-group-append" >
<span class="input-group-text">.00</span>
</div>
<input type="submit" class="btn btn-primary" value="Place Bid">
</div>
</form>
<h4>Details</h4>
<li>Listed by: {{ listing.user }} </li>
<li>Category: {{ listing.category }} </li>
<li>Listing created at: {{ listing.created_at }} </li>
</div>
{% endblock %}
So how can I avoid all this repetition and make the code more succinct. Also, this way when the user places a successful bid, the rendered template does not contain the new information from the form.
The pattern is very simple
def some_view(request):
form = SomeForm(request.POST or None)
if request.method == 'POST' and form.is_valid():
# Form processing
return render(request, "auctions/view_list.html", {
"form": form
})

Django CSRF_TOKEN issue with Edge only

I'm trying my django application through different browsers (Chrome, Firefox, IE11 and Edge) and I got an issue with the csrf_token and Edge only.
This issue is in reference with my django form.
My view file :
class ManageDocView(AdminRequiredMixin, View):
""" Render the Admin Manage documents to update year in the filename"""
template_name = 'omcl/manage_doc_form.html'
form_class = ManageDocForm
success_url = 'omcl/manage_doc_form.html'
#staticmethod
def get_title():
return 'Change Document Title'
def get(self, request):
form = self.form_class()
context = {
"form": form,
"title": self.get_title()
}
return render(request, self.template_name, context)
def post(self, request):
form = self.form_class()
query_document_updated = None
query_omcl = None
query_document = None
if "submitButton" in request.POST:
omcl_list = request.POST.get('omcl_list', False)
query_omcl = Omcl.objects.get(id=omcl_list)
query_document = Document.objects.filter(omcl=omcl_list)
form.fields['omcl_list'].initial = query_omcl
elif "UpdateDocument" in request.POST:
checkbox_id = request.POST['DocumentChoice']
checkbox_id_minus_1 = int(checkbox_id) - 1
query_document_updated = Document.objects.get(id=checkbox_id)
omclcode = query_document_updated.omcl.code
src_filename = query_document_updated.src_filename
filename, file_extension = os.path.splitext(src_filename)
category = query_document_updated.category
if category == "ANNUAL":
category = "ANNUAL_REPORT"
year = self.request.POST['pts_years']
# Create the new document title updated by the new year
new_document_title = f"{year}_{category}_{omclcode}_{checkbox_id_minus_1} - {src_filename}"
# Create the new document file updated by the new year
new_document_file = f"omcl_docs/{omclcode}/{year}_{category}_{omclcode}_{checkbox_id_minus_1}{file_extension}"
# Get file.name in order to rename document file in /media/
document_path = query_document_updated.file.name
try:
actual_document_path = os.path.join(settings.MEDIA_ROOT, document_path)
new_document_path_temp = f"{settings.MEDIA_ROOT}/{new_document_file}"
new_document_path = os.rename(actual_document_path, new_document_path_temp)
except FileNotFoundError:
messages.error(self.request, _(f"Document {src_filename} doesn't exist on the server"))
return redirect('manage_doc')
else:
# Assign modifications to selected document and save it into the database
query_document_updated.title = new_document_title
query_document_updated.file = new_document_file
query_document_updated.save()
messages.success(self.request, _(f"The modification has been taken into account"))
context = {
'form': form,
'query_omcl': query_omcl,
'query_document': query_document,
'query_document_updated': query_document_updated,
'title': self.get_title(),
}
return render(request, self.template_name, context)
My forms file :
class ManageDocForm(forms.Form):
def __init__(self, *args, **kwargs):
super(ManageDocForm, self).__init__(*args, **kwargs)
omcl_list = forms.ModelChoiceField(
queryset=Omcl.objects.filter(is_obsolete=False),
label=_('OMCL Choice'),
widget=ModelSelect2Widget(
model=Omcl,
search_fields=['code__icontains', 'name__icontains'],
attrs={'data-placeholder': "Please select an OMCL"}
)
)
now = datetime.today().year
year_choices = ((i, str(i)) for i in range(now, now - 30, -1))
pts_years = forms.ChoiceField(
label='PTS years',
choices=year_choices,
required=True,
widget=Select2Widget(
attrs={'data-placeholder': "Please select a new year"}),
)
My template file with a little part of javascript :
{% block extra_script %}
<!-- Submit OMCL list with change and not submit button + Previous/Next pagination button -->
<script>
$('#select-omcl-form').on('change', function () {
$(this).submit();
});
</script>
{% endblock %}
{% block main %}
<h2>{{ title }}</h2>
<div class="row manage-doc">
<div class="col-md-12">
<form id="select-omcl-form" name="select-omcl-form" action="" method="POST">
{% csrf_token %}
<fieldset>
<legend><span class="name">{% trans 'Select an OMCL' %}</span></legend>
{{ form.omcl_list }}
<input type="hidden" name="submitButton">
</fieldset>
</form>
</div>
</div>
<br/>
<div class="row manage-doc">
<div class="col-md-12">
<fieldset>
<legend><span class="name">{% trans 'Select a document' %}</span></legend>
<form action="" method="POST">
{% csrf_token %}
<div id="table-document">
<table id="document-table" class="table table-bordered table-striped table-condensed table_model">
<thead>
<tr>
<th id="radio-column"></th>
<th id="document-title-column">{% trans 'Document title' %}</th>
</tr>
</thead>
<tbody>
{% for document in query_document|dictsortreversed:'title' %}
<tr>
<td><input type="radio" class="radio-document" id="document-radiobox" name="DocumentChoice"
value="{{ document.id }}"></td>
<td>{{ document.title }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<br><br>
<legend><span class="name">{% trans 'Select a new year' %}</span></legend>
{{ form.pts_years }}
<button class="btn btn-default" id="document-button" type="submit"
name="UpdateDocument">{% trans "Change year" %}</button>
</form>
</fieldset>
<br>
</div>
</div>
{% endblock main %}
A gif presentation :
This is a little gif which explains the process and the issue according to csrf_token only with Edge browser :
Link to my gif
What I tried :
I tried to add CSRF_COOKIE_DOMAIN in my settings.py file but it doesn't work.
Do you have any idea ? It's pretty weird because I don't have any issue with others browsers. Ony with Microsoft Edge.
Cookies are allowed in my browser.
I found the issue thanks to my collegue. I used redirect but I had to use render because if I redirect, the CSRF_TOKEN is not actualized and it sends a second POST request with the previous token.
So it should be :
except FileNotFoundError:
messages.error(self.request, _(f"Document {src_filename} doesn't exist on the server"))
context = {
'form': form,
'query_omcl': query_omcl,
'query_document': query_document,
'query_document_updated': query_document_updated,
'title': self.get_title(),
}
return render(request, self.template_name, context)
Instead of :
except FileNotFoundError:
messages.error(self.request, _(f"Document {src_filename} doesn't exist on the server"))
return redirect('manage_doc')

Categories