How to process two GET requests, at the same time and collect the data in javascript - django

Hello I have a question and a doubt, I am in a view, when I give a button I do the following code
function pagar_recibo(id) {
$.ajax ({
delay: 250,
type: 'GET',
url: '/general/recibo/add',
data: {
'id': id,
'action_al': 'add_alumnos',
},
});
};
This button is a href that goes to another url, that is to say it makes another request to the server with GET then in the new view in the get_context_data I have the following
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['arg'] = json.dumps(self.alum())
# context['arg'] = self.alum()
return context
and the function is as follows
def alum(self, **kwargs):
data = []
try:
action = self.request.GET.get('action_al', False)
print(action)
if action == False:
return
elif action == 'add_alumnos':
data = []
id = int(self.request.GET['id'])
Alumnos = Alumno.objects.filter(pk=id)
for i in Alumnos:
item = i.toJSON()
item['text'] = i.get_full_name()
data.append(item)
print(data)
except Exception as e:
data['error'] = str(e)
return data
This is how I pick it up in the template
window.data = {{ arg|safe }};
The problem is that one GET request is empty, the url change and the other is the ajax request with the given key and value, but I always get empty windows data, how could I fix that?
It could be done with a POST request? then how do I collect the value in the js file?
Please I would need help. Regards

Related

Using Modelform with ModelChoicefield does not work for me, gives undefined error when submitting the form

I am trying to use a form that adds data to the model RaportProductie using AJAX.
In the form I have 2 dropdown inputs that take data from the ManoperaRaportareBloc model.
These are the attributes from ManoperaRaportareBloc : categorie_lucrare and subcategorie_lucrare
When I submit the form it shows an error with undefined.
Please help.
ty.
forms.py:
class RaportProductieForm(forms.ModelForm):
data = forms.DateField(initial=datetime.date.today)
categorie_lucrare = forms.ModelChoiceField(queryset=ManoperaRaportareBloc.objects.all().values_list('categorie_lucrare', flat=True))
subcategorie_lucrare = forms.ModelChoiceField(queryset=ManoperaRaportareBloc.objects.all().values_list('subcategorie_lucrare', flat=True))
class Meta:
model = RaportProductie
fields = ['lucrare', 'data', 'tip', 'subcontractor', 'obiectiv', 'categorie_lucrare', 'subcategorie_lucrare', 'um', 'cantitate', 'valoare_prod']
views.py:
def raportproductie_create_view(request):
# request should be ajax and method should be POST.
if request.is_ajax and request.method == "POST":
# get the form data
form = RaportProductieForm(request.POST)
# save the data and after fetch the object in instance
if form.is_valid():
instance = form.save()
# serialize in new friend object in json
ser_instance = serializers.serialize('json', [ instance, ])
# send to client side.
return JsonResponse({"instance": ser_instance}, status=200)
else:
# some form errors occured.
data = {
'result': 'error',
'message': 'Form invalid',
'form': 'oops.'
}
return JsonResponse(data, status=400)
# some error occured
return JsonResponse({"error": ""}, status=400)
template.html:
$("#friend-form").submit(function (e) {
// preventing from page reload and default actions
e.preventDefault();
// serialize the data for sending the form data.
var serializedData = $(this).serialize();
console.log(serializedData)
// make POST ajax call
$.ajax({
type: 'POST',
url: "{% url 'proiecte:raportprod-create' %}",
data: serializedData,
success: function (response) {
// display the newly friend to table.
var instance = JSON.parse(response["instance"]);
var fields = instance[0]["fields"];
$("#table-ajax tbody").prepend("<tr><td>"+fields.data+"</td><td>"+fields.tip+"</td><td>"+fields.subcontractor+"</td><td>"+fields.obiectiv+"</td><td>"+fields.categorie_lucrare+"</td><td>"+fields.subcategorie_lucrare+"</td><td>"+fields.um+"</td><td>"+fields.cantitate+"</td><td>"+fields.valoare_prod+"</td></tr>")
},
error: function (xhr, status, error) {
var err = JSON.parse(xhr.responseText);
alert(err.error);
}
})
})
later edit:
i've used pdb to debug, printed the form before checking if valid and it returns this:
form.data
<QueryDict: {'csrfmiddlewaretoken': ['*********'], 'lucrare': ['1'], 'date': ['2023-01-10'], 'tip': ['1'], 'subcontractor': ['TGC Tadjiki'], 'obiectiv': ['obiectiv'], 'categorie_lucrare': ['CONFECTII_METALICE'], 'subcategorie_lucrare': ['CONSTRUCTIE ATIC - CONF METALICA'], 'um': ['km'], 'cantitate': ['2'], 'valoare_prod': ['0']}>
so...the inputs are working,
also in the ajax code, i've also gave a console.log(serializedData) and it outputs this:
csrfmiddlewaretoken=***********=1&date=2023-01-10&tip=1&subcontractor=TGC%20Tadjiki&obiectiv=obiectiv&categorie_lucrare=HIDRO_TERASE&subcategorie_lucrare=CONSTRUCTIE%20ATIC%20-%20CONF%20METALICA&um=mp.&cantitate=2&valoare_prod=0
later later edit:
when I am not using ModelChoiceField in the forms.py, and write the inputs by hand, the form submits...
I found an answer to my question, in the Modelform modified the custom queryset so that they remain Charfield and have added choices:
class RaportProductieForm(forms.ModelForm):
date = forms.DateField(initial=datetime.date.today)
queryset=ManoperaRaportareBloc.objects.all()
OPTIONS1 = [(choice.pk, choice.categorie_lucrare) for choice in queryset]
OPTIONS2 = [(choice.pk, choice.subcategorie_lucrare) for choice in queryset]
queryset2 = Echipa.objects.all()
OPTIONS3 = [(choice.pk, choice.nume) for choice in queryset2]
categorie_lucrare = forms.CharField(widget=forms.Select( choices = OPTIONS1 ))
subcategorie_lucrare = forms.CharField(widget=forms.Select( choices = OPTIONS2 ))
subcontractor = forms.CharField(widget=forms.Select( choices = OPTIONS3 ))
class Meta:
model = RaportProductie
fields = ['lucrare', 'date', 'tip', 'subcontractor', 'obiectiv', 'categorie_lucrare', 'subcategorie_lucrare', 'um', 'cantitate', 'valoare_prod']

