I'm trying to get a JSON object like:
{
"username": "clelio",
"name": "Clelio de Paula",
}
and transform it in:
class User(models.Model):
name = models.CharField(max_length=30)
username = models.CharField(max_length=20)
def jsonToClass(s):
aux = json.dumps(s, self)
self.name = aux['name']
self.id = aux['id']
So I tried to use the simplejson and one method called jsonToClass():
>>> import simplejson as json
>>> u1 = User()
>>> u1.jsonToClass(face)
>>> u1.save()
This doesn't work. What is the easiest method to do what I want?
You probably want to look at Django's (de)serialization framework. Given JSON like:
[
{
"model": "myapp.user",
"pk": "89900",
"fields": {
"name": "Clelio de Paula"
}
}
]
you can save it like this:
from django.core import serializers
for deserialized_object in serializers.deserialize("json", data):
deserialized_object.save()
Note that I believe you have to use the Django serialization format to use this method, so you might have to adjust your JSON accordingly.
I just realized that
{
"username": "clelio",
"name": "Clelio de Paula",
}
is a dict() object.
So, this is easiest than I thought.
What I need to solve is just
def jsonToClass(self, aux):
self.name = aux['name']
self.username = aux['username']
that's it.
This is simply achieved as follows:
data = {
"username": "stackExchange",
"name": "stack overflow"
}
for obj in serializers.deserialize("json", data):
do_something_with(obj)
Check out django docs for details
Related
Create/remove/update/delete (CRUD) mutations usually return the corresponding database model instance as output type of the mutation. However for non-CRUD mutations I'd like to define business logic specific mutation output types. E.g. returning the count of list elements + a list of IDs which cannot be mapped 1-to-1 between graphql type and db models. How can I achieve this with graphene-django?
List not related to Models
As you want to return both a count and a list of elements, you can create a custom type:
class ListWithCountType(graphene.Scalar):
#staticmethod
def serialize(some_argument):
# make computation here
count = ...
some_list = ...
return { "count": count, "list": some_list }
Then on your mutation you use it like this:
class MyMutation(graphene.Mutation):
list_with_count = graphene.Field(ListWithCountType)
#classmethod
def mutate(cls, root, info, **kwargs):
some_argument = kwargs.pop("some_argument")
return cls(list_with_count=some_argument)
Add to your schema:
class Query(graphene.ObjectType):
my_mutation = MyMutation.Field()
Should return something like:
{
"data": {
"list_with_count": {
"count": <COUNT VALUE>,
"list": <SOME_LIST VALUE>
}
}
}
*PS: if this is only an output, ok. But if you want this type to be an argument, you should also implement "parse_literal" and "parse_value", besides the "serialize".
Here is an example with a custom ErrorType used with forms.
List related to Models
From the docs:
# cookbook/ingredients/schema.py
import graphene
from graphene_django.types import DjangoObjectType
from cookbook.ingredients.models import Category
class CategoryType(DjangoObjectType):
class Meta:
model = Category
class Query(object):
all_categories = graphene.List(CategoryType)
def resolve_all_categories(self, info, **kwargs):
return Category.objects.all()
On your schema:
import graphene
import cookbook.ingredients.schema
class Query(cookbook.ingredients.schema.Query, graphene.ObjectType):
pass
schema = graphene.Schema(query=Query)
Then you can query like:
query {
allCategories {
id
}
}
Should return something like:
{
"data": {
"allCategories": [
{
"id": "1",
},
{
"id": "2",
},
{
"id": "3",
},
{
"id": "4",
}
]
}
}
Here is an example with user model.
my_objects = []
my_objects.append(Needed("bye",9))
my_objects.append(Needed("tata",8))
my_objects.append(Needed("hi",10))
i have list of object(example 5 objects in list) like this
class Needed:
def __init__(self, name, number):
self.name = name
self.number = number
and i need to convert this into json order by count like below
{
"results":[
{ "name":"hi",
"number":"10"
},
{ "name":"bye",
"number":"9"
},
{ "name":"tata",
"number":"8"
},
...........
...........
]
}
so how to achieve this in django
First you need to make your objects json-serializable. You could provide a default encoder function or write your own JSONEncoder as mentionned in the FineManual, but for a simple one-off case like your example building dicts from your objects is probably the simplest solution:
class Needed(object):
def __init__(self, name, number):
self.name = name
self.number = number
def to_dict(self):
return {"name": self.name, "number": self.number}
Then build a list of dicts from your objects:
results = [obj.to_dict() for obj in my_objects]
sort it based on number:
results.sort(key=lambda obj: obj["number"])
and serialize the whole thing:
jsdata = json.dumps({"results": results})
This is pretty ordinary Python stuff - building dictionaries out of objects, making a list of them and sorting the list.
Beside the fact that this is not django related, here is some Python code that can help you:
from operator import attrgetter
# sort objects by attribute number in reverse order
result = {'results': [obj.__dict__ for obj in sorted(my_objects, key=attrgetter('number'), reverse=True)]}
# `indent=4` returns a json string "prettyfied"
print(json.dumps(result, indent=4))
Which prints:
{
"results": [
{
"name": "hi",
"number": 10
},
{
"name": "bye",
"number": 9
},
{
"name": "tata",
"number": 8
}
...
]
}
Hope it helps.
I am trying to build a database-backed system using Python as an engine and JSON as the DB file. Currently, there are three files:
# functions.py
import json
from pprint import pprint
with open('db.json') as data_file:
data = json.load(data_file)
def getStudentByUsername(username, record):
detail = json.load(open('db.json'))["students"][username][record]
pprint(detail)
# main.py
import functions
functions.getStudentByUsername('youngh', 'age')
{ // db.json
"students": {
"youngh": {
"name": "Hayden Young",
"age": 13,
"email": "user#school.county.sch.uk"
}
}
}
But, I can't find a way to change my students object like this and still query by username:
{ //db.json "students": [
{
"username": "youngh",
"name": "Hayden Young"
}]
}
Any ideas? I'm new to this type of use of Python 3.
In your second example, you have the user attributes in a dictionary inside a list.
You will need to iterate over your list and get the dictionary with the username you seek.
with open('db.json') as dbfile:
for student in json.load(dbfile)["students"]:
if student["username"] == username:
return(student)
Keep in mind that because the usernames are contained in their own separate dictionaries, you can now have duplicate usernames, and the for loop method will only return the first match.
I think you can use lambda:
#let this var be your file output after parsing to json
users = {
"students":
[
{
"username": "youngh",
"name": "Hayden Young"
}
]
}
def getStudentByUsername(username, record):
detail= filter(lambda user: username == user['username'], users["students"])
print (next(detail)[record])
For duplicate usernames, you can do something like this:
def getStudentByUsername(username, record):
detail= filter(lambda user: username.lower() == user['username'].lower(), users["students"])
while True:
try:
print (next(detail)[record])
except StopIteration:
return
I have a Django models like so:
class Floor(models.Model):
name = models.CharField(max_lenght =100)
class Point(models.Model):
created_at = fields.UnixDateTimeField(auto_now_add=True)
updated_at = fields.UnixDateTimeField(auto_now=True)
floor = models.ForeignKey(Floor)
device = models.CharField(max_lenght=100)
creates_at and updated_at are just custom fields with timestamps.
So, i need to send request like points/?start=x,end=y,timeslice=z, where x -
is start timestamp, y - end timestamp, z - timeslice in this period. For example, if x is start of the day, and y is and of the day, and z is 3600? i will have 24 slices and want to have JSON like so:
{
floor_id: floor_id
slice: first timestamp of first slice
count: count of devices in this slice
},
{
floor_id: floor_id
slice: first timestamp of second slice
count: count of devices in this slice
},
...
Propably, i need to customise my serializers, using django-filters and write spetial view for this purpose, but i have no ideas how to put it together
UPD: Ok, i customise my serializer for Floor model, and now it looks like:
class FloorWithTPCountSerializer(serializers.ModelSerializer):
class Meta:
model = Floor
fields = ('id', 'count')
count = serializers.SerializerMethodField('get_tp_count')
def get_tp_count(self, obj):
return obj.trackpoint_set.values('tag').distinct().count()
And no i recive JSON like:
{
"id": 28,
"count": 3
},
{
"id": 35,
"count": 1
},
I can suggest, that i need to get querystring params in this serialize class and declarate a method for counting points within timeslice. So, how can i get querydict in serializer class?
Ok, as i suggested early the key was in the serializer customisation. I have to declarete custom method for needed JSON structure.
Here is my solution:
class FloorWithTPCountSerializer(serializers.ModelSerializer):
class Meta:
model = Floor
fields = ('id', 'results')
results = serializers.SerializerMethodField('get_tp_start')
def get_tp_start(self, obj):
query_params = self.context.get("request").query_params
aggregations = {'hour':3600, 'day':86400, 'week':604800}
if 'start' in query_params and 'end' in query_params:
st_tm = int(query_params.get('start'))
en_tm = int(query_params.get('end'))
if 'aggregation' in query_params:
aggregation_value = query_params.get('aggregation')
aggregation = aggregations.get(aggregation_value)
else:
aggregation = en_tm - st_tm
trackpoint_set = obj.trackpoint_set
st = [{'count': trackpoint_set.filter(created_at__gte=ts, created_at__lt=ts + aggregation).values(
'tag').distinct().count(), 'timestamp': ts} for ts in range(st_tm, en_tm, aggregation)]
else:
st = None
return st
Ofcourse, it still lacks some checks by querstring consistency, but i can fetch JSON form, as i needed.
For example, requesting
tpfloors/?start=1496188800&end=1496275199&aggregation=day
i can get something like this:
{
"id": 49,
"results": [
{
"count": 3,
"timestamp": 1496188800
}
]
},
Best regards.
I am trying to save json data as django models instances, I am new to djano-rest-framework
here is my model:
class objective(models.Model):
description = models.CharField(max_length=200)
profile_name = models.CharField(max_length=100)
pid = models.ForeignKey('personal_info')
serializer.py
class objective_Serilaizer(serializers.Serializer):
description = serializers.CharField(max_length=200)
profile_name = serializers.CharField(max_length=100)
pid = serializers.IntegerField()
def restore_object(self, attrs, instance=None):
if instance:
instance.description = attrs.get('description', instance.description)
instance.profile_name = attrs.get('profile_name', instance.profile_name)
instance.pid = attrs.get('pid', instance.pid)
return instance
return objective(**attrs)
json
{
"objective": {
"description": "To obtain job focusing in information technology.",
"profile_name": "Default",
"id": 1
}
}
I tried
>>> stream = StringIO(json)
>>> data = JSONParser().parse(stream)
I am getting following error
raise ParseError('JSON parse error - %s' % six.text_type(exc))
ParseError: JSON parse error - No JSON object could be decoded
Use:
objective_Serilaizer(data=json)
or probably because your json is data on the request object:
objective_Serilaizer(data=request.DATA)
Here's a good walk through from the Django Rest-framework docs.
If you are sure your JSON as a string is correct then it should be easy to parse without going to the lengths you currently are:
>>> import json
>>> stream = """\
... {
... "objective": {
... "description": "To obtain job focusing in information technology.",
... "profile_name": "Default",
... "id": 1
... }
... }"""
>>> json.loads(stream)
{u'objective': {u'profile_name': u'Default', u'description': u'To obtain job focusing in information technology.', u'id': 1}}
So surely the question is how come you aren't able to parse it. Where is that JSON string you quote actually coming from? Once your JSON object is parsed, you need to address the top-level "objective" key to access the individual data elements in the record you want to create.