Django Python arrange json into a single node - python

I'm working with a legacy database which has 2 records, the data in each record contain the following values: Name, Email, Company, Phone
These 2 records contain the same data value except the value for Phone which is different.
When I retrieve them in JSON I get the following output:
"results": [
{
"Name": "Mack",
"Email": "Mack#email.com",
"Company": "Company Name",
"Phone": "123456789"
},
{
"Name": "Mack",
"Email": "Mack#email.com",
"Company": "Company Name",
"Phone": "1111111"
}
]
My question: As you can see there is some duplicate data in the output above, so is there a way to arrange the JSON output to the following:
"results": [
{
"Name": "Mack",
"Email": "Mack#email.com",
"Company": "Company Name",
"Phone": "123456789"
"Phone 2": "1111111"
}
]
Here is the code for Views.py file:
class DataView(viewsets.ModelViewSet):
queryset = DataList.objects.all()
serializer_class = DataSerializer
Here is the code for Serializers.py file:
class DataSerializer(serializers.ModelSerializer):
data_details = serializers.SerializerMethodField()
class Meta:
model = DataList
fields = 'data_details'
def get_data_details(self, obj):
return [{
'name': obj.name,
'email': obj.email,
'company': obj.company,
'phone': obj.phone,
}]
Here is the code for models.py file:
class Data(models.Model):
name = models.CharField(db_column='name', primary_key=True, max_length=50)
email = models.CharField(db_column='email', max_length=50)
company = models.CharField(db_column='company', max_length=100)
phone= models.TextField(db_column='phone')
class Meta:
managed = False
db_table = 'data_table'
Thank you.

Related

DRF Serializer How do I serialize my data and display

