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);
}
});
});
Related
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'),
]
I have problem with editing form in django. Pls can someone help me?
I have form with 2 fields: description and image. By this form users can edit currect article data. For example add new several images to article or update/delete one of the currect image. To create image field I used django-multiupload app. Also I load data to server by ajax. I tried next code but it didnt show me currect images in image field. Only descrtiption field works fine and show me currect data. How to fix this problem?
models.py:
class Article(models.Model):
project = models.ForeignKey(Project, on_delete=models.CASCADE)
description = models.TextField(_('Description'))
class Image(models.Model):
article= models.ForeignKey(Article, on_delete=models.CASCADE)
image = models.FileField(_('Image'), upload_to='images/%Y/%m/%d/')
forms.py:
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = ('description', )
image = MultiFileField()
def save(self, commit=True):
instance = super(ArticleForm, self).save(commit)
return instance
views.py:
def article_edit(request, article_id):
data = dict()
article= get_object_or_404(Article, pk=article_id)
if request.method == 'POST':
article_form = ArticleForm(request.POST, request.FILES, instance=article)
if article_form.is_valid():
article.save()
data['form_is_valid'] = True
articles = Article.objects.all
context = {'articles': articles}
context.update(csrf(request))
data['html_article'] = render_to_string('project/article_list.html', context)
else:
data['form_is_valid'] = False
else:
article_form = ArticleForm(instance=article)
context = {'article_form': article_form}
data['html_article_form'] = render_to_string('project/article_edit.html', context, request=request)
return JsonResponse(data)
JS:
$(function () {
var loadForm = function () {
var btn = $(this);
$.ajax({
url: btn.attr("data-url"),
type: 'get',
dataType: 'json',
beforeSend: function () {
$("#modal").modal("show");
},
success: function (data) {
$("#modal .modal-content").html(data.html_article_form);
}
});
};
var saveForm = function () {
var form = $(this);
var dataForm = new FormData(form.get(0));
$.ajax({
url: form.attr("action"),
data: dataForm
type: form.attr("method"),
dataType: 'json',
success: function (data) {
if (data.form_is_valid) {
$("#article-list").html(data.html_article);
$("#modal").modal("hide");
}
else {
$("#modal .modal-content").html(data.html_article_form);
}
}
});
return false;
};
// Create Article
$("#article-add-button").click(loadForm);
$("#modal").on("submit", ".js-article-add-form", saveForm);
// Update Article
$("#article-list").on("click", "#js-edit-article-button", loadForm);
$("#modal").on("submit", ".js-article-edit-form", saveForm);
});
article_edit:
{% load widget_tweaks %}
<form method="post" enctype="multipart/form-data" action="{% url 'article_edit' %}" class="js-article-edit-form">
{% csrf_token %}
{% for field in article_form %}
<div class="form-group{% if field.errors %} has-danger{% endif %}">
<label class="form-control-label" for="{{ field.id_for_label }}">{{ field.label }}</label>
{% render_field field class="form-control" %}
{% for error in field.errors %}
<div class="form-control-feedback">{{ error }}</div>
{% endfor %}
</div>
{% endfor %}
<button type="submit">Submit</button>
</form>
I've been stuck on this issue for a few weeks as I'm not very familiar with how to get the ajax set up. I'm working on a Django app which is basically one page that has a Dropdown menu. I would like to get whatever the user selects from the Dropdown menu and pass that data into my views.py so I can use that information to display a graph. Right now the graph part is working (I can pass in hard coded data into it and it will generate the graph) and my dropdown is working as well. However, I don't know how to get data from the drop down into my views.py. Here is how it looks.
Display.html
{% extends "RecordEvent/nav.html" %}
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
</head>
{% block content %}
<div class="row">
<div class="padded">
<div class="download-header">
<h3>Logs</h3>
<div class="row inline download-header">
<div class="col-lg-6">
<div class="dropdown padding col-lg-6">
<button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<span id="dropdownTitle" class="">Measurable</span>
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
{% include 'RecordEvent/includes/EntryDropdown.html' %}
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<div class='padded'>
<div class='col-sm-12' url-endpoint='{% url "api-data" %}'>
<h1>Graph Data</h1>
<canvas id="myChart" width="400" height="400"></canvas>
</div>
</div>
<script>
{% block jquery %}
var endpoint = 'display/api/chart/data/'
var defaultData = []
var defaultLabels = [];
$.ajax({
method: "GET",
url: endpoint,
success: function(data){
defaultLabels = data.labels
defaultData = data.default
console.log(data)
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: defaultLabels,
datasets: [{
label: '# Measurable',
data: defaultData,
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
});
},
error: function(error_data){
console.log("error")
console.log(error_data)
}
})
{% endblock %}
</script>
{% endblock %}
The first div creates the Dropdown menu. Everything below is to get the graph setup.
views.py
#login_required
def DisplayView(request):
return render(request,'DisplayData/Display.html')
class ChartData(APIView):
authentication_classes = []
permission_classes = []
def get(self, request, format=None):
all_entries = models.Entries.objects.all().filter(parent=2) #change to input from drop down
all_id = models.Entries.objects.all().values_list('id', flat=True)
all_measurables = models.Measurables.objects.all().filter(user_id=1) #change to current user
all_times = [m.timestamp for m in all_entries]
all_data = []
for m in all_entries:
data = m.data
json_data = json.loads(data)
value = json_data['value']
all_data.append(value)
data = {
"labels": all_times,
"default": all_data,
#"default": all_parent,
}
return Response(data)
#login_required
def LogDisplay(request):
measurables=[entry for entry in models.Measurables.objects.all().filter(user_id=request.user.id)]
return render(request, 'DisplayData/Logs.html',{'dropdown':measurables})
I need to get the value from the drop down into the where the comment says get value from drop down.
How can I do it?
to post via form
<form method='post' action = 'api url'>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
{% include 'RecordEvent/includes/EntryDropdown.html' %}
</ul>
</form>
amd in views.py access with
request.post[<name>]
to post via ajax
$('ul li').click(function(){
$.ajax({
url: <api url>,
type:'post',
data:{<name>:$(this).html()},
})
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>
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);
}
});
});