Replace dictionary values containing array of integers with array of objects - django

I am currently working with django and I am able to fetch the JSON of my model.But one of the keys of the JSON contains an array of numbers which I need to replace with array of objects of those numbers.Below is the query to get json of the Contexts model
queryset = serializers.serialize("json", Contexts.objects.all())
This is what I get
[{"model": "app.contexts", "pk": 1, "fields": {"context_name": "tech-experts", "context_description": "this is for tech experts", "context_priority": "H", "users": [1, 3, 4]}}, {"model": "app.contexts", "pk": 2, "fields": {"context_name": "video-conf-issue", "context_description": "bla bla", "context_priority": "H", "users": [4, 5]}}, {"model": "app.contexts", "pk": 3, "fields": {"context_name": "video-conf-issue", "context_description": "bla bla", "context_priority": "L", "users": [3]}}, {"model": "app.contexts", "pk": 15, "fields": {"context_name": "Network debug", "context_description": "Group for debugging network issues", "context_priority": "L", "users": [2]}}]
Now I am interested in just the fields values.So I do this
result = [i.get('fields') for i in ast.literal_eval(queryset)]
So now I get this
[{'context_priority': 'H', 'context_name': 'tech-experts', 'context_description': 'this is for tech experts', 'users': [1, 3, 4]}, {'context_priority': 'H', 'context_name': 'video-conf-issue', 'context_description': 'bla bla', 'users': [4, 5]}, {'context_priority': 'L', 'context_name': 'video-conf-issue', 'context_description': 'bla bla', 'users': [3]}, {'context_priority': 'L', 'context_name': 'Network debug', 'context_description': 'Group for debugging network issues', 'users': [2]}]
Now as you can see users has an array which contains integers.Basically these integers are user ids and I want the user objects of these ids.
So my User model object for the userId 1, it will be
User.objects.filter(userId=1)
So in order to achieve this I do the below operation
[i.update({"users":[].append(User.objects.filter(userId=j))}) for i in result for j in i.get("users")]
But now I get the resulting value for the key users as None
[{'context_description': 'this is for tech experts', 'users': None, 'context_priority': 'H', 'context_name': 'tech-experts'}, {'context_description': 'bla bla', 'users': None, 'context_priority': 'H', 'context_name': 'video-conf-issue'}, {'context_description': 'bla bla', 'users': None, 'context_priority': 'L', 'context_name': 'video-conf-issue'}, {'context_description': 'Group for debugging network issues', 'users': None, 'context_priority': 'L', 'context_name': 'Network debug'}]
How can I achieve this?
Added the Contexts and User model below
class User(models.Model):
userId = models.PositiveIntegerField(null = False)
pic = models.ImageField(upload_to=getUserImagePath,null=True)
Email = models.EmailField(null = True)
class Contexts(models.Model):
context_name = models.CharField(max_length=50)
context_description = models.TextField()
context_priority = models.CharField(max_length=1)
users = models.ManyToManyField(User, related_name='context_users')

change
[i.update({"users":[].append(User.objects.filter(userId=j))}) for i in result for j in i.get("users")]
to
[i.update({"users":[].append(User.objects.filter(pk=j))}) for i in result for j in i.get("users")]

Related

how to get only values from query dict