I have following Serializer I am facing problem with Json with serializing. I have user named daniel james and he have multiple subject like maths science I am providing nested serializer to fill all subject but based on subject users name also repeats below is more specific qsn
This is my model.
class Result(BaseModel):
semester_choices = (
('first', 'First'),
('second', 'Second'),
('third', 'Third'),
('fourth', 'Fourth'),
('fifth', 'Fifth'),
('sixth', 'Sixth'),
('seventh', 'Seventh'),
('eight', 'Eight'),
('all', 'All'),
)
user = models.ForeignKey(User, on_delete=models.CASCADE)
registration_number = models.CharField(null=True, blank=True, max_length=20)
semester = models.CharField(max_length=50, choices=semester_choices, null=True, blank=True)
gpa = models.CharField(max_length=20)
subject = models.CharField(max_length=50)
serializers.py
class ResultSerializer(serializers.ModelSerializer):
class Meta:
model = Result
fields = '__all__'
class ListResultSerializer(ResultSerializer):
user = serializers.CharField()
semester = serializers.CharField()
subject = serializers.SerializerMethodField()
class Meta(ResultSerializer.Meta):
fields = (
'user',
'semester',
'subject',
)
def get_subject(self, instance):
return SubjectSerializer(instance).data
This is my SubjectSerializer
class SubjectSerializer(ResultSerializer):
class Meta(ResultSerializer.Meta):
fields = (
'gpa',
'subject'
)
And In my views.py I have done like this.
class ListResultView(rest_generics.ListAPIView, UserMixin):
serializer_class = serializers.ListResultSerializer
permission_classes = (AllowAny,)
def get_object(self):
return self.get_user()
def get_queryset(self):
return usecases.ListResultUseCase(
user=self.get_user()
).execute()
I use usecases.py to filter the data here is further code
class ListResultUseCase:
def __init__(self, user: User):
self._user = user
def execute(self):
self._factory()
return self._result
def _factory(self):
self._result = Result.objects.filter(user=self._user)
Now this is the Json I am getting right now from above code.
[
{
"user": "daniel james",
"semester": "first",
"subject": {
"gpa": "a+",
"subject": "maths"
}
},
{
"user": "daniel james",
"semester": "first",
"subject": {
"gpa": "A",
"subject": "data structures"
}
}
]
I want my json to be in this format
[
{
"user": "daniel james",
"semester": "first",
"subject": [
{
"gpa": "a+",
"subject": "maths"
},
{
"gpa": "A",
"subject": "data structures"
}
]
}
]
Any help in serializer?
You could create a seperate serializer to use with the nested serializer.
class SubjectNestedSerializer(serializers.ModelSerializer):
class Meta:
model = Subject
exclude = ['user']
P.S
Try to change your model like this
class Semester(BaseModel):
semester_choices = (
('first', 'First'),
('second', 'Second'),
('third', 'Third'),
('fourth', 'Fourth'),
('fifth', 'Fifth'),
('sixth', 'Sixth'),
('seventh', 'Seventh'),
('eight', 'Eight'),
('all', 'All'),
)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='semesters')
registration_number = models.CharField(null=True, blank=True, max_length=20)
semester = models.CharField(max_length=50, choices=semester_choices, null=True, blank=True)
class Subject(BaseModel):
semester = models.ForeignKey(Semester, on_delete=models.CASCADE, related_name='semester_subjects')
gpa = models.CharField(max_length=20)
subject = models.CharField(max_length=50)
You could create a Serializer for your user, and adding a method field that retrieve all the subjects of the user like this.
def get_subjects(self,instace):
subjects = Subject.objects.filter(user=instance)
return SubjectSerializer(subjects, many=True)
What you want is an aggregation of existing data to have a more meaningful result for frontend. I'd rather generating my own response than using a serializer for this.
Here is a simple example for you.
Let's say you want results for multiple users. (It's even easier if you want for one user)
def get_item_with_attribute_from_list(items, attribute, attribute_value):
"""
This is just a utility function that I use occasionally
"""
if items is None or len(items) == 0:
return None
if isinstance(items[0], dict):
for item in items:
if item.get(attribute) == attribute_value:
return item
else:
for item in items:
if getattr(item, attribute, None) == attribute_value:
return item
results = Result.objects.all().select_related('user')
response = []
for result in results:
user_dict = get_item_with_attribute_from_list(response, "user", result.user.name)
subject = {"gpa": "A", "subject": "data structures"}
if user_dict:
semester_list = user_dict['semesters']
semester = get_item_with_attribute_from_list(semester_list, 'semester_name', result.semester)
if semester:
semester['subjects'].append(subject)
else:
semester_list.append({'subjects': [subject]})
else:
response.append({'user': result.user.name, 'semesters': [{'semester_name': result.semester, 'subjects': [subject]}]})
Resulting JSON will be something like this.
[
{
"user": "daniel james",
"semesters": [
{
"semester_name": "first",
"subjects": [
{
"gpa": "a+",
"subject": "maths"
},
{
"gpa": "A",
"subject": "data structures"
}
]
},
{
"semester_name": "second",
"subjects": [
{
"gpa": "b+",
"subject": "geometry"
},
{
"gpa": "C",
"subject": "chemistry"
}
]
}
]
},
... # Other user's data
]
This way, you'll have more structured data, you'll be able to calculate SPA's for each semester easily.

how to create multiple objects with one request DRF

