Removing fields from json - django

I have a view function which renders json. I am able to specify which columns I want in my json but I don't know how to change the name of the key fields. Like the field "pk" should be "id".
I am using this autocomplete control (http://loopj.com/2009/04/25/jquery-plugin-tokenizing-autocomplete-text-entry/) and it requires the json to have certain fields.
from django.http import HttpResponse
from django.shortcuts import render_to_response
from iCookItThisWay.recipes import models
from django.core import serializers
from django.utils import simplejson
def index(request, template_name):
meal_types = []
q = ''
if 'q' in request.GET and request.GET['q']:
q = request.GET['q']
if len(q) > 0:
meal_types = models.MealType.objects.filter(name__istartswith=q)
json_serializer = serializers.get_serializer("json")()
sdata = json_serializer.serialize(meal_types, ensure_ascii=False, fields = ('id', 'name'))
return HttpResponse(simplejson.dumps(sdata), mimetype='application/json')
Could you also please point me to some documentation. I feel that I am crap at finding documentation.

Instead of using the serializer, you can build a dict manually and convert it to json via .dumps()
meal_types = models.MealType.objects.filter(name__istartswith=q)
results = []
for meal_type in meal_types:
results.append(
{'id': meal_type.id,
'name': meal_type.name})
return HttpResponse(simplejson.dumps(results), mimetype='application/json')
You could also build the results with a list comprehension, since there are only a couple
of fields:
results = [{'id': mt.id, 'name': mt.name} for mt in meal_types]

Related

PostgreSQL text search in Django not working as expected

I am implementing a search function for my API to return the object's properties when requested. So far I have tried to use Full Text Search which is usable but it has these annoying things: words have to be spelled correctly for the results to be returned and partial search, for example "appl" instead of "apple", won't work. I have also tried Trigram Similarity but it failed for long sentences. How do I implement a search function that is both accurate and fuzzy in Django?
This works
This won't work
This is my views.py
from django.shortcuts import render
from rest_framework.response import Response
from rest_framework import status
from rest_framework.decorators import api_view
from .models import Object_Locations
from .serializers import Object_LocationsSerializer
from django.contrib.postgres.search import SearchVector, SearchQuery
def index(request):
return render(request, 'main/base.html', {})
#api_view(['GET',])
def LocationsList(request):
if request.method == 'GET':
vector = SearchVector('name', 'desc', 'catergory')
query = request.GET.get('search')
if query:
locations = Object_Locations.objects.annotate(search=vector,).filter(search=SearchQuery(query))
else:
locations = Object_Locations.objects.all()
serializer = Object_LocationsSerializer(locations, many=True)
return Response(serializer.data)
From the SearchQuery documentation :
SearchQuery translates the terms the user provides into a search query object that the database compares to a search vector. By default, all the words the user provides are passed through the stemming algorithms, and then it looks for matches for all of the resulting terms.
If search_type is 'plain', which is the default, the terms are treated as separate keywords. If search_type is 'phrase', the terms are treated as a single phrase. If search_type is 'raw', then you can provide a formatted search query with terms and operators.
In the code above the SearchQuery with the search phrase "a blac husky" is translated to a SQL code like:
... ## plainto_tsquery('a blac husky') ...
So if you want to have results with similar search phrases it's possible to combine query terms:
from django.contrib.postgres.search import SearchQuery, SearchVector
from django.shortcuts import render
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .models import Object_Locations
from .serializers import Object_LocationsSerializer
def index(request):
return render(request, 'main/base.html', {})
#api_view(['GET',])
def LocationsList(request):
if request.method == 'GET':
vector = SearchVector('name', 'desc', 'catergory')
query_terms = request.GET.get('search')
query_raw = ' | '.join(query_terms.split())
query = SearchQuery(query_raw, search_type='raw')
if query.value:
locations = Object_Locations.objects.annotate(search=vector).filter(search=query)
else:
locations = Object_Locations.objects.all()
serializer = Object_LocationsSerializer(locations, many=True)
return Response(serializer.data)
In the above code the SearchQuery with the search phrase "a blac husky" is translated to a SQL code like:
... ## plainto_tsquery('a | blac | husky') ...
It's possible to use logical operation to combine SearchQuery as described in the documentation I linked.
If you want to deepen further you can read an article that I wrote on the subject:
"Full-Text Search in Django with PostgreSQL"

Serving a django model containing objects

I have following django model:
class Weather(models.Model):
lat_lng = gis_models.PointField()
raw_data = psql_fields.JSONField(null=True)
I have following view:
def weather(request):
data = WeatherModel.objects.all()
js_data = serializers.serialize('json', data)
return HttpResponse(js_data, content_type='application/json')
It throws error saying 'Point object is not json serializable.'
I want this function to return json.
Please help.
The default JSON serializer doesn't know how to serialize Point objects.
Derive your own from Django's encoder. You can also use JsonResponse for shorter code:
from django.contrib.gis.geos import Point
from django.core.serializers.json import DjangoJSONEncoder
from django.http import JsonResponse
class GeoJSONEncoder(DjangoJSONEncoder):
def default(self, obj):
if isinstance(obj, Point):
return obj.coords
return super().default(obj)
def weather(request):
data = WeatherModel.objects.all()
return JsonResponse(data, encoder=GeoJSONEncoder)
You can use JsonResponse with values.
from django.http import JsonResponse
def weather(request):
data = list(WeatherModel.objects.all())
js_data = serializers.serialize('json', data)
return JsonResponse(data, safe=False) # or JsonResponse({'data': data})
Modifed answer from here.

Custom validation is not working inside forms.py

I want to validate my email field like: if email contains [gmail.com,outlook.com,yahoo.com] then I want to raise validation Error. But it's not working, I don't know what i am doing wrong. plz help me
views.py
from django.shortcuts import render
from django.views.generic import View
from access.utils import is_valid
from access.mixin import HttpResponseMixin
import json
from access.forms import Employer_Form
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
#method_decorator(csrf_exempt,name = 'dispatch')
class Emp_Registration_view(View,HttpResponseMixin):
def post (self,request,*args,**kwargs):
data = request.body
json_data = is_valid(data)
if not json_data:
return self.render_http_response(json.dumps({'msg':'Please send valid json only'}),status=400)
emp_data = json.loads(data)
form= Employer_Form(emp_data)
if form.is_valid():
form.save(commit=True)
return self.render_http_response(json.dumps({'msg':'Registered Successfully'}))
if form.errors:
return self.render_http_response(json.dumps(form.errors),status=400)
forms.py
from access.models import Employer_Registration
from django import forms
class Employer_Form(forms.ModelForm):
def clean_email(self):
email = self.cleaned_data['emp_email']
email_lists = ['gmail.com','yahoo.com','outlook.com','hotmail.com']
data = emp_email.split('#')
if data in email_lists:
raise forms.ValidationError("email is not valid")
return email
class Meta:
model = Employer_Registration
fields = '__all__'
Your method should be named clean_emp_email, because the field is named emp_email. Otherwise it won't be called.
Seems like you are splitting on # so if you split example#gmail.com it will be [example , gmail.com] and that you are comparing in this line exactly
if [example , gmail.com] in email_lists
so it is not found I suggest you to do you can omit splitting and find in substring as
for i in email_lists:
if i in self.cleaned_data['emp_email']:
raise forms.ValidationError("email is not valid")
After #Alexandr Tatarinov answer you should also call the clean_field_name or simply clean

Django get resource in Json

import json
from django.core import serializers
from django.http import HttpResponse, Http404
from menu.models import *
def Database(request):
if request.method == 'GET':
menus = Menu.objects.all()
return toJSON(serialize(menus))
def serialize(menus):
serialized = []
for obj in menus:
serialized.append(obj.serializer())
return serialized
def toJSON(menus, status=200):
j = json.dumps(menus, ensure_ascii=False)
return HttpResponse(j, status=status, content_type='application/json; charset=utf-8')
I make my views.py like this, but it returns just [], How can I solve this?
did you mean you don't get key-value pair, instead you get just list ?
use
j = json.dumps({"menus":menus}, ensure_ascii=False)
instead of
j = json.dumps(menus, ensure_ascii=False)

Override Django Object Serializer to get rid of specified model

I need to convert a Django Queryset Object into a Json string. The built in Django Serialization library works great. Although it specifies the name of the Model from where it was created. Since I don't need this, how do I get rid of it? What else do I need to override to be able to use the overridden end_object method below?
class Serializer(PythonSerializer):
def end_object(self, obj):
self.objects.append({
"model" : smart_unicode(obj._meta), # <-- I want to remove this
"pk" : smart_unicode(obj._get_pk_val(), strings_only=True),
"fields" : fields
})
self._current = None
Sorry I had totally forgot about this question. This is how I ended up solving it (with thanks to FunkyBob on #django):
from django.core.serializers.python import Serializer
class MySerialiser(Serializer):
def end_object( self, obj ):
self._current['id'] = obj._get_pk_val()
self.objects.append( self._current )
# views.py
serializer = MySerialiser()
data = serializer.serialize(some_qs)
Here's a serializer that removes all metadata (pk, models) from the serialized output, and moves the fields up to the top-level of each object. Tested in django 1.5
from django.core.serializers import json
class CleanSerializer(json.Serializer):
def get_dump_object(self, obj):
return self._current
Serializer = CleanSerializer
Edit:
In migrating my app to an older version of django (precipitated by a change in hosting provider), the above serializer stopped working. Below is a serializer that handles the referenced versions:
import logging
import django
from django.core.serializers import json
from django.utils.encoding import smart_unicode
class CleanSerializer148(json.Serializer):
def end_object(self, obj):
current = self._current
current.update({'pk': smart_unicode(obj._get_pk_val(),
strings_only=True)})
self.objects.append(current)
self._current = None
class CleanSerializer151(json.Serializer):
def get_dump_object(self, obj):
self._current['pk'] = obj.pk
return self._current
if django.get_version() == '1.4.8':
CleanSerializer = CleanSerializer148
else:
CleanSerializer = CleanSerializer151
Serializer = CleanSerializer
Override JSON serializer class:
from django.core.serializers.json import Serializer, DjangoJSONEncoder
from django.utils import simplejson
class MySerializer(Serializer):
"""
Convert QuerySets to JSONS, overrided to remove "model" from JSON
"""
def end_serialization(self):
# little hack
cleaned_objects = []
for obj in self.objects:
del obj['model']
cleaned_objects.append(obj)
simplejson.dump(cleaned_objects, self.stream, cls=DjangoJSONEncoder, **self.options)
In the view:
JSONSerializer = MySerializer
jS = JSONSerializer()