I'm trying to integrate in my django modal an ajax call to modify directly the value of my data.
In other words I have the following views.py
class UpdateCrudUser(View):
def get(self, request):
id1 = request.GET.get('id', None)
conto1 = request.GET.get('conto', None)
obj = Materiale.objects.get(id=id1)
obj.conto = conto1
obj.save()
element = {
'id':obj.id,
'conto':obj.conto}
data = {
'element': element}
return JsonResponse(data)
After that I have build before my table as following:
{% for element in elements %}
<tr id="element-{{element.id}}">
<td class="elementConto userData" name="conto">{{element.conto}}</td>
</tr>
{% endfor %}
...
And after that the modal:
<form id="updateUser">
<div class="modal-body">
<input class="form-control" id="form-id" type="hidden" name="formId"/>
<label for="conto">Conto</label>
<input class="form-control" id="form-conto" name="formConto"/>
Finally the script with the ajax call:
function editUser(id) {
if (id) {
tr_id = $("#element-" + id);
conto = $(tr_id).find(".elementConto").text();
$('#form-id').val(id);
$('#form-conto').val(conto);
}
}
$("form#updateUser").submit(function() {
var idInput = $('input[name="formId"]').val();
var contoInput = $('input[name="formConto"]').val();
if (contoInput && tipologiaInput ) {
// Create Ajax Call
$.ajax({
url: '{% url "crud_ajax_update" %}',
data: {
'id': idInput,
'conto': contoInput,
},
dataType: 'json',
success: function (data) {
if (data.element) {
updateToUserTabel(data.element);
}
}
});
} else {
alert("Vediamo se funziona.");
}
$('form#updateUser').trigger("reset");
$('#myModal').modal('hide');
return false;
});
But If I try to modify using the modal my data, django give me the following error:
ValueError: Cannot assign "'Materia Prima'": "Materiale.conto" must be a "Conto" instance.
It's possible that this error arises from the model?Becouse conto is a foreingKey:
class Materiale(models.Model):
conto = models.ForeignKey(Conto, on_delete=models.CASCADE, null=True)
class Conto(models.Model):
nome=models.CharField('Nome Conto', max_length=30, blank=True, default="")
def __str__(self):
return self.nome
In this case how could I overcome that problem?
In your UpdateCrudUser, the variable conto1 has been assign to be a string, more precisely when you do this: conto1 = request.GET.get('conto', None).
Then, when you instantiate the Materiale model (through the obj object), you're attempting to set that string to its conto field, which expects an object of the Conto model, rather than a string.
How to overcome this? Instead of assigning that string to obj.conto directly, first make a query to get a Conto object by its field nome. Something like this in your UpdateCrudUser view:
obj = Materiale.objects.get(id=id1)
conto_obj, created = Conto.objects.get_or_create(nome=conto1)
obj.conto = conto_obj
Note that I used the get_or_create() method because in case that the user's input for Conto name doesn't match any existent object, this will create a new Conto object that then can be assign to the Materiale instance that you want to update.
Related
I am trying to pass a list to the view so that i can filter by that list. i have taken some ideas from another Stack Overflow question here which should be working but is giving me some errors.
attempt 1 shown below prints as an empty array []
attempt 2 shown below gives error the JSON object must be str, bytes or bytearray, not NoneType
the ajax code consol log error Array [1] so the list works there
EDIT: I know the error is that the data being passed is NoneType, which means that the list with the values inside isn't being passed through. I'm getting a error log from the AJAX call so there must be an error there. Can anyone point out where I'm wrong?
Here is the code
view
def find(request):
Posts = Post.objects.all()
genre_list = Genres.objects.all()
if request.method == 'POST':
#attempt 1
genres_selected_use = request.POST.getlist('genres_selected') # this when printed shows an empty array []
#attempt 2
#genres_selected_use = json.loads(request.POST.get('genres_selected')) # this gives error *the JSON object must be str, bytes or bytearray, not NoneType*
for arg in genres_selected_use:
Posts = Posts.filter(genres=arg)
print(genres_selected_use)
#return redirect('find')
context = {
'products': Posts,
'keyword_list': Keywords.objects.all(),
}
return render(request, 'find/find.html', context)
AJAX
$('.filter_form').submit(function(e){
const url = $(this).attr('action')
var genres_selected_initial = [];
var genre_item = document.getElementById(`filter_idAction`);
var genres_selected_id = $(genre_item).attr('value');
var g = parseInt(genres_selected_id)
if (genre_item.classList.contains("clicked_filter")) {
genres_selected_initial.push(g);
}
//var genres_selected = genres_selected_initial; //attempt 1
var genres_selected = JSON.stringify(genres_selected_initial); //attempt 2
$.ajax({
type: 'POST',
url: url,
data: {
'csrfmiddlewaretoken': $('input[name=csrfmiddlewaretoken]').val(),
'genres_selected': genres_selected,
},
success: function(response){
console.log(genres_selected)
},
error: function(response){
console.log('error', genres_selected)
}
})
})
form
<form class="filter_form" action="{% url 'find' %}" method="POST">
{% csrf_token %}
#rest of form
</form>
I am guessing there is an easy fix for this?
Try using request.POST.getlist('genres_selected', request.POST.getlist('genres_selected[]'))
Sometimes the ajax field will append "[]" appended to the field name when it is given a list.
For anyone with a similar problem
it was solved by adding e.preventDefault()
Bit of a problem. What i am trying to do is determine what date the user has selected from an option picker and print the value from a main.py function.
So let me show my set up.
first thing i have done is calculate the date and in my views.py:
def index(request):
#GOING TO PUT THE DATE DIFFERENCE CALCULATION HERE
the_uploaded_excel_file = excel_upload.objects.order_by('-id').first()
excel_file_path_from_db = the_uploaded_excel_file.my_excel_file.path
print(excel_file_path_from_db)
wb = load_workbook(excel_file_path_from_db)
ws = wb["Sheet1"]
df = pd.read_excel(excel_file_path_from_db, engine='openpyxl', sheet_name='Sheet1', skiprows=1)
max_date_column = ws.max_column
last_date_entered = ws.cell(row=1, column=max_date_column).value
todays_date = datetime.datetime.now().date()
Date_difference = pd.date_range(start= last_date_entered, end=todays_date, freq='D')
print("last date entered was ")
print(last_date_entered)
print("todays date is ")
print(todays_date)
print("the days not done are")
print(Date_difference)
for date in Date_difference:
print(date)
return render(request, "index.html", {
'Date_difference': Date_difference
})
Then I show the dates in my html:
<h2>
{% for daterange in Date_difference %}
<h5>{{ daterange|date:"d M Y" }}</h5>
{% endfor %}
</h2>
<select style="background-color: #ceedd0;" id="date_selector"
onchange="what_date_has_been_picked()" name="filter_for">
{% for daterange in Date_difference %}
<option value={{ daterange }}>{{ daterange|date:"d M Y" }}</option>
{% endfor %}
</select>
this produces the following:
now what I want to do is to be able to print this result in my main.py. so i set up an ajax function.
the function from my main.js is called when the date selector is changed:
function what_date_has_been_picked(){
var obj = {'FileName': Date_difference};
var myJSON = JSON.stringify(Date_difference);
$.ajax({
type: 'GET',
url: '/send_date/',
data: myJSON,
success: function (response) {
document.location.reload(true);
}
});
}
Then i set the URL:
path('send_date/', views.send_date, name="send_date"),
views.py:
def send_date(request):
return send_date(request)
main.py :
def send_date(request):
selected_date = json.load(list(request.GET)[0])
print(selected_date)
data = {
'status': 'ok',
}
return JsonResponse(data)
But the problem is the Date is not printed. Where did i go wrong?
your problem
Date_difference is a context variable for the render of index function view on Django Fronted.
Your have write Date_difference on main.js.That is an static file content. Django serve this file but is not rending it.
quick solution
Pick the value of <select> with jquery
function what_date_has_been_picked(){
var myJSON = JSON.stringify({'FileName': $("date_selector").val()});
$.ajax({
type: 'GET',
url: '/send_date/',
data: myJSON,
success: function (response) {
document.location.reload(true);
}
});
}
If you need the text instead of value change the method from .val() to .text()
others in main.py
You can't convert a string to json with json.load
for obtain GET parameters:
selected_date = json.load(list(request.GET)[0])
better replace with this
parameter = request.GET.get('FileName')
And then you can construct a JSON with this data.
I am trying to save data in a pair of related models in my Django application using Ajax. Though the parent table data is saved, I am unable to save data in the child model. The system gives off the following error message:
Error: ValueError: The mappedTargFields could not be created because the data didn't validate.
How do I save data in child table as well? Even with extensive search I am unable to find a solution to save inline formsets data (which I normally do using CBV + management form). Or is it not possible to save formset data using jQuery/Ajax?
Given below are the relevant codes:
views.py
def SaveMapAjax(request, object_id=False):
if request.method == 'POST' and request.is_ajax():
qs_targ_model_form = mappedTargModelForm(request.POST)
target_field_formset = CreateMappedTargFieldsFormset(request.POST)
if qs_targ_model_form.is_valid():
qs_targ_model_form.save()
target_field_formset = CreateMappedTargFieldsFormset(request.POST, instance=qs_targ_model_form, prefix='')
target_field_formset.save()
msg='Data saved!!!'
return JsonResponse(msg, safe=False)
else:
msg= 'Error occured in save!'
else:
qs_targ_model_form = mappedTargModelForm()
target_field_formset = CreateMappedTargFieldsFormset(instance=qs_targ_model_form)
return JsonResponse(msg, safe=False)
Formset
CreateMappedTargFieldsFormset = inlineformset_factory(
mappedTargModel, # Parent table
mappedTargFields, # Child table
form=mappedTargFieldsForm, # Modelform on Child table
extra=2,
can_delete=False, min_num=1, validate_min=True)
Template
<!--html-->
<form action="" method="POST" class="form" id="dataMapperForm">
{% csrf_token %}
{{ target_model_form.as_p }}
<div class="col-md-12 text-nowrap" style="font-family:'Courier New'">
{{ target_field_formset.management_form }}
</div>
</form>
<!--The ajax part-->
<script>
$(function() {
$('#dataMapperForm').on('submit', function(e) {
var frm = $('#dataMapperForm');
e.preventDefault();
$.ajax({
type: 'POST',
url: '{% url 'save_mapper' %}',
data: frm.serialize(),
success: function(data) {
console.log('Success!!');
$("#dataMapperForm")[0].reset();
},
error: function(data) {
console.log('Error');
},
});
});
});
</script>
Edit:
Following is the error it is throwing on target_field_formset.errors:
[{'mapper_item': ['Select a valid choice. That choice is not one of the available choices.'], 'mapper_header': ['The inline value did not match the parent instance.']}, {'mapper_item': ['Select a valid choice. That choice is not one of the available choices.'], 'mapper_header': ['The inline value did not match the parent instance.']}, {'mapper_item': ['Select a valid choice. That choice is not one of the available choices.'], 'mapper_header': ['The inline value did not match the parent instance.']}]
Edit2:
On printing the serialized data to the console I am getting the follwoing:
&mapper_doc_type=MAPPER // Parent model field
&mapper_name=Test // Parent model field
&mapper_target_model=employee // Parent model field
&mapper_hdr_tab-TOTAL_FORMS=3
&mapper_hdr_tab-INITIAL_FORMS=0
&mapper_hdr_tab-MIN_NUM_FORMS=1
&mapper_hdr_tab-MAX_NUM_FORMS=1000
&mapper_hdr_tab-0-mapper_item=name // Child model "pk"
&mapper_hdr_tab-0-mapper_header=name // Child model "fk" field
&mapper_hdr_tab-0-mapped_field=name // Child model field
&mapper_hdr_tab-0-mapped_field_col_name=NAME
To my mind, value assignment to mapper_item should be an integer and not name as it shows above. Similarly for the next item mapper_header which should be the primary key of the parent table and not name.
Something I am doing here is very wrong.
you check that form is_valid, but don't check that formset is_valid
if qs_targ_model_form.is_valid():
qs_targ_model_form.save()
target_field_formset = CreateMappedTargFieldsFormset(request.POST, instance=qs_targ_model_form, prefix='')
if target_field_formset.is_valid():
target_field_formset.save()
msg='Data saved!!!'
return JsonResponse(msg, safe=False)
else:
msg = 'Formset is not valid'
else:
msg= 'Error occured in save!'
I meet difficulties as below :
I have a blog page. In blog ,i create 'comment' function to comment post. And comments has 'like' function. For this ,i create two view function ,one of them simple function ,second is api function. And create jquery ajax for to call api function. After api calling ,it update data in db. Problem is :
If i create two comment ,ajax function works only for first comment for to like comment. It looks like ,for first comment CommentLikeAPIToggle works ,for next comments CommentLikeToggle works. Here is my codes :
views.py
class CommentLikeToggle(RedirectView):
def get_redirect_url( self, *args, **kwargs):
id = self.kwargs.get('id')
obj = get_object_or_404(Comment,id=id)
url_ = obj.content_object.get_absolute_url()
user = self.request.user
if user.is_authenticated():
if user in obj.likes.all():
obj.likes.remove(user)
else:
obj.likes.add(user)
return url_
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import authentication, permissions
class CommentLikeAPIToggle(APIView):
authentication_classes = (authentication.SessionAuthentication,)
permission_classes = (permissions.IsAuthenticated,)
def get(self, request,id=None, format=None):
obj = get_object_or_404(Comment,id=id)
url_ = obj.get_absolute_url()
user = self.request.user
updated = False
liked = False
if user.is_authenticated():
if user in obj.likes.all():
liked = False
obj.likes.remove(user)
else:
liked = True
obj.likes.add(user)
updated = True
data = {
'updated':updated,
'liked':liked
}
return Response(data)
Ajax function :
function updateComLike (newCount,btn,verb){
btn.text(" "+newCount+ " " + verb);
btn.attr({"data-likes": newCount,"class":"fa fa-thumbs-up"})
}
$("#com-like").click(function(e){
e.preventDefault()
var this_ = $(this)
var likeUrl = this_.attr("data-href")
var likeCount = parseInt(this_.attr("data-likes"))
$.ajax({
url: likeUrl,
method: "GET",
data : {},
success: function(data){
var newLikes;
if (data.liked){
newLikes = likeCount + 1
updateComLike(newLikes,this_ ,gettext("Unlike"))
} else {
newLikes = likeCount - 1
updateComLike(newLikes,this_ ,gettext("Like"))
}
}, error: function(error){
}
})
})
Template tag :
{% for comment in comments %}
{{ comment.content }}
<footer>
<a data-href="{{comment.get_api_com_like_url}}" data-likes="
{{comment.likes.count}}" href="{{comment.get_com_like_url}}" id="com-like">
<i class="fa fa-thumbs-up"></i> {{comment.likes.count}}
{% if request.user in comment.likes.all %} {% trans "Unlike" %}
{%else%}{%trans "Like" %}{% endif %}
</a>
</footer>
{% endfor %}
Urls :
url(r'^api/(?P<id>\d+)/com-like/$',CommentLikeAPIToggle.as_view(), name='com-like-api-toggle'),
url(r'^(?P<id>\d+)/com-like/$',CommentLikeToggle.as_view(), name='com-like-toggle'),
I have found my problem and solved it myself. The problem is :i'm using id in template tags. And id should be unique to each element. So i used class instead of id and problem fixed
{{comment.likes.count}}" href="{{comment.get_com_like_url}}" class="com-like">
And in the ajax
$('a.com-like').click(function(e){
New to Python and Django and I'm trying to make a simple ajax call from a button click to pass certain data to my views.py, however, when I try to make a url as seen on my ajax code below, the documentId.id does not append unless I directly append in without the "?id=".
{%for document in documents%}
{{document.filename}}
<input type="button" id="{{document.id}}" onclick="loadData(this)" name="load-data" value="Add"/>
{%endfor%}
<script type ="text/javascript">
function loadData(documentId){
$.ajax({
url:"upload-data/load" + "?id=" + documentId.id,
data: {'documentId': documentId},
type: 'GET',
success: function(){
window.location.href = "http://127.0.0.1:8000/url/locations";
}
});
}
</script>
This gives me then an error that says the url cannot be found. I have a line in my urls.py below:
url(r^"upload-data/load/([0-9]+)/$', views.loadFile, name="load-data"),
Other than this method, I am stumped as to how I am going to extract my data to my views.py.
def loadFile(request):
documentId = request.GET.get('id')
newLayer = Layer(get_object_or_404(Document, pk = documentId))
newLayer.save()
layers = Layer.objects.all()
return render(request, 'url/loaded.html', { 'layers': layers})
The persisting error in the console would be:
http://127.0.0.1:8000/upload-data/load/ [HTTP/1.0 404 Not Found]
Use something like this:
def loadFile(request):
documentId= request.GET.get('id', '').
newLayer = Layer(get_object_or_404(Document, pk = documentId))
newLayer.save()
layers = Layer.objects.all()
return render(request, 'url/loaded.html', { 'layers': layers})
And update your url as :
url(r^"upload-data/load/', views.loadFile, name="load-data")
And the script would be like :
<script type ="text/javascript">
function loadData(documentId){
$.ajax({
url:"upload-data/load/?id="+ documentId.id,
data: {'documentId': documentId},
type: 'GET',
success: function(){
window.location.href = "http://127.0.0.1:8000/url/locations";
}
});
}
</script>
Thanks.
In JavaScript you need
"upload-data/load/" + documentId.id
Django doesn't use ?id= in url definition r^"upload-data/load/([0-9]+)/$'. It expects ie. upload-data/load/123 instead of upload-data/load?id=123
EDIT: and you need id in def loadFile(request, id).
And then you don't have to use request.GET.get('id')
From the above answers and comments it seems like rather than passing id as a url param you want to pass the same as a get param. In that case make your urls like below.
url(r^"upload-data/load/', views.loadFile, name="load-data")
and in views, check for get params by replacing id with documentId. document id will be in your dict named as data passed to view. So look for request.GET.get('data','') and from data extract id as below
def loadFile(request):
data = request.GET.get('data', None)
if data:
documentId = data['documentId']
newLayer = Layer(get_object_or_404(Document, pk = documentId))
newLayer.save()
layers = Layer.objects.all()
return render(request, 'url/loaded.html', { 'layers': layers})
else:
return JsonResponse({'error': 'pass document id'}, status=400)
Since you are passing a get param from javascript named as documentId not id.
HTH