I have the following models
class Product(models.Model):
name = models.CharField(null=True, blank=True, max_length=500)
category = models.CharField(null=True, blank=True, max_length=120)
class SpecificationName(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE, null=True, related_name='specifications')
name = models.CharField(max_length=125)
class Attribute(models.Model):
spec_name = models.ForeignKey(SpecificationName, on_delete=models.CASCADE, null=True, related_name='attributes')
index = models.CharField(max_length=200, blank=True, null=True)
value = models.CharField(max_length=250, blank=True, null=True)
after saving objects in Django admin I have an example
{
"name": "Apple Smart Watch",
"category": "IT",
"specifications": [
{
"name": "Test Data",
"attributes": [
{
"index": "test",
"value": "test2"
},
{
"index": "test7",
"value": "test8"
},
{
"index": "test9",
"value": "test10"
}
]
},
{
"name": "Test Data Continued",
"attributes": [
{
"index": "bla",
"value": "bla1"
},
{
"index": "bla 2",
"value": "bla 4"
},
{
"index": "test9",
"value": "test10"
}
]
},
{
"name": "Test Spec",
"attributes": []
}
]
}
I need to save this kind of object with one request but I am failing to do this
my serializer looks like this
class ProductSerializer(serializers.ModelSerializer):
specifications = SpecNameSerializer(many=True)
# attributes = AttributeSerializer(many=True, required=False)
class Meta:
model = Product
fields = ['name', 'category', 'brand', 'price', 'specifications']
def create(self, validated_data):
specs = validated_data.pop('specifications')
instance = Product.objects.create(**validated_data)
for spec in specs:
SpecificationName.objects.create(product=instance, **spec)
print(spec)
return instance
with this code, I am getting the following result but not as expected
{
"name": "Appel watch series",
"specifications": [
{
"name": "Test Data",
"attributes": []
},
{
"name": "Test Data comn",
"attributes": []
},
{
"name": "Test Spec",
"attributes": []
}
]
}
it cannot write into attributes
I searched for many answers but I did not find or applied some of them, again it did not help me. I am using just ListCreateView in the views. Please is there anybody who can help solve this problem. Thanks in advance!
SOLVED
I am using here ModelSerializer instead I used Serializer and added some changes here my answer and it worked
class AttributeSerializer(serializers.Serializer):
index = serializers.CharField(max_length=200)
value = serializers.CharField(max_length=200)
class SpecNameSerializer(serializers.ModelSerializer):
attributes = AttributeSerializer(many=True)
class Meta:
model = SpecificationName
fields = '__all__'
class ProductSerializer(serializers.ModelSerializer):
specifications = SpecNameSerializer(many=True)
class Meta:
model = Product
fields = ['name', 'category', 'brand', 'price', 'specifications']
def create(self, validated_data):
specs = validated_data.pop('specifications')
instance = Product.objects.create(**validated_data)
for spec in specs:
SpecificationName.objects.create(product=instance, **spec)
attrs = spec.pop('attributes')
for attr in attrs:
Attribute.objects.create(spec_name=spec, **attr)
return instance

How to print model fields as json output?

views.py
def districts_list(request):
obj_districts_list = Districts.objects.all()
data = serializers.serialize(
'json', obj_districts_list, fields=('district_name'))
return HttpResponse(data, content_type="application/json")
models.py
class Districts(models.Model):
id = models.AutoField(primary_key=True)
district_name = models.CharField(max_length=40)
country = models.ForeignKey('Country', on_delete=models.CASCADE)
state = models.ForeignKey('States', on_delete=models.CASCADE)
def __str__(self):
return '{}'.format(self.district_name)
OUTPUT:
But i just want the fields inside the Accounts.districts as output in JSON format.
Use QuerySet.values() to retrieve the fields you're interested in as dicts, then pass this to json.dumps(), ie:
>>> qs = User.objects.values("username", "first_name", "last_name", "email", "userprofile__nickname")
>>> print(json.dumps(list(qs), indent=2))
[
{
"username": "toto",
"first_name": "",
"last_name": "",
"email": "toto#example.com",
"userprofile__nickname": "Toto le toto"
},
{
"username": "root",
"first_name": "Root",
"last_name": "Root",
"email": "root#example.com",
"userprofile__nickname": "Root"
},
]
Depending on your models fields, you may have to provide a custom JSONDecoder subclass for datetimes and other types not directly handled by the default JSONEncoder.

Django Rest Framework relationship queries in nested serializer