Testing AJAX in Django

I want to test an AJAX call in my Django app.
What is does is adding a product to a favorite list. But I can't find a way to test it.
My views.py:
def add(request):
data = {'success': False}
if request.method=='POST':
product = request.POST.get('product')
user = request.user
splitted = product.split(' ')
sub_product = Product.objects.get(pk=(splitted[1]))
original_product = Product.objects.get(pk=(splitted[0]))
p = SavedProduct(username= user, sub_product=sub_product, original_product = original_product)
p.save()
data['success'] = True
return JsonResponse(data)
My html:
<form class="add_btn" method='post'>{% csrf_token %}
<button class='added btn' value= '{{product.id }} {{ sub_product.id }}' ><i class=' fas fa-save'></i></button
My AJAX:
$(".row").on('click', ".added", function(event) {
let addedBtn = $(this);
console.log(addedBtn)
event.preventDefault();
event.stopPropagation();
var product = $(this).val();
console.log(product)
var url = '/finder/add/';
$.ajax({
url: url,
type: "POST",
data:{
'product': product,
'csrfmiddlewaretoken': $('input[name=csrfmiddlewaretoken]').val()
},
datatype:'json',
success: function(data) {
if (data['success'])
addedBtn.hide();
}
});
});
The problem is that I pass '{{product.id }} {{ sub_product.id }}' into my views.
My test so far:
class Test_add_delete(TestCase):
def setUp(self):
self.user= User.objects.create(username="Toto", email="toto#gmail.com")
self.prod = Product.objects.create(
name=['gazpacho'],
brand=['alvalle'],
)
self.prod_2 = Product.objects.create(
name=['belvita'],
brand=['belvita', 'lu', 'mondelez'],
)
def test_add(self):
old_saved_products = SavedProduct.objects.count()
user = self.user.id
original_product = self.prod.id
sub_product = self.prod_2.id
response = self.client.post(reverse('finder:add', args=(user,))), {
'product': original_product, sub,product })
new_saved_products = SavedProducts.objects.count()
self.assertEqual(new_saved_products, old_saved_products + 1)
My test is not running and I get a SyntaxError 'product': original_product, sub_product. I know it's not the proper way to write it but my AJAX send the two ids with a space in between to the view.
If all you want to do is test if the data was actually saved, instead of just returning data['success'] = True you can return the whole entire new object... That way you can get back the item you just created from your API, and see all the other fields that may have been auto-gen (ie date_created and so on). That's a common thing you'll see across many APIs.
Another way to test this on a Django level is just to use python debugger
import pdb; pdb.set_trace() right before your return and you can just see what p is.
The set_trace() will stop python and give you access to the code scope from the command line. So just type 'l' to see where you are, and type(and hit enter) anything else that's defined, ie p which will show you what p is. You can also type h for the help menue and read the docs here

