JSON Serializing in Django and JSON Parsing in Jquery - django

So I have this code:
def success_comment_post(request):
if "c" in request.GET:
c_id = request.GET["c"]
comment = Comment.objects.get(pk=c_id)
model = serializers.serialize("json", [comment])
data = {'message': "Success message",
'message_type': 'success',
'comment': model }
response = JSONResponse(data, {}, 'application/json')
return response
else:
data = {'message': "An error occured while adding the comment.",
'message_type': 'alert-danger'}
response = JSONResponse(data, {}, 'application/json')
and back in jQuery I do the following:
$.post($(this).attr('action'), $(this).serialize(), function(data) {
var comment = jQuery.parseJSON(data.comment)[0];
addComment($("#comments"), comment);
})
Now... in the Django function, why do I have to put the comment in [] -->
model = serializers.serialize("json", [comment])
and back in jQuery, why do I have to do jQuery.parseJSON(data.comment)[0]?
Anyway I don't have to do this? I find it weird I have to hardcode the [0]
Thanks a lot!

Well serializers.serialize only takes querysets or iterators with django model instances but using Comment.objects.get will return an object and not an iterator and that is why you will need to put it in [] to make it an iterator.
Since its a list you will have to access it like an array in javascript too. I would suggest not using serializer and using simplejson to convert field values to json.
Sample Code:
from django.utils import simplejson as json
from django.forms.models import model_to_dict
comment = Comment.objects.get(pk=c_id)
data = {'message': "Success message",
'message_type': 'success',
'comment': model_to_dict(comment)}
return HttpResponse(json.dumps(data), mimetype='application/json')
I have only mentioned relevant parts of your code. Hopefully this should solve your problem

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']

Django rest serialization - Passing JSON to Javascript