I am having difficulties in implementing nested serializers in Django REST Framework.
I'm building an Online score board, for which I currently have three models and I'm trying to serialize it into a single response.
models.py
class Player(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
def __str__(self):
return self.first_name
class Event(models.Model):
user = models.ManyToManyField("Player")
name = models.CharField(max_length=50)
desc = models.CharField(max_length=225)
def __str__(self):
return self.name
class LeadBoard(models.Model):
"""model for LeadBoard"""
player = models.ForeignKey(Player, on_delete=models.CASCADE, related_name='leadboard_player', null=True, blank=True)
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name='leadboard_event', null=True, blank=True)
score = models.IntegerField()
def __str__(self):
return self.score
The event model represent some kind of sports events and each Event can have multiple Players (user filed in Event model), the LeadBoard model stores the score of players in each event.
serializer.py
class PlayerSerializer(serializers.ModelSerializer):
class Meta:
model = Player
fields = ('id','first_name', 'last_name', 'bio')
class EventSerializer(serializers.ModelSerializer):
user = PlayerSerializer(read_only=True, many=True)
class Meta:
model = Event
fields = ('id', 'name', 'user', 'desc')
class LeadBoardSerializer(serializers.ModelSerializer):
event = EventSerializer(read_only=True)
class Meta:
model = LeadBoard
fields = ('id', 'event', 'score')
I have added two Players
[
{
"id": 1,
"first_name": "Jhon",
"last_name": "Doe"
},
{
"id": 3,
"first_name": "Anna",
"last_name": "Doe"
}
]
and their scores in LeadBoard model
[
{
"id": 1,
"player": 1,
"event": 1,
"score": 20
},
{
"id": 2,
"player": 3,
"event": 1,
"score": 90
}
]
This is the response of LeadBoard,
[
{
"id": 1,
"event": {
"id": 1,
"name": "event2020",
"user": [
{
"id": 1,
"first_name": "Jhon",
"last_name": "Doe"
},
{
"id": 3,
"first_name": "Anna",
"last_name": "Doe"
}
],
"desc": "event description"
},
"score": 20
},
{
"id": 2,
"event": {
"id": 1,
"name": "event2020",
"user": [
{
"id": 1,
"first_name": "Jhon",
"last_name": "Doe"
},
{
"id": 3,
"first_name": "Anna",
"last_name": "Doe"
}
],
"desc": "event description"
},
"score": 90
}
]
But what I'm expecting to get is a response like this, which returns the Players(users) of events and their scores correctly.
[
{
"id": 1,
"event": {
"id": 1,
"name": "event2020",
"user": [
{
"id": 1,
"first_name": "Jhon",
"last_name": "Doe",
"score": 20
},
{
"id": 3,
"first_name": "Anna",
"last_name": "Doe",
"score": 90
}
],
"desc": "event description"
}
}
]
What am I missing here?
I'm new to Django and Django Rest Framework.
You need make response by event not by leadboard.
class PlayerSerializer(serializers.ModelSerializer):
class Meta:
model = Player
fields = ('id','first_name', 'last_name', 'bio')
class LeadBoardSerializer(serializers.ModelSerializer):
player = PlayerSerializer(read_only=True)
class Meta:
model = LeadBoard
fields = ('id', 'player', 'score')
class EventSerializer(serializers.ModelSerializer):
leadboard_event = LeadBoardSerializer(read_only=True, many=True)
class Meta:
model = Event
fields = ('id', 'name', 'desc', 'leadboard_event')
now use view to get event list
Update 1
if you want get score in player.
class PlayerSerializer(serializers.Serializer):
player_id = serializers.IntegerField()
first_name = serializers.CharField(max_length=256)
last_name = serializers.CharField(max_length=256)
score = serializers.IntegerField()
class LeadBoardSerializer(serializers.ModelSerializer):
player = serializers.SerializerMethodField()
class Meta:
model = LeadBoard
fields = ('id', 'player')
def get_player(self,obj):
player_dict = {'player_id': obj.player.id, 'first_name': obj.player.first_name, 'last_name': obj.player.last_name, 'score': obj.score}
result = PlayerSerializer(data=player_dict)
return result
class EventSerializer(serializers.ModelSerializer):
leadboard_event = LeadBoardSerializer(read_only=True, many=True)
class Meta:
model = Event
fields = ('id', 'name', 'desc', 'leadboard_event')
Try it.

Get full fields in nested model. Django Rest Framework

I have 2 model classes:
class CustomUser(AbstractUser):
username = models.CharField(max_length=30, unique=True)
tags = models.ManyToManyField('events.Tag', related_name='user_tag', blank=True)
class Tag(models.Model):
name = models.CharField(unique=True, max_length=50)
And serializers:
class UserSerializer(serializers.ModelSerializer):
tags = TagSerializer(many=True)
class Meta:
...
class TagSerializer(serializers.ModelSerializer):
class Meta:
lookup_field = 'name'
model = Tag
fields = ('id', 'name')
When I do a get query I get something like this:
"data": {
"type": "CustomUser",
"id": "6",
"attributes": {
"username": "mercer",
},
"relationships": {
"tags": {
"data": [
{
"type": "Tag",
"id": "1"
}
]
},
}
}
What I want is to get Tag 'name' field in user representation:
"type": "Tag",
"id": "1",
"name":"name"
And I want to make patch query for adding tag to user.
I can use SerializerMethodField(), but this way I will not able to add tags
The problem was with settings of rest framework. I wrote there custom json render classes and recived this form of output. Now i removed it and everything is fine.

Categories