In Django, is it possible to make a HttpResponse which is a combination of a queryset and a text string?
I imagine something like this
objs = ModelName.objects.all()
text = "Some text"
allData = ??? #Some kind of operation (json.dumps, serializers, or ...) that combines the two
return HttpResonse(allData,content_type="application/json")
You can wrap both in a dictionary, for example:
from django.http import JsonResponse
from django.core.serializers import serialize
from json import loads as jloads
objs = ModelName.objects.all()
text = 'Some text'
allData = {
'objs': jloads(serialize('json', objs)),
'text': text
}
return JsonResponse(allData)
The data is thus a JSON object with two keys: objs that will contain the serialized queryset, and text that will contain the value in text.
Related
I have model of category and need to serialize to give beautiful output.
My model
class Categorie(models.Model):
name = models.CharField(max_length=50)
My serializer
class CategorieSerializer(serializers.ModelSerializer):
class Meta:
model = Categorie
fields = ['name']
My code
class JokesCategories(APIView):
def get(self, request):
categories = Categorie.objects.all()
serializer = CategorieSerializer(categories, many=True)
output_data = {}
for num, dictionary in enumerate(serializer.data):
output_data[num] = dict(dictionary)['name']
return Response(output_data)
I have output
{
"0": "animal",
"1": "career"
}
But need
[
0: "animal",
1: "career"
]
Help for you advices.
You can't. A JSON object always has strings as keys, not integers. This is part of the JSON specifications [json.org]. You can for example use jsonlint to check if a certain text is valid JSON, and the latter is not.
Python's JSON encoder thus will fallback on converting the integers into strings to produce a valid JSON blob. Your dictionary indeed produced integers as keys, but the serializer thus converts it to strings.
Here it however might make more sense to use a list, and not an object, since the keys (indices) start at 0 and are incremental. Using a dictionary/JSON object thus does not make much sense:
class JokesCategories(APIView):
def get(self, request):
categories = Categorie.objects.all()
serializer = CategorieSerializer(categories, many=True)
output_data = [data['name'] for item in serializer.data]
return Response(output_data)
Is there a way to minimize a json in JsonResponse?
By minimize I mean removing spaces etc.
Thanks to this I can save around 100KB on my server ;).
Example:
I have a json:
{"text1": 1324, "text2": "abc", "text3": "ddd"}
And I want to achieve something like this:
{"text1":1324,"text2":"abc","text3":"ddd"}
Now creating response looks like that:
my_dict = dict()
my_dict['text1'] = 1324
my_dict['text2'] = 'abc'
my_dict['text3'] = 'ddd'
return JsonResponse(my_dict, safe=False)
If you do this in enough places you could create your own JsonResponse like (mostly ripped from django source):
class JsonMinResponse(HttpResponse):
def __init__(self, data, encoder=DjangoJSONEncoder, safe=True, **kwargs):
if safe and not isinstance(data, dict):
raise TypeError('In order to allow non-dict objects to be '
'serialized set the safe parameter to False')
kwargs.setdefault('content_type', 'application/json')
data = json.dumps(data, separators = (',', ':')), cls=encoder)
super(JsonMinResponse, self).__init__(content=data, **kwargs)
HTTPResponse allows us to return data in the format we specify using separators with json.dumps
HttpResponse(json.dumps(data, separators = (',', ':')), content_type = 'application/json')
I have 2 applications in my "aplikacja" django project:
articles
qr
From articles model I would like to get a value "title" from the first article and then put it into qr.views (it prepares for me a pdf file)
Articles models:
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=150)
content = models.TextField(verbose_name="Zawartosc")
published = models.DateTimeField(verbose_name="Data Publikacji")
How to get a "title" value into qr views?
I suppose I need to import article from aplikacja.articles.models. But how to get exactly value in test_qr method?
from reportlab.pdfgen import canvas
from django.http import HttpResponse
from reportlab.graphics.shapes import Drawing
from reportlab.graphics.barcode.qr import QrCodeWidget
from reportlab.graphics import renderPDF
from django.contrib.auth.models import User
from aplikacja.articles.models import article
def test_qr(request):
# Create the HttpResponse object with the appropriate PDF headers.
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="somefilename.pdf"'
a= map(lambda x: str(x), User.objects.values_list('id', flat=True).order_by('id'))
p = canvas.Canvas(response)
p.drawString(10, 800, a[1])
qrw = QrCodeWidget(a[1])
b = qrw.getBounds()
w=b[2]-b[0]
h=b[3]-b[1]
d = Drawing(200,200,transform=[200./w,0,0,200./h,0,0])
d.add(qrw)
renderPDF.draw(d, p, 1, 1)
p.showPage()
p.save()
return response
To get the first article use the first() method:
article = article.objects.all().order_by('published').first()
title = article.title if article else None
BTW python lists are zero based so to get the first element of a list you should use a[0] instead of a[1]. But anyway I suggest you to use the same first() method to get the id of the first user:
first_user_id = str(User.objects.values_list('id', flat=True) \
.order_by('id').first())
I have a database of artists and paintings, and I want to query based on artist name and painting title. The titles are in a json file (the artist name comes from ajax) so I tried a loop.
def rest(request):
data = json.loads(request.body)
artistname = data['artiste']
with open('/static/top_paintings.json', 'r') as fb:
top_paintings_dict = json.load(fb)
response_data = []
for painting in top_paintings_dict[artist_name]:
filterargs = {'artist__contains': artistname, 'title__contains': painting}
response_data.append(serializers.serialize('json', Art.objects.filter(**filterargs)))
return HttpResponse(json.dumps(response_data), content_type="application/json")
It does not return a list of objects like I need, just some ugly double-serialized json data that does no good for anyone.
["[{\"fields\": {\"artist\": \"Leonardo da Vinci\", \"link\": \"https://trove2.storage.googleapis.com/leonardo-da-vinci/the-madonna-of-the-carnation.jpg\", \"title\": \"The Madonna of the Carnation\"}, \"model\": \"serve.art\", \"pk\": 63091}]",
This handler works and returns every painting I have for an artist.
def rest(request):
data = json.loads(request.body)
artistname = data['artiste']
response_data = serializers.serialize("json", Art.objects.filter(artist__contains=artistname))
return HttpResponse(json.dumps(response_data), content_type="application/json")
I just need to filter my query by title as well as by artist.
inYour problem is that you are serializing the data to json twice - once with serializers.serialize and then once more with json.dumps.
I don't know the specifics of your application, but can chain filters in django. So I would go with your second approach and just replace the line
response_data = serializers.serialize("json", Art.objects.filter(artist__contains=artistname))
with
response_data = serializers.serialize("json", Art.objects.filter(artist__contains=artistname).filter(title__in=paintings))
Check the queryset documentation.
The most efficient way to do this for a __contains search on painting title would be to use Q objects to or together all your possible painting names:
from operator import or_
def rest(request):
data = json.loads(request.body)
artistname = data['artiste']
with open('/static/top_paintings.json', 'r') as fb:
top_paintings_dict = json.load(fb)
title_filters = reduce(or_, (Q(title__contains=painting) for painting in top_paintings_dict[artist_name]))
paintings = Art.objects.filter(title_filters, artist__contains=artist_name)
That'll get you a queryset of paintings. I suspect your double serialization is not correct, but it seems you're happy with it in the single artist name case so I'll leave that up to you.
The reduce call here is a way to build up the result of |ing together multiple Q objects - operator.or_ is a functional handle for |, and then I'm using a generator expression to create a Q object for each painting name.
I have the following function,
def facebooktest(request):
fb_value = ast.literal_eval(request.body)
fb_foodies = Foodie.objects.filter(facebook_id__in = fb_value.values())
for fb_foodie in fb_foodies:
state = request.user.relationships.following().filter(username = fb_foodie.user.username).exists()
userData = {
'fbid': fb_foodie.facebook_id,
'followState': int(state),
}
Basically I am checking to see which of the user's facebook friends are on my django app. If they are, return the followState. The followState basically returns a 1 or a 0. 1 if the user is already following them on my Django app and 0 if they are not following their facebook friend on my Django app.
I would like to return back a json type dictionary to that user that looks like this:
[{fbid:222222222222, followState: 0}, {fbid:111111111111, followState: 1}, {fbid:435433434534, followState:1}]
EDIT
I have the dictionary structure but I just want to return it like the structure above.
def facebooktest(request):
fb_value = ast.literal_eval(request.body)
fb_foodies = Foodie.objects.filter(facebook_id__in = fb_value.values())
response = []
for fb_foodie in fb_foodies:
state = request.user.relationships.following().filter(username = fb_foodie.user.username).exists()
userData = {
'fbid': fb_foodie.facebook_id,
'followState': int(state),
}
response.append(userData)
return json.dumps(response)
There is a function in the django.forms.models package for that: model_to_dict
from django.forms.models import model_to_dict
model_to_dict(your_model, fields=[], exclude=[])
From the help:
model_to_dict(instance, fields=None, exclude=None)
Returns a dict containing the data in ``instance`` suitable for passing as
a Form's ``initial`` keyword argument.
``fields`` is an optional list of field names. If provided, only the named
fields will be included in the returned dict.
``exclude`` is an optional list of field names. If provided, the named
fields will be excluded from the returned dict, even if they are listed in
the ``fields`` argument.
I think you're looking for this:
return HttpResponse(simplejson.dumps(response_dict), mimetype='application/json')
where 'response_dict' would be your dictionary.