Disclaimer - Django noob, especially REST Framework. I'm trying to create an app that for this purposes passes JSON to the template. I figured Django Rest would be ideal.
I have set up a user profile so the user can select various attributes (works fine), and now want to pass a JSON of all the user's selections to template. Think of it as a "my profile" page.
View:
profile = Profile.objects.filter(user=request.user)
serializer = ProfileSerializer(profile, many=True)
myteam = JsonResponse(serializer.data, safe=False)
print(myteam.content) ## to see what's being passed
context = {'myteam': myteam.content}
return render(request, 'main/myteam.html', context)
Template:
<script>
console.log({{myteam}});
<\script>
Django server output:
b'[{"user": "DAVE", "GK1": {"id": 1001, "ShortName": "J. Strummer", "Club": "CLUB", "Shirt": "SHIRT.png", "ShortClub": "ETC", "ShortPos": "FW", "CurrentVal": "10", "TotalPoints": 1}, "GK2": {"id": 320, "ShortName": "D. Jones", "Club": "CLUB2", "Shirt": "ETABE.png", "ShortClub": "ETABE", "ShortPos": "GK", "CurrentVal": "4.5",
Template - Google Chrome JS console:
Uncaught SyntaxError: Invalid or unexpected token
Template - Chrome details:
console.log(b'[{"user": "mikey", "GK1": {"id": 1001, "ShortName": "J. Strummer", "Club": "ETC", "Shirt": "SHIRT.png", "ShortClub": "ETC", "ShortPos": "FW", "CurrentVal": "10.0", "TotalPoints": 1}, // lot's more of this
Noob Conclusion:
I don't seem to be getting a "clean" JSON object passed to the template from the server. Possibly due to the b'[ .... is this bytes literal?
Perhaps I should be using another method to pass the JSON to the template?
TWIST - in my testing I followed the REST tutorial and was able to setup a simple view which returned JsonResponse:
player = Player.objects.all()
serializer = PlayerSerializer(player, many=True)
return JsonResponse(serializer.data, safe=False)
Now if you go to this url mapping it displays in browser a perfect JSON example. I don't see why there should be a difference between
myteam = JsonResponse(serializer.data, safe=False)
and
return JsonResponse(serializer.data, safe=False)
I've been stuck on this on and off for literally days now so any help would be hugely appreciated.
I believe you may need to do this:
from rest_framework.renderers import JSONRenderer
profile = Profile.objects.filter(user=request.user)
serializer = ProfileSerializer(profile, many=True)
content = JSONRenderer().render(serializer.data)
return JsonResponse(content)
Or this:
from rest_framework.renderers import JSONRenderer
profile = Profile.objects.filter(user=request.user)
serializer = ProfileSerializer(profile, many=True)
return JsonResponse(serializer.data)
Rather than creating a JsonResponse object and passing it back through context.
There is another alternative, however, to the above as you'll want your endpoint to be extremely flexible.
Such API querying functionality is available from a 3rd-party package. I use this a lot, and find it works really well:
pip install djangorestframework-queryfields
Declare your serializer like this:
from rest_framework.serializers import ModelSerializer
from drf_queryfields import QueryFieldsMixin
class MyModelSerializer(QueryFieldsMixin, ModelSerializer):
...
Then the fields can now be specified (client-side) by using query arguments:
GET /identities/?fields=id,data
Exclusion filtering is also possible, e.g. to return every field except id:
GET /identities/?fields!=id
There are a few things going on here.
Firstly, you have taken the rendered output of a response and passed the content back into a template. This isn't the right thing to do; you should skip the JsonResponse altogether and pass serializer.data into a renderer before sending it to the template.
serializer = ProfileSerializer(profile, many=True)
data = JSONRenderer().render(serializer.data)
context = {'myteam': data}
return render(request, 'main/myteam.html', context)
Secondly, the encoding is due to Django templates' automatic HTML escaping. You should mark your JSON as safe.
console.log({{ myteam|safe }});

How to convert QueryDict to python dictionary

I am trying to post some data from Dojo to Django application. I use postData to post the data to the server
here is the code snippet
var csrftokenval = dojo.cookie('csrftoken');
var selectedmoid1 = tree.getSelectedItemId();
var loadURL = '/calerts/';
dojo.rawXhrPost({
url : loadURL,
headers : {'X-CSRFToken':csrftokenval},
postData: dojo.toJson({'selectedmoid':selectedmoid1,'previousval':previousVal}),
handleAs: "text",
load : function(data, ioArgs){
dojo.byId('content-main').innerHTML = data;
},
error : function(data, ioArgs){
}
});
In the Django views i get the data as
def calerts(request):
user = request.user
compId = int(request.session.get('USERCOMPANY_ID','-1'))
listCount = 25
print '0000000000000000000000000000000 ',request.POST
print 'post dictionary ::: ',request.POST.dict()
I know to get the dict value from querydict using dict() method however in my case the print is
post dictionary ::: {u'{"selectedmoid":"4","previousval":"4"}': u''}
i dont undersand where that final u'' comes from. Also i would like to retrieve the values of selectedmoid and previousval
Your sending the data as a raw JSON post, not a form-encoded one. So you should access request.body, not request.POST, and decode the JSON from there.

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')

Deserializing JSON in Django

This one has had me pulling out my hair. I've been trying to deserialize JSON in Django for the last couple hours.
I have a function:
# in index.html
function updateWidgetData(){
var items=[];
for statement here:
for statement here:
var item={
id: $j(this).attr('id'),
collapsed: collapsed,
order : i,
column: columnId
};
items.push(item);
var sortorder={ items: items};
$j.post('2', 'data='+$j.toJSON(sortorder), function(response)
{
if(response=="success")
$j("#console").html('<div class="success">Saved</div>').hide().fadeIn(1000);
setTimeout(function(){
$j('#console').fadeOut(1000);
}, 2000);
});
}
And I'm trying to deserialize the JSON in django:
# in views.py
if request.is_ajax():
for item in serializers.deserialize("json", request.content):
item = MyObject(id=id, collapsed=collapsed, order=order, column=column)
return HttpResponse("success")
else:
....
And it hasn't been working. I know this is probably a really trivial question, but I've never used JSON before, and I'd really appreciate some help. Thanks!
serializers.deserialize is for deserializing a particular type of JSON - that is, data that was serialized from model instances using serializers.serialize. For your data, you just want the standard simplejson module.
And the second thing wrong is that your response isn't just JSON - it is an HTTP POST with JSON in the data field. So:
from django.utils import simplejson
data = simplejson.loads(request.POST['data'])
from django.core import serializers
obj_generator = serializers.json.Deserializer(request.POST['data'])
for obj in obj_generator:
obj.save()
Objects should now be saved and visible in django admin