models.py:
class Order(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE, null=True)
order_quantity = models.PositiveIntegerField(null=True)
date = models.DateTimeField(auto_now_add=True)
class Product(models.Model):
name = models.CharField(max_length=100, choices=PRODUCTS, null = True)
rate = models.PositiveIntegerField(null = True)
Views.py:
def index(request):
orders = Order.objects.all()
context = {
'orders': orders,
}
return render(request,'index.html', context)
Here I have multiple orders for samsung, apple etc. There should be only one data for samsung, apple and so on. How can I aggregate order_quantity for each product and send data as the format required for the data?
I need the following data format to show data in amchart bar diagram. How can I achieve it?
Format required for graph
var data = [
{
name: "Samsung",
value: 35654,
},
{
name: "Apple",
value: 65456,
},
{
name: "Xiomi",
value: 45724,
},
];
Could you do:
Order.objects.annotate(total_items_sold=Sum("order_set__order_quantity").values("name", "items_sold")
Which you then convert to a list of dictionaries? I.e. the data format you require.
Related
I am working on creating a GET only endpoint that shows the standings of a given season for a sports league. Honestly, at this point I have tried nearly everything with no luck. All other Serializers work fine so far and there is no issue with the way my database is setup. I have omitted many fields and tables due to the complexity, but anything relevant to the question is included below.
First, let me show you the rough format of how I want to JSON to be returned.
Sample Response (The end goal)
{
divisions: [
{
"divisionName": "WEEKNIGHT B",
"divisionId": "ee68d8ab-2752-4df6-b11d-d289573c66df",
teams: [
{
"teamId": "b07560bc-aac2-4c6c-bbfe-11a368137712",
"statsId": "53852698-9b78-4f36-9a2e-4751b21972f9",
"teamName": "FNA",
},
{
"teamId": "406eb5aa-6004-4220-b219-59476a3136d1",
"statsId": "a96ebf10-87c5-4f19-99c3-867253f4a502",
"teamName": "COPENHAGEN ROAD SODAS",
},
]
},
{
"divisionName": "WEEKNIGHT C",
"divisionId": "4e1469ae-2435-4a3d-a621-19a979ede7c1",
teams: [
{
"teamId": "ebc7e632-073e-4484-85f9-29c0997bec25",
"statsId": "cd6373a7-4f53-4286-80f2-eb3a8a49ee3a",
"teamName": "HAWKS",
"gamesPlayed": 29,
},
{
"teamId": "d8cda7a6-15f4-4e8f-8c65-ef14485957e4",
"statsId": "4492a128-763a-44ad-9ffa-abae2c39b425",
"teamName": "DUISLANDERS",
},
]
}
]
}
Through the URL I am passing in the Season ID, so everything is based off the season id. Below is an example of how I can replicate the type of response I want, by iterating through some queries which I know is rather messy, but I am using it just for example purposes.
Sample Query to show how it can be done using queries
standingsDict = {
"standings": []
}
divisionList = []
season = Season.objects.get(name='Fall 2021')
divisions = Division.objects.filter(seasondivision__season__id=season.id)
for div in divisions:
teamstats = TeamStats.objects.filter(
season_division_team__season_division__season_id=season.id,
season_division_team__season_division__division_id=div)
divDict = {
"divisionName": div.name,
"divisionId": div.id,
"teams": []
}
teamsList = []
for stats in teamstats:
teamDict = {
"teamId": stats.season_division_team.team.id,
"statsId": stats.id,
"seasonDivisionTeamId": stats.season_division_team_id,
"teamName": stats.season_division_team.team.name,
}
teamsList.append(teamDict)
divDict['teams'] = teamsList
divisionList.append(divDict)
standingsDict['standings'] = divisionList
Output Snippet of that loop
{
"standings":[
{
"divisionName":"WEEKNIGHT B",
"divisionId":"UUID(""ee68d8ab-2752-4df6-b11d-d289573c66df"")",
"teams":[
{
"teamId":"UUID(""756ea44f-885f-4ea0-ae4c-8a72c894067f"")",
"statsId":"UUID(""8ef1f683-ad5b-40d8-9277-0c2689cff771"")",
"seasonDivisionTeamId":"UUID(""19e29f9a-af04-4a4f-9e38-bad0cbf8817d"")",
"teamName":"GABAGOOLS"
},
{
"teamId":"UUID(""aefdc0dc-e2aa-4ce5-ad28-47f0724b57ab"")",
"statsId":"UUID(""05e0012c-0adc-4d15-bbc5-901e49489667"")",
"seasonDivisionTeamId":"UUID(""8adab3d1-7614-4ece-92f5-f0ab34b23c4c"")",
"teamName":"LONG BEACH THUNDER MAJOR"
},
Currently with the way everything is setup, I can traverse the FK Relationships to get them in a forward manner, for example, I can go from SeasonDivisionTeam, get the TeamStatsSerializer, and for each team, I can display the division. But that displays the same division multiple times for all the Team Stats, which is not what I am looking for.
Models
class BaseModel(LifecycleModelMixin, models.Model):
date_modified = models.DateTimeField(auto_now=True)
date_created = models.DateTimeField(auto_now_add=True)
id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False)
class Meta:
abstract = True
class Season(BaseModel):
name = models.CharField(max_length=50)
startDate = models.DateField(null=True, blank=True)
endDate = models.DateField(null=True, blank=True)
class Division(BaseModel):
name = models.CharField(max_length=50)
seasons = models.ManyToManyField(Season, through='SeasonDivision')
class SeasonDivision(LifecycleModelMixin, models.Model):
id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False)
division = models.ForeignKey(Division, on_delete=models.CASCADE)
season = models.ForeignKey(Season, on_delete=models.CASCADE)
class Team(BaseModel):
name = models.CharField(max_length=50)
season_divisions = models.ManyToManyField(SeasonDivision, through='SeasonDivisionTeam')
class SeasonDivisionTeam(LifecycleModelMixin, models.Model):
id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False)
team = models.ForeignKey(Team, on_delete=models.CASCADE)
season_division = models.ForeignKey(SeasonDivision, on_delete=models.CASCADE)
class Player(BaseModel):
season_division_teams = models.ManyToManyField(SeasonDivisionTeam, through='SeasonDivisionTeamPlayer')
firstName = models.CharField(max_length=80)
class SeasonDivisionTeamPlayer(LifecycleModelMixin, models.Model):
id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False)
player = models.ForeignKey(Player, on_delete=models.CASCADE)
season_division_team = models.ForeignKey(SeasonDivisionTeam, on_delete=models.CASCADE)
class PlayerStats(BaseModel):
season_division_team_player = models.ForeignKey(SeasonDivisionTeamPlayer, on_delete=models.CASCADE)
goals = models.IntegerField(default=0)
class TeamStats(BaseModel):
season_division_team = models.ForeignKey(SeasonDivisionTeam, on_delete=models.CASCADE)
regWins = models.IntegerField(default=0)
Serializers (Many of these have been changed multiple times, so what I have below is just the last thing I was testing that didn't work. )
class StandingsSerializer(serializers.ModelSerializer):
teamstats = TeamStatsSerializer(many=True, source='teamstats_set')
class Meta:
model = SeasonDivisionTeam
fields = [
"teamstats",
]
depth = 1
Views (Same as above, have done alot of testing with these, so what I have below is just the most recent test)
class StandingsList(generics.ListCreateAPIView):
queryset = Season.objects.order_by('-endDate').all()
serializer_class = StandingsSerializer
def get_queryset(self):
season_id = self.request.query_params.get('season_id')
queryset = SeasonDivisionTeam.objects.filter(season_division__season_id=season_id)
return queryset
I'm trying to build a way to return grouped counts of another object based on specific filtering criteria. As an example, given the following model with the following sample data, I'd like to create a call that will return the following result:
The Model:
class Task(models.Model):
class Meta:
db_table = "task"
id = models.UUIDField(
db_column="task_id", primary_key=True, default=uuid.uuid4, editable=False
)
start_date = models.DateTimeField()
due_date = models.DateTimeField()
task_status = models.CharField(max_length=250)
)
Sample Data:
id start_date due_date task_status
624d8126... 2021-01-01 2021-03-02 in progress
171a7969... 2021-03-01 2021-02-28 assigned
92f6e493... 2021-04-01 2021-04-10 completed
a5722f6f... 2021-04-03 2021-04-08 assigned
e884efcb... 2021-05-01 2021-04-30 available
Desired Result (or something similar)
getTaskCounts
{
taskCount
{
countType: "behind schedule",
count: 2
},
taskCount
{
countType: "in progress",
count: 2
},
taskCount
{
countType: "completed",
count: 1
}
}
Note I'm grouping the various statuses based on the desired result.
You can define custom object type like:
class TaskCount(graphene.ObjectType):
count_type = graphene.String()
count = graphene.Int()
and then define another object to return a grouped list of them like:
from django.db.models import Count
class TaskCounts(graphene.ObjectType):
task_counts = graphene.List(TaskCount)
def resolve_task_counts(self, info):
# Query for grouping -- test in Django shell
grouped_tasks = Task.objects
.values('task_status')
.annotate(count=Count('task_status'))
.order_by()
return [
TaskCount(count_type=grouped_task.task_status, count=grouped_task.count) for grouped_task in grouped_tasks
]
My data input is in the form of list of 'n' number of dicts
"contact_person":[
{
"contactperson_salutation[0]":"sddd",
"contactperson_first_name[0]":"santoorr",
"contactperson_last_name[0]":"",
"contactperson_email[0]":"gfgh",
"contactperson_mobile_number[0]":"",
"contactperson_work_phone_number[0]":"jio"
},
{
"contactperson_salutation[1]":"dfsf",
"contactperson_first_name[1]":"lux",
"contactperson_last_name[1]":"",
"contactperson_email[1]":"",
"contactperson_mobile_number[1]":"",
"contactperson_work_phone_number[1]":"9048"
}, .............]
My model is like this:
class ContactPerson(models.Model):
client = models.ForeignKey(Client, on_delete=models.CASCADE)
contactperson_salutation = models.CharField(max_length=4, choices=SALUTATIONS)
contactperson_first_name = models.CharField(max_length=128)
contactperson_last_name = models.CharField(max_length=128, blank=True)
contactperson_email = models.EmailField(blank=True, null=True)
contactperson_mobile_number = models.CharField(max_length=20, blank=True)
contactperson_work_phone_number = models.CharField(max_length=20, blank=True)
How to write serializer when the fields names are changing for every dict in the input list..
And if errors occurs the Error Response should be in this format:
[
{
"contactperson_email[0]":"Invalid Email",
"contactperson_mobile_number[0]":"Invalid mobile phone",
"contactperson_work_phone_number[0]":"Invalid workphone number"
},
{
"contactperson_mobile_number[1]":"Invalid mobile phone",
"contactperson_work_phone_number[1]":"Invalid workphone number"
}
]
You would probably benefit from parsing the "contactperson_salutation[0]"-like strings to build a list contactperson_salutation with all the ocurrences.
Same thing for each of the other fields.
try overwriting the to_internal_value method of the Serializer to achieve this. But the error would still be not in the format you require.
The error message will contain your model keys, not the keys which are suffixed with [x].
class ContactPersonSerializer(serializers.ModelSerializer):
class Meta:
model = ContactPerson
fields = [
"contactperson_salutation",
"contactperson_first_name",
"contactperson_last_name",
"contactperson_email",
"contactperson_mobile_number",
"contactperson_work_phone_number",
]
def to_internal_value(self, data):
if hasattr(data, "_mutable"):
data._mutable = True
data = {key[:-3]: value for key, value in data.items()}
if hasattr(data, "_mutable"):
data._mutable = False
return super().to_internal_value(data)
I manage to get time series data with TruncYear/TruncMonth/TruncDay/etc like below from Tracking table. However the data for the venue just produce the venue_id. I would like to have that serialized so that it returns the "name" from the relation Venue table.
I am using Django 1.11 a postgres 9.4
Here is my time series code:
tracking_in_timeseries_data = Tracking.objects.annotate(
year=TruncYear('created_at')).values('year', 'venue_id').annotate(
count=Count('employee_id',
distinct = True)).order_by('year')
return Response(tracking_in_timeseries_data, status=status.HTTP_200_OK)
currently it output like this:
[
{
"venue_id": 4,
"year": "2017-01-01T00:00:00Z",
"count": 1
},
{
"venue_id": 2,
"year": "2018-01-01T00:00:00Z",
"count": 2
},
{
"venue_id": 6,
"year": "2019-01-01T00:00:00Z",
"count": 1
}
]
I want to explode venue data to return the id & name like this:
[
{
"venue": {
id: 4,
name: "room A"
},
"year": "2017-01-01T00:00:00Z",
"count": 1
},
{
"venue": {
id: 2,
name: "room B"
},
"year": "2018-01-01T00:00:00Z",
"count": 2
},
{
"venue": {
id: 6,
name: "room C"
},
"year": "2019-01-01T00:00:00Z",
"count": 1
}
]
How to explode the "venue" to return the id and name ? The name is useful for presentation purpose.
UPDATE (here are some attempts that failed):
this only displays count but accumulative ( https://gist.github.com/axilaris/0cd86cec0edf675d654eadb3aff5b066). something weird and not sure why.
class TimeseriesSerializer(serializers.ModelSerializer):
venue = VenueNameSerializer(source="venue_id",many=False, read_only=True)
year = serializers.TimeField(read_only=True)
count = serializers.IntegerField(read_only=True)
class Meta:
model = Tracking
fields = ("venue",
"year",
"count")
class TimeseriesSerializer(serializers.Serializer): <-- here is another try but doesnt work serializers.Serializer
venue_id = VenueNameSerializer(many=False, read_only=True)
year = serializers.TimeField(read_only=True)
count = serializers.IntegerField(read_only=True)
I think the answer is quite close to this: django rest framework serialize a dictionary without create a model
FYI, this is my actual code (must as well put it here) for the test, names may differ slightly but the whole intention is the same. https://gist.github.com/axilaris/919d1a20d3e799101a8cf6aeb4d120b5
What you need is to create a serializer for the Venue which displays the id and name fields and use it as a field in the TrackingSerializer.
In your case there is something more to consider: since you are using values to group, what you get from the queryset is not a Tracking object, thus your venue_id can't be translated to a Venue object by DRF.
To fix this you need to override the to_representation method of VenueSerializer to get the Venue object from its primary key.
I'm including models and views to give you a working example, but you probably only need serializers and the adjusted queryset from the view.
Models
class Employee(models.Model):
first_name = models.CharField(max_length=128)
last_name = models.CharField(max_length=128)
class Venue(models.Model):
name = models.CharField(max_length=128)
class Tracking(models.Model):
venue = models.ForeignKey(Venue)
employee = models.ForeignKey(Employee)
created_at = models.DateTimeField(auto_now_add=True)
Views
class TrackingViewSet(viewsets.ModelViewSet):
queryset = (
Tracking.objects
.annotate(
year=ExtractYear('created_at'),
)
.values('year', 'venue')
.annotate(
count=Count('employee_id', distinct=True),
)
.order_by('year')
)
serializer_class = TrackingSerializer
Serializers
class VenueSerializer(serializers.ModelSerializer):
class Meta:
model = Venue
fields = ['id', 'name']
def to_representation(self, value):
value = Venue.objects.get(pk=value)
return super(VenueSerializer, self).to_representation(value)
class TrackingSerializer(serializers.ModelSerializer):
venue = VenueSerializer(read_only=True)
year = serializers.IntegerField(read_only=True)
count = serializers.IntegerField(read_only=True)
class Meta:
model = Tracking
fields = ['venue', 'year', 'count']
Note that I replaced your TruncYear with ExtractYear, the difference between the two is that the former returns a datetime, the latter an int which is what you want I guess.
If you prefer to use TruncYear you will have to replace:
year = serializers.IntegerField(read_only=True)
with:
year = serializers.DateTimeField(read_only=True)
in TrackingSerializer.
I would like to return a given row and the row before and after it (sorted by file_created_time desc) when calling GET with a uid parameter representing the row.
URL ex: https://<domain>/api/videos/cbf02e8c-b2f5-4cd8-b3ec-87417eae2f7d?with_adjacent=true
{
"uid": "fd5d5936-8183-495f-9a9d-8ffca25a9bab",
"is_thumbnail": true,
"file_name": "2018-02-03_05-00-40.jpg",
"file_path": "thumbnails/2018-02-03_05-00-40.jpg",
"file_created_time": "2018-02-03T05:00:40-07:00",
"owner": "system_user",
"created_time": "2018-02-04T14:49:29.355156-07:00"
},
{
"uid": "cbf02e8c-b2f5-4cd8-b3ec-87417eae2f7d",
"is_thumbnail": true,
"file_name": "2018-02-03_01-09-30.jpg",
"file_path": "thumbnails/2018-02-03_01-09-30.jpg",
"file_created_time": "2018-02-03T01:09:30-07:00",
"owner": "system_user",
"created_time": "2018-02-04T14:49:30.464810-07:00"
},
{
"uid": "ed626576-cc9d-4434-9f44-93a4f8f525ad",
"is_thumbnail": true,
"file_name": "2018-02-03_00-59-15.jpg",
"file_path": "thumbnails/2018-02-03_00-59-15.jpg",
"file_created_time": "2018-02-03T00:59:15-07:00",
"owner": "system_user",
"created_time": "2018-02-04T14:49:32.611105-07:00"
}
Given the model:
class Videos(models.Model):
"""This class represents the Videos model."""
uid = models.UUIDField(
primary_key=True, default=uuid.uuid4, editable=False)
is_thumbnail = models.BooleanField(default=False)
file_name = models.CharField(unique=True, max_length=64)
file_path = models.CharField(unique=True, max_length=256)
file_created_time = models.DateTimeField()
owner = models.ForeignKey('auth.User',
related_name='videos',
on_delete=models.CASCADE)
created_time = models.DateTimeField(auto_now_add=True)
def __str__(self):
"""Return a human readable representation of the model instance."""
return "{}".format(self.file_name)
And View:
class DetailsView(generics.RetrieveUpdateDestroyAPIView):
"""This class handles the http GET, PUT and DELETE requests."""
queryset = Videos.objects.all()
serializer_class = VideosSerializer
permission_classes = (permissions.IsAuthenticated, IsOwner)
lookup_field = 'uid'
I'm happy the adjust the view as necessary, that's just what I have now.
Edit:
To further complicate this, this model contains rows where is_thumbnail is either true or false. Thus, assuming I change my pk to an id, if I want to select an is_thumbnail = True row sorted by file_created_time, there's no guarantee that its adjacent rows are pk +/- 1.
Apart from my other answer, I found a better way (think so) to achieve the result.I'm only adding the key part of the snippet
....
vid_1 = Videos.objects.get(uid=input_uid)
vid_2 = vid_1.get_next_by_file_created_time()
vid_3 = vid_1.get_previous_by_file_created_time()
queryset = [vid_1, vid_2, vid_3]
return Response(VideosSerializer(queryset,many=True).data)
We could get these kinds of things only if DateTime field is not null.
for more, refer this official documentation and stackoverflow answer