How to update database after clicking on html element?

In my flask application, I have a points column in the database, which is initialized to 0 on user registration. Now, I want to be able to update the points in database after clicking an html element.
class User(UserMixin, db.Model):
points = db.Column(db.Integer)
#bp.route('/activity1')
#login_required
def activity1():
return render_template('activity1.html', title='Activity 1')
Activity1.html has the point-generating html element
#bp.route('/register', methods=['GET', 'POST'])
def register():
...
form = RegistrationForm()
if form.validate_on_submit():
user.points = 0
db.session.add(user)
db.session.commit()
...
<a data-toggle="collapse" class="w3-large" href="#tip4" onclick="getPoints()">...</a>
<script>
function getPoints(){
points += 20; #How do i access the database.points in this case?
}
</script>
I'm not sure if I understand the code correctly, but are you asking how to update the number of points from activity1.html in the last code snippet? That won't work, the HTML is rendered on the server and once presented to the browser, there's no link between the two.
If you need to pass some data to the template while rendering it, you have to pass it in the render_template call, e.g.
render_template('activity1.html', title='Activity 1', user=user)
Then you can access it in the template like this:
<script>
function getPoints(){
points = {{ user.points|int }} + 20;
// post to backend to update data in database (using jQuery)
$.ajax({
type: 'POST',
contentType: 'application/json',
data: {
id: "{{ user.id }}",
points: points
},
dataType: 'json',
url: 'http://xxx/update_points',
success: function (e) {
// successful call
},
error: function(error) {
// an error occured
}
});
}
</script>
If you then want to update the user points in the database, you'll have to make a request to the server, which will take care of this. On the server side in Flask, define a view to handle this request:
#bp.route('/update_points', methods=['POST'])
def update_points():
data = request.get_json()
# don't know exactly what's the model and how to get the 'user' instance
user = User.get_user_by_id(data['id'])
user.points = data['points']
db.session.add(user)
db.session.commit()
Take it as an example code, I didn't test it and ommited quite a lot of details (e.g. how to get user instance in update_points etc.) Also, I might have missed what you are really asking for.

Django : Calling a Url with get method

I have the url and corresponding view as follows.
url(r'^(?P<token>.*?)/ack$', views.api_ACK, name='device-api_ack')
def api_ACK(request, token):
"""
Process the ACK request comming from the device
"""
logger.info('-> api_ACK', extra={'request': request, 'token' : token, 'url': request.get_full_path()})
logger.debug(request)
if request.method == 'GET':
# verify the request
action, err_msg = api_verify_request(token=token, action_code=Action.AC_ACKNOWLEDGE)
return api_send_answer(action, err_msg)
I want to call api_ACK function with request method as GET from another view api_send_answer
I am creating one url in /device/LEAB86JFOZ6R7W4F69CBIMVBYB9SFZVC/ack in api_send_answer view as follows..
def api_send_answer(action, err_msg, provisional_answer=None):
last_action = create_action(session,action=Action.AC_ACKNOWLEDGE,token=last_action.next_token,timer=500)
url = ''.join (['/device/',last_action.next_token ,'/',Action.AC_ACKNOWLEDGE])
logger.debug('Request Url')
logger.debug(url)
response = api_ACK(request=url,token=last_action.next_token) # This is wrong
Now from api_send_answer it is redirecting to api_ACK view, but how to call api_ACK with request method as GET?
Please help..Any suggestions would be helpful to me
This line
response = api_ACK(request=url,token=last_action.next_token) is wrong because view expects HttpRequest object and you give him url instead.
if you need to return view response to user, you can use redirect:
def api_send_answer(action, err_msg, provisional_answer=None):
last_action = create_action(session,action=Action.AC_ACKNOWLEDGE,token=last_action.next_token,timer=500)
url = ''.join (['/device/',last_action.next_token ,'/',Action.AC_ACKNOWLEDGE])
logger.debug('Request Url')
logger.debug(url)
return HttpResponseRedirect(url)
if you need to do something else with view response you have to use HttpRequest object not url as parameter.

Is it possible to return an HttpResponse in django with text & a json object?

In my view function, I'd like to return a json object (data1) and some text/html (form). Is this possible?
Here is part of my views.py:
if request.is_ajax() and request.method == 'POST':
...
if form.is_valid():
answer = form.cleaned_data['answer'] # Answer extracted from form is also a string
a1 = ques1.correct_answer
if a1 == answer:
test1 = question_list.get(id=nextid)
form = AnswerForm(test1)
ques1 = question_list.filter(id=nextid) # Filter next question as <qs>
data1 = serializers.serialize("json",ques1) # Json-ize
# ********EDITED HERE **********
variables1 = Context({
'form' : form,
'q1' : data1,
})
#response = HttpResponse()
#response['data1'] = response.write(data1)
#response['form'] = response.write(form)
if nextid <= qsnlen:
return HttpResponse(variables1, mimetype="application/json")
#return HttpResponse(response)
else:
...
I'd like to send back both the form html and the ques1 json object. How can I do this? Thanks in advance.
Just put both pieces of data in a JSON container, one key with the form data and one with the HTML as a rendered string. In the browser, you can just pull both keys out & do your thing.
In your view:
form_json_data = get_form_json_data()
rendered_html = get_the_html()
return HttpResponse(json.dumps({
"formdata": form_json,
"html": rendered_html}),
content_type="application/json")
In js:
$.post(foo, postdata, function(data){
var formdata = data.formdata
var html = data.html;
$(".html-target").replaceWith(html);
do_whatever(formdata);
})
Use JsonResponse
from django.http import JsonResponse
response_data = {put your data into a dict}
return JsonResponse(response_data, status=201)
To do this with one response; you need to send the JSON as a plain text in the context of your template response (HTML).
If you need to send JSON as as a separate JSON object, with its own mime type, then you need to write two views; one that sends back the JSON as application/json and the other that sends back the form (HTML).
EDIT:
You are not returning JSON objects, but you are turning a dictionary that has two items of two different types. As I explained in the comments, in one request/response cycle; you can only return one response which has a specific mime type that is based on the content and how you want the browser to handle it. Most of the time the content type is 'text/html'.
In your scenario, if you want to return both the HTML (which is your form), and the JSON response (which is a string), you need to return HTML.
If you want to return JSON to Jquery as a JSON object; you need to detect the request type. In your front end (the templates), you will initiate two requests - one from the browser, which will return back the form. The other from jQuery, which will return the appropriate JSON object.
Here is a possible approach to this:
def foo(request):
if request.is_ajax():
ctx = dict()
ctx['hello'] = 'world'
return HttpResponse(json.dumps(ctx),content_type='application/json')
else:
return HttpResponse('hello world')