if request.method == 'POST':
product=request.POST.get('product')
upload_month = request.POST.get('upload_month')
un_month= Planning_quantity_data.objects.values('month').filter(product=product,upload_month=upload_month).distinct()
print(un_month)
<QuerySet [{'month': 'Mar_22'}, {'month': 'Apr_22'}, {'month': 'May_22'}, {'month': 'Jun_22'}]>
I want to get only the values without key and store it in a new list in
views.py file:
like newlist = ['Mar_22' , 'Apr_22', 'May_22','Jun_22']
while I am using
un_month1=list(un_month.values())
print(un_month1)
It is showing like something this:
[{'id': 1, 'upload_month': 'Mar_22', 'product': 'MAE675', 'material_code': 'MAE675 (MEMU â OB) RCF', 'order_type': 'Onhand', 'BOM_CODE': '675MEMU', 'month': 'Mar_22', 'quantity': 3, 'po_value': '37/5', 'remarks': 'Qty in Rakes. 3-5 rakes partial qty dispatched', 'empid': None}, {'id': 2, 'upload_month': 'Mar_22', 'product': 'MAE675', 'material_code': 'MAE675 (MEMU â OB) RCF', 'order_type': 'Onhand', 'BOM_CODE': '675MEMU', 'month': 'Apr_22', 'quantity': 3, 'po_value': '37/5', 'remarks': 'Qty in Rakes. 3-5 rakes partial qty dispatched', 'empid': None}, {'id': 3, 'upload_month': 'Mar_22', 'product': 'MAE675', 'material_code': 'MAE675 (MEMU â OB) RCF', 'order_type': 'Onhand', 'BOM_CODE': '675MEMU', 'month': 'May_22', 'quantity': 3, 'po_value': '37/5', 'remarks': 'Qty in Rakes. 3-5 rakes partial qty dispatched', 'empid': None}]
If you use values_list() [django-docs] with a single field, you can use flat=True to return a QuerySet of single values, I mean:
if request.method == 'POST':
product=request.POST.get('product')
upload_month = request.POST.get('upload_month')
newlist = list(Planning_quantity_data.objects.filter(product=product,upload_month=upload_month).values_list('month', flat=True))
print(newlist)
And this will print just ['Mar_22', 'Apr_22', 'May_22', 'Jun_22'] for you.

Replace null values with mean for specific columns in pyspark

I would like to replace null values with mean for the age and height column. I know there is a post
Fill Pyspark dataframe column null values with average value from same column
but in this post the given function throws an error.
df = spark.createDataFrame([(1, 'John', 1.79, 28,'M', 'Doctor'),
(2, 'Steve', 1.78, 45,'M', None),
(3, 'Emma', 1.75, None, None, None),
(4, 'Ashley',1.6, 33,'F', 'Analyst'),
(5, 'Olivia', 1.8, 54,'F', 'Teacher'),
(6, 'Hannah', 1.82, None, 'F', None),
(7, 'William', 1.7, 42,'M', 'Engineer'),
(None,None,None,None,None,None),
(8,'Ethan',1.55,38,'M','Doctor'),
(9,'Hannah',1.65,None,'F','Doctor')]
, ['Id', 'Name', 'Height', 'Age', 'Gender', 'Profession'])
the function in the post given
def fill_with_mean(df, exclude=set()):
stats = df.agg(*(
avg(c).alias(c) for c in df.columns if c not in exclude
))
return df.na.fill(stats.first().asDict())
fill_with_mean(df, ["Age", "Height"])
when I run this function, it says
NameError: name 'avg' is not defined
Can anybody fix this? Thank you.
Fixed example. It works for me in a way as you expect!
from pyspark.sql.functions import avg
df = spark.createDataFrame(
[
(1, 'John', 1.79, 28, 'M', 'Doctor'),
(2, 'Steve', 1.78, 45, 'M', None),
(3, 'Emma', 1.75, None, None, None),
(4, 'Ashley', 1.6, 33, 'F', 'Analyst'),
(5, 'Olivia', 1.8, 54, 'F', 'Teacher'),
(6, 'Hannah', 1.82, None, 'F', None),
(7, 'William', 1.7, 42, 'M', 'Engineer'),
(None, None, None, None, None, None),
(8, 'Ethan', 1.55, 38, 'M', 'Doctor'),
(9, 'Hannah', 1.65, None, 'F', 'Doctor')
],
['Id', 'Name', 'Height', 'Age', 'Gender', 'Profession']
)
def fill_with_mean(this_df, exclude=set()):
stats = this_df.agg(*(avg(c).alias(c) for c in this_df.columns if c not in exclude))
return this_df.na.fill(stats.first().asDict())
res = fill_with_mean(df, ["Gender", "Profession", "Id", "Name"])
res.show()

Django Reverse Foreign key with nested serializer gives multiple results

How to generate left outer join query using reverse foreign key relation and map it to the nested serializer? I want to filter result on multiple foreign keys.
models.py
class Question(models.Model):
question_name = models.CharField(max_length=1024)
class Paper(models.Model):
paper_name = models.CharField(max_length=128)
class Answer(models.Model):
score = models.IntegerField()
question_id = models.ForeignKey(Question, related_name='answer_questions')
paper_id = models.ForeignKey(Paper, related_name='answer_papers')
class Meta:
unique_together = ("question_id", "paper_id")
serializers.py
class PaperSerializer(serializers.ModelSerializer):
class Meta:
fields = ('id', 'paper_name')
model = Paper
class AnswerSerializer(serializers.ModelSerializer):
class Meta:
fields = ('id', 'score', 'question_id', 'paper_id')
model = Answer
class QuestionSerializer(serializers.ModelSerializer):
answer_questions = AnswerSerializer(many=True, allow_null=True)
class Meta:
fields = ('id', 'question_name', 'answer_questions')
model = Question
views.py
class QuestionList(generics.ListAPIView):
def get_queryset(self):
paper_id = self.kwargs['pk']
queryset = Question.objects.filter(answer_questions__paper_id=paper_id, answer_questions__question_id=F('id'))
return queryset
serializer_class = QuestionSerializer
My url is
localhost/papers/1/questions/
Expected output:
(1) List of all questions with answer object for corresponding question_id and paper_id only (single answer object) embedded in it.
(2) List should include all questions irrespective of they are answered or not (in case of question not answered, question with empty answer object should be returned) i.e. left outer join
[
{
"id": 1,
"question_id": 1,
"answer_questions": [
{
"id": 24,
"score": 5,
"question_id": 1,
"paper_id": 1
},
{
"id": 27,
"score": 8,
"question_id": 1,
"paper_id": 2
},
{
"id": 28,
"score": 6,
"question_id": 1,
"paper_id": 3
}
]
}
]
Current Output:
(1) I am getting multiple answer objects for particular question_id including all paper_ids. i.e. For question_id = 1 and paper_id = 2, My output shows questions with answer objects for question_id = 1 not filtering on paper_id.
(2) Only answered questions (as query is inner join query)
[
{
"id": 1,
"question_id": 1,
"answer_questions": [
{
"id": 24,
"score": 5,
"question_id": 1,
"paper_id": 1
}
]
}
]
If it's not a good way to implement, kindly suggest better way to optimize it.
I think you'll get desired output if you slightly change the get_quesyset() method.
class QuestionList(generics.ListAPIView):
def get_queryset(self):
return Question.objects.all()
serializer_class = QuestionSerializer
When you access the QuestionList list api you will get the output as follows
[
{
"id": 4,
"question_name": "qus-1",
"answer_questions": [
{
"id": 5,
"score": 50,
"question_id": 4,
"paper_id": 4
},
{
"id": 6,
"score": 10,
"question_id": 4,
"paper_id": 5
}
]
},
{
"id": 5,
"question_name": "qus-2",
"answer_questions": []
},
{
"id": 6,
"question_name": "que-3",
"answer_questions": [
{
"id": 7,
"score": 342,
"question_id": 6,
"paper_id": 4
}
]
}
]
Update-1
Change your serializer as below
class QuestionSerializer(serializers.ModelSerializer):
answer_questions = serializers.SerializerMethodField()
def get_answer_questions(self, question):
paper_id = self.context['view'].kwargs.get('paper_id')
return AnswerSerializer(question.answer_questions.filter(paper_id=paper_id), many=True).data
class Meta:
fields = ('id', 'question_name', 'answer_questions')
model = Question

Django pagination over the page limit showing still last results neverending

I have a Django function based API that inputs page number and on each page the size of the page. Here is my code.
#api_view(['POST'])
def attendance_all_get_list_by_page(request):
# ----- YAML below for Swagger -----
"""
description: attendance_all_get_list_by_page
parameters:
- name: page
type: integer
required: true
location: form
- name: page_limit
type: integer
required: true
location: form
"""
attendance_list = Attendance.objects.all().order_by('id')
page = request.GET.get('page', request.POST['page'])
paginator = Paginator(attendance_list, request.POST['page_limit'])
try:
attendances = paginator.page(page)
except PageNotAnInteger:
attendances = paginator.page(request.POST['page'])
except EmptyPage:
attendances = paginator.page(paginator.num_pages)
serializer = AttendanceSerializer(list(attendances), many=True)
data = serializer.data[:]
return Response(data, status=status.HTTP_200_OK)
my serializer:
class EmployeeSerializer(serializers.ModelSerializer):
class Meta:
model = Employee
fields = ("id", "username")
class AttendanceSerializer(serializers.ModelSerializer):
employee = EmployeeSerializer(many=False, read_only=True)
class Meta:
model = Attendance
fields = ('id','employee','created_at')
Imagine I had attendance record of
16,17,18,19
So for example with page=2 page_limit=2, it will show the following (this should be the last page of 4 records)
[
{
"id": 18,
"employee": {
"id": 16,
"username": "haha"
},
"created_at": "2017-12-28T03:29:29.698339Z"
},
{
"id": 19,
"employee": {
"id": 16,
"username": "haha"
},
"created_at": "2017-12-28T03:38:53.639749Z"
}
]
if I did (page=3 page_limit=2) or (page=10 page_limit=2), it will still show
[
{
"id": 18,
"employee": {
"id": 16,
"username": "haha"
},
"created_at": "2017-12-28T03:29:29.698339Z"
},
{
"id": 19,
"employee": {
"id": 16,
"username": "haha"
},
"created_at": "2017-12-28T03:38:53.639749Z"
}
]
the expected result should be
[]
Whats wrong with my pagination, something is affecting over the last page. I want so that the last page should show the last page result but after that it should be empty record lists.
You catch EmptyPage and return last page content. So if you are out of range you will get second page everytime.
You need to return empty list in this case:
except EmptyPage:
attendances = []

Django rest framework : Do not return array but list of objects with id as key

Django rest framework returns the following output at an API endpoint
[
{
"id": "QFELD_2.3.2.QF1",
"siteuxid": "VBKM02_Abschlusstest",
"section": 2,
"maxpoints": 4,
"intest": true,
"uxid": "KA0",
"points": 0,
"value": 0,
"rawinput": "",
"state": 3
},
{
"id": "QFELD_2.3.2.QF2",
"siteuxid": "VBKM02_Abschlusstest",
"section": 2,
"maxpoints": 4,
"intest": true,
"uxid": "KA1",
"points": 0,
"value": 0,
"rawinput": "",
"state": 3
},
...
Is it possible to return the data in an list object format like:
{
"QFELD_2.3.2.QF1" : {
"siteuxid": "VBKM02",
"section": 2,
"maxpoints": 4,
"intest": true,
"uxid": "KA0",
"points": 0,
"value": 0,
"rawinput": "",
"state": 3
},
"QFELD_2.3.2.QF2" : {
"siteuxid": "VBKM02",
"section": 2,
"maxpoints": 4,
"intest": true,
"uxid": "KA1",
"points": 0,
"value": 0,
"rawinput": "",
"state": 3
},
...
My Serializer is:
class ScoreSerializer(serializers.ModelSerializer):
id = serializers.CharField(required=False, allow_blank=True, max_length=100, source='q_id')
class Meta:
model = Score
fields = ('id', 'siteuxid', 'section', 'maxpoints', 'intest', 'uxid', 'points', 'value', 'rawinput', 'state')
And View is:
class ScoreViewSet(viewsets.ModelViewSet):
serializer_class = ScoreSerializer
The ListMixin code a is good place to get started. You should get the serializer's result and transform it as you like.
class ListModelMixin(object):
"""
List a queryset.
"""
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
# Might need to change this not to transform all the data
data = {i['id']: i for i in serializer.data}
return self.get_paginated_response(data)
serializer = self.get_serializer(queryset, many=True)
data = {i['id']: i for i in serializer.data}
return Response(data)