How to pass extra options from template to the view in Django? - python

I'm using django-voting application to let users vote on objects, and it works fine. But now that turns out there are more than one model to be voted, I decided to send extra options dynamically from template to the view to make it more generic and usable. But it doesn't work.
views.py
def vote_on_object(request, model, direction, post_vote_redirect=None,
object_id=None, slug=None, slug_field=None, template_name=None,
template_loader=loader, extra_context=None, context_processors=None,
template_object_name='object', allow_xmlhttprequest=False):
at the moment urls and template is like this and it works:
urls.py
link_dict = {
'model': Link,
'template_object_name': None,
'allow_xmlhttprequest': True,
}
url(r'^links/(?P<object_id>\d+)/(?P<direction>up|down|clear)vote/?$', vote_on_object, link_dict, name='vote_link'),
template.html
<form class="vote" method="POST" model="{{ object | model | lower }}" id="{{ object.pk }}" action="{% url 'vote_link' object_id=object.pk direction="up" %}">
{% csrf_token %}
<button type="submit"> + </button>
</form>
but when I change urls and template as below to send model dynamically to the views:
urls.py
link_dict = {
'template_object_name': None,
'allow_xmlhttprequest': True,
}
url(r'^vote/(?P<model>[-\w\d\_]+)/(?P<object_id>\d+)/(?P<direction>up|down|clear)vote/?$', vote_on_object, link_dict, name='vote_link'),
template.html
<form class="vote" method="POST" model="{{ object| model |lower}}" id="{{ object.pk }}" action="{% url 'vote_link' model=object|model object_id=object.pk direction="up" %}">
{% csrf_token %}
<button type="submit"> + </button>
</form>
I get following error: "POST /vote/Link/1/upvote HTTP/1.1" 500 11350
Also I should say model filter is a filter I've defined to extract model of object inside template.
Here's vote.js which handles AJAX voting:
$(document).ready(function() {
//listen for click
$('form.vote').on('submit', function(e){
e.preventDefault();
var vote_el = $(this);
var
url = vote_el.attr('action'),
model = vote_el.attr('model'),
direction = vote_el.attr('direction'),
object_id = vote_el.attr('id'),
allow_xmlhttprequest = "True" ;
console.log(allow_xmlhttprequest, url, model, direction, object_id);
$.ajax({
type:'POST',
url: vote_el.attr('action'),
data: {
'model': model,
'object_id': object_id,
'direction': direction,
},
dataType: "json",
success : function(data) {
console.log("Voted");
var pk = object_id;
$("p."+model+"-"+pk).text(data['score'].score);
}
});
});

Related

Dependent Chained Dropdown Select List with Django - Not working

I am trying to build a dependant dropdown in a django form, but it is not working. I have followed videos and tutorials, but got no luck.
I would like to select a brand of a car (make) and then a model of a car. The model depends on the car's brand, of course.
I have followed this tutorial https://python.plainenglish.io/python-and-django-create-a-dependent-chained-dropdown-select-list-b2c796f5a11
Status: The "Make" dropdown works fine. The "Model" dropdown is never showing anything.
It just does not work, but no error is shown... :S
models.py
from django.db import models
from django import forms
class Vehicle(models.Model):
make = forms.CharField(max_length=30)
model = forms.CharField(max_length=30)
...omitted
forms.py
from django import forms
from .models import Vehicle
import json
def readJson(filename):
with open(filename, 'r') as fp:
return json.load(fp)
def get_make():
""" GET MAKE SELECTION """
filepath = '/Users/alvarolozanoalonso/desktop/project_tfm/tfm/JSON/make_model_A.json'
all_data = readJson(filepath)
all_makes = [('-----', '---Select a Make---')]
for x in all_data:
if (x['make_name'], x['make_name']) in all_makes:
continue
else:
y = (x['make_name'], x['make_name'])
all_makes.append(y)
# here I have also tried "all_makes.append(x['make_name'])
return all_makes
class VehicleForm(forms.ModelForm):
make = forms.ChoiceField(
choices = get_make(),
required = False,
label='Make:',
widget=forms.Select(attrs={'class': 'form-control', 'id': 'id_make'}),
)
...omitted
class Meta:
model = Vehicle
fields = ['make', 'is_new', 'body_type', 'fuel_type', 'exterior_color', 'transmission', 'wheel_system', 'engine_type',
'horsepower', 'engine_displacement', 'mileage', 'transmission_display', 'year', 'fuel_tank_volume',
'city_fuel_economy', 'highway_fuel_economy', 'maximum_seating']
model.HTML
{% block javascript %}
<script>
$("#id_make").change(function () {
var makeId = $(this).val();
$.ajax({
type: "POST",
url: "{% url 'get-model' %}",
data: {
'csrfmiddlewaretoken': '{{ csrf_token }}',
'make': makeId,
},
success: function (data) {
console.log(data.models);
let html_data = '<option value="">-------</option>';
data.models.forEach(function (data) {
html_data += `<option value="${data}">${data}</option>`
});
$("#id_model").html(html_data);
}
});
});
</script>
{% endblock javascript %}
<form class="" action="" method="post">
{% csrf_token %}
{% for error in errors %}
<div class="alert alert-danger mb-4" role="alert">
<strong>{{ error }}</strong>
</div>
{% endfor %}
<div class="form-row">
<div class="form-group col-md-6">
<label>Status:</label>
{{ form.make }}
</div>
<div class="form-group col-lg-6">
<label >Model:</label>
<select id="id_model" class="form-control" name="state">
<option value="-----">Select Model</option>
</select>
</div>
...omitted
<div class="form-group col-md-6">
<button type="submit" class="btn btn-primary">Calculate</button>
</div>
</form>
views.py
def model(request):
context = {}
if request.method == 'GET':
form = VehicleForm()
context['form'] = form
return render(request, 'model.html', context)
if request.method == 'POST':
form = VehicleForm(request.POST)
if form.is_valid():
return render(request, 'model.html', context)
def getModel(request):
make = request.POST.get('make')
models = return_model_by_make(make)
return JsonResponse({'models': models})
Your change handler for id_make is attached before the select is created in the DOM, so your event handler does not fire.
You can use event delegation to set up an event handler before an element is created
$(document).on('change', "#id_make", function () {
var makeId = $(this).val();
$.ajax({
type: "POST",
url: "{% url 'get-model' %}",
data: {
'csrfmiddlewaretoken': '{{ csrf_token }}',
'make': makeId,
},
success: function (data) {
console.log(data.models);
let html_data = '<option value="">-------</option>';
data.models.forEach(function (data) {
html_data += `<option value="${data}">${data}</option>`
});
$("#id_model").html(html_data);
}
});
});

django / ajax form submit gets 405 error but works?

What i want to do is adding photo in user album.
I have gallery.html (template of ListView).
It shows every photo in photo model.
Each photo has button for adding photo to user album.
click button -> shows form in modal -> select album -> submit
then photo is added to album, with no refresh.
It works... harf ;( photo is added to the album. it's nice.
But i get 405 error page. what am i missing??
my code:
form in gallery.html
<form class='addphotoform' method="POST" id='addphotoform'>
{% csrf_token %}
select album.<br>
<select class="form-select" id='album_pk' name='album_pk' aria-label="Default select example">
{% for album in user.albums.all %}
<option value='{{album.pk}}'>{{album.album_name}}</option>
{% endfor%}
</select>
<input type="hidden" name="photo_id" id="photo_id" value="{{photo.id}}"/>
<button type="button submit" class="btn btn-danger">add</button>
</form>
ajax
$('#addphotoform').on('submit', function(event){
$.ajax({
type: "POST",
url: "{% url 'album:add_photo' %}",
data: { csrfmiddlewaretoken: '{{ csrf_token }}',
photo_id : $('#photo_id').val(),
album_pk : $('#album_pk').val()
},
success: function () {
console.log('added');
},
error: function () {
console.log('failed');
},
});
})
album/view.py
#login_required
def add_photo(request):
if request.method == 'POST':
photo_pk = request.POST.get('photo_id')
album_pk = request.POST.get('album_pk')
photo = get_object_or_404(Photo, pk=photo_pk)
album = get_object_or_404(UserAlbum, pk=album_pk)
album.album_photos.add(photo)
return HttpResponse('add done')
else:
return HttpResponse('wrong approach')
gallery/view.py
class GalleryView(ListView):
model = Photo
template_name = 'gallery.html'
context_object_name = 'photos'
ordering = ('-date_posted')
album/url.py
app_name = 'album'
urlpatterns = [
path('useralbum/<str:username>/<int:pk>/', views.AlbumDetailView.as_view(), name='album'),
path('useralbum/<str:username>/', views.UserAlbumListView.as_view(), name='user_album_list'),
path('useralbum/<str:username>/create/', views.craete_album, name='create_album'),
path('<int:pk>/delete', views.delete_album, name='delete_album'),
path('<int:pk>/rename', views.rename_album, name='rename_album'),
path('<int:pk>/del_photo', views.del_photo, name='del_photo'),
path('add_photo', views.add_photo, name='add_photo'),
]

Django Ajax Likes Work Incorrectly: Problem With jQuery

I have a Like feature, which works fine for the "Detailed Product". However, I want to add this feature on the main page, where multiple products are shown. Not sure, how to correctly do that.
urls.py:
url(r'^like$', views.like_product, name='like_product')
script in the base.html:
<script type="text/javascript">
$(document).ready(function(event){
$(document).on('click', '#like', function(event){
event.preventDefault();
var pk = $(this).attr('value');
$.ajax({
type: 'POST',
url: '{% url 'like_product' %}',
data: {'id': pk, 'csrfmiddlewaretoken': '{{ csrf_token }}'},
dataType: 'json',
success: function(response){
$('#like-section').html(response['form'])
console.log($('#like-section').html(response['form']));
},
error: function(rs, e){
console.log(rs.responseText);
},
});
});
});
</script>
likes.html:
<form action="{% url 'like_product' %}" method="post">
{% csrf_token %}
{% if is_liked %}
<button type="submit" id="like" name="product_id" value="{{ product.id }}" class="btn btn-danger">Dislike</button>
{% else %}
<button type="submit" id="like" name="product_id" value="{{ product.id }}" class="btn btn-primary">Like</button>
{% endif %}
</form>
views.py:
def home(request):
products = Product.objects.all().order_by('-pub_date')
f = ProductFilter(request.GET, queryset=products)
context = {
'filter': f,
}
return render(request, 'product/home.html', context).
def detail(request, product_id):
product = get_object_or_404(Product, product_id=product_id)
is_liked = False
if product.likes.filter(id=request.user.id).exists():
is_liked = True
context = {
'product': product,
'is_liked': is_liked,
'total_likes': product.total_likes()
}
return render(request, 'product/detail.html', context)
def like_product(request):
product = get_object_or_404(Product, id=request.POST.get('id'))
is_liked = False
if product.likes.filter(id=request.user.id).exists():
product.likes.remove(request.user)
is_liked = False
else:
product.likes.add(request.user)
is_liked = True
context = {
'product': product,
'is_liked': is_liked,
'total_likes': product.total_likes()
}
if request.is_ajax():
html = render_to_string('product/likes.html', context, request=request)
return JsonResponse({'form': html})
Likes/Dislikes are being recorded correctly if clicked from the main page, however they are not correctly displayed (actual amount of likes and Dislike button can only be seen on the "Detailed Product" page). I suspect this is because I have id="like" in the likes.html for both buttons. I suspect the jQuery script needs to be changed as well. Not sure how to do that. Thanks in advance for your help.
I assume you are getting ID from URL to details page. It really depends how you are generating the list of products on the page but if you are using loop in templates then just add like button under each product and then use it's id to set up like form.

Django-Ajax giving error "Method Not Allowed (POST): /post/like/"

I am new to django i am using ajax and django for very first time. I have tried by best to search here and there but i couldn't get to solution
this answer didn't help as well
Django and ajax request Method Not Allowed (POST)
the error i am getting is
Method Not Allowed (POST): /post/like/
[07/Jun/2019 16:06:16] "POST /post/like/ HTTP/1.1" 405 0
below are the codes
likes_section.html
{% if request.user.is_authenticated %}
<form action="{% url 'like_post' %}" method="post">
{% csrf_token %}
{% if is_liked %}
<span class="mr-2" style="color:black;">{{ post.total_likes }} Like{{ post.total_likes|pluralize }}<button type="submit" id="like_the_post_by_user" class="btn btn-primary ml-2" name="post_id" value="{{ post.id }}">DisLike</button></span>
{% else %}
<span class="mr-2" style="color:black;">{{ post.total_likes }} Like{{ post.total_likes|pluralize }}<button type="submit" id="like_the_post_by_user" class="btn btn-primary ml-2" name="post_id" value="{{ post.id }}">Like</button></span>
{% endif %}
</form>
{% else %}
<span class="mr-2">{{ post.total_likes }} Like{{ post.total_likes|pluralize }}<button type="submit" id="like_the_post_by_user" class="btn btn-primary ml-2" name="post_id" value="{{ post.id }}" disabled>Like</button>Please Login to enable Like button</span>
{% endif %}
Ajax
$(document).ready(function(event){
$(document).on('click',"#like_the_post_by_user", function(event){
event.preventDefault();
console.log($("#like_the_post_by_user").val())
console.log("from jquery section")
var pk = $(this).attr('value');
$.ajax({
type : "POST",
url : "{% url 'like_post' %}",
data : {'id': pk , "csrfmiddlewaretoken": '{{ csrf_token }}' },
dataType : 'json',
success : function(response){
$('#like-section_user').html(response['form'])
console.log($('#like-section_user').html(response['form']));
},
error : function(rs, e){
console.log(rs.responseText);
}
});
});
});
urls.py
urlpatterns = [
path('', PostListView.as_view(),name="blog-home"),
path('post/<int:pk>/', PostDetailView.as_view(),name="post-detail"),
path('post/new/', PostCreateView.as_view(),name="post-create"),
path('post/<int:pk>/update/', PostUpdateView.as_view(),name="post-update"),
path('post/<int:pk>/delete/', PostDeleteView.as_view(),name="post-delete"),
path('user/<str:username>/', UserPostListView.as_view(),name="user-posts"),
path('post/<str:category>/', CategoryListView.as_view(),name="category-posts"),
path('about/', AboutListView.as_view(),name="about"),
#path('users/myposts/', ActiveUserPostDetailView.as_view(),name="my-blogs"),
path('feedback-email/', views.feedback_email,name="feedback-email"),
path('post/like/', views.like_post,name="like_post"),
]
views.py
def like_post(request):
#post = get_object_or_404(Post,id=request.POST.get("post_id"))
if request.method == 'POST':
print('method is {}'(request.method))
print("\ninside like view\n")
print("\n in {} \n".format(request.POST.get('id')))
post = get_object_or_404(Post,id=request.POST.get("id"))
is_liked = False
if post.likes.filter(id=request.user.id).exists():
print("\ninside like\n")
post.likes.remove(request.user)
is_liked = False
else:
print("\ninside dislike\n")
post.likes.add(request.user)
is_liked = True
comments = Comment.objects.filter(post=post,reply=None).order_by("-id")
context = {
"post":post,
"is_liked":is_liked,
"comment": comments
}
#return redirect("post-detail",pk=request.POST.get("post_id"))
print("\ngetting in ajax\n")
if request.is_ajax():
print("\ninside ajax\n")
html = render_to_string('blog/likes_section.html', context, request=request)
return JsonResponse({"form":html})
any help will be greatly appreciated !
Thanks in advance
Your "/post/like" URL is matching the URL pattern for CategoryListView, since it is "post" plus a string.
As you have done with the post detail view, bring the pattern for the like view earlier in the list of URLs so that it matches first.

Django creating a custom like button for each item

I'm trying to create my own like button but I am encountering some issues.
The code use Ajax with Django and I am getting an error message but I don't know what is wrong.
here is the code, mostly inspired by this post.
article\models.py
class Article(models.Model):
user = models.ForeignKey(User, default='1')
titre = models.CharField(max_length=100, unique=True)
[... some unrelated models ...]
slug = models.SlugField(max_length=40)
likes = models.ManyToManyField(User, related_name="likes")
def __str__(self):
return self.titre
#property
def total_likes(self):
return self.likes.count()
article\urls.py
url(r'^like/$', views.like_button, name='like_button'),
article\views.py
#login_required(login_url='/user')
def like_button(request):
if request.method == 'POST':
user = request.user
id = request.POST.get('pk', None)
article = get_object_or_404(Article, pk=id)
if article.likes.filter(id=user.id).exists():
article.likes.remove(user)
else:
article.likes.add(user)
context = {'likes_count': article.total_likes}
return HttpResponse(json.dumps(context), content_type='application/json')
(As you can see I am trying to get the article id and not the slug)
article.html
<div>
{% for a in article %}
[... some unrelated html ...]
<input type="button" class="like" name="{{ a.id }}" value="Like" />
<p>count : {{ a.total_likes }}</p>
{% endfor %}
</div>
<script>
$('.like').click(function(){
$.ajax({
type: "POST",
url: "{% url 'like_button' %}",
data: {'pk': $(this).attr('name'), 'csrfmiddlewaretoken': '{{ csrf_token }}'},
dataType: "json",
success: function(response) {
alert('Company likes count is now ' + response.count_likes);
},
error: function(rs, e) {
alert(rs.responseText); #No Article matches the given query.
}
});
})
</script>
the error say that No Article matches the given query.
What should I change in order to make this work?
From your code I can see that "id="like" is used in a for loop so it make multiple buttons with same ID. ID must be unique
Tryto change id with class like
<div>
{% for a in article %}
[... some unrelated html ...]
<input type="button" class="like" name="{{ a.id }}" value="Like" />
<p>count : {{ a.total_likes }}</p>
{% endfor %}
</div>
<script>
$('.like').click(function(){
var pk = $(this).attr('name');
$.ajax({
type: "POST",
url: "{% url 'like_button' %}",
data: {'pk': pk, 'csrfmiddlewaretoken': '{{ csrf_token }}'},
dataType: "json",
success: function(response) {
alert('Company likes count is now ' + response.count_likes);
},
error: function(rs, e) {
alert('Something went wrong.'); #getting this message.
}
});
})
</script>

Categories