how to apply a condition to a queryset in django - python

I am new to programming, I have a doubt I formed the QuerySet with table data i want to know how to apply condition to the formed queryset and get the count.
Code :
final_set = TaskMaster.objects.filter(istaskactive=True)
I want something like
no_of_rebuild_task = final_set..objects.filter(tasktype.id=1).count
model.py
class TaskMaster(models.Model):
sid = models.CharField(max_length=3)
# Remember to change the default value in processor in production
processor = models.ForeignKey(User,null=True,on_delete=models.CASCADE,default=1)
tasktype = models.ForeignKey(TaskTypeTable, null=True,on_delete=models.CASCADE)
task_title = models.TextField(null=True)
task_description = models.TextField(null=True)
datacenter = models.ForeignKey(DatacenterTable,null=True,on_delete=models.CASCADE)
priority = models.ForeignKey(PriorityTable, null=True,on_delete=models.CASCADE)
status = models.ForeignKey(StatusTable, default=1,on_delete=models.CASCADE)
pid = models.IntegerField(null=True)
sourceincident = models.CharField(max_length=250,null=True)
errorincident = models.CharField(max_length=250,null=True)
processingteam =
models.ForeignKey(TeamTable,null=True,on_delete=models.CASCADE)
createddate = models.DateField(("Date"), default=datetime.date.today)
duedate = models.DateField(("Date"), default=datetime.date.today)
istaskactive = models.BooleanField(default=True)

In Django ORM you can use count() to count the number of records in the selected table.
So for your query it can be
no_of_rebuild_task = TaskMaster.objects.filter(istaskactive=True, tasktype_id=1).count()
See effective way of Django ORM
and count() here.

no_of_rebuild_task = final_set.filter(tasktype__id=1).count()

Related

How to return sum according to date range in django?

It'd be really nice if someone could help me with this. I've stuck here. I'm able to do this manually but how to do according to user input.
Payment.objects.filter(created_by=42, mode='cash', created_at__range=["2021-11-01", "2021-11-04"]).aggregate(Sum('amount'))
Here created_by and date_range I'm sending in url like this : http://127.0.0.1:8000/api/v1/registration/?created_by=42&start_date=2021-06-06&end_date=2021-11-18 so the id created by and date_range will always change. And according to change the sum will return.
My Model :
class Payment(TimestampedModel):
customer_visit = models.ForeignKey(
CustomerVisit, on_delete=models.CASCADE, null=True, related_name="customer_payments"
)
mode = models.CharField(choices=PAYMENTCHOICES, max_length=25)
amount = models.FloatField()
ref_no = models.TextField(null=True)
bank = models.ForeignKey(
"BankDetails", on_delete=models.CASCADE, null=True, related_name="payment_bank"
)
is_settlement = models.BooleanField(default=False)
created_by = models.ForeignKey("Employee", on_delete=models.DO_NOTHING, null=True,related_name='payment_created_by')
updated_by = models.ForeignKey("Employee", on_delete=models.DO_NOTHING, null=True,related_name='payment_updated_by')
My View :
class UserWiseCollectionView(ListAPIView):
permission_classes = [
IsAuthenticated,
]
pagination_class = CustomPagination
model = CustomerVisit
serializer_class = UserWiseCollectionSerializer
filter_backends = [DjangoFilterBackend]
filterset_fields = ['created_by']
def get_queryset(self):
start_date = self.request.query_params.get("start_date")
end_date = self.request.query_params.get("end_date")
emp_id = self.request.query_params.get("emp_id")
items = self.model.objects.all()
if start_date and end_date:
items = items.filter(
created_at__range=[start_date, end_date]
)
if emp_id is not None:
items = items.filter(phelebotomist_id = emp_id)
return items
If requirement is to get all the rows created by specific employee within the specific date range, below code might work.
Requirement
Payment.objects.filter(created_by=42, mode='cash', created_at__range=["2021-11-01", "2021-11-04"]).aggregate(Sum('amount'))
View code
def get_queryset(self):
start_date = self.request.query_params.get("start_date")
end_date = self.request.query_params.get("end_date")
emp_id = self.request.query_params.get("emp_id")
employee = Employee.objects.get(pk=emp_id)
payment_by_employee = employee.payment_created_by.all()
if start_date and end_date:
payment_by_employee = payment_by_employee.filter(
created_at__range=[start_date, end_date], mode='cash'
)
payment_by_employee.aggregate(Sum('amount'))
return payment_by_employee
If you want all the records related to specific employee within specific range in CustomerVisit table, you can make use of the related name that is provided to the field(foreign_key) pointing to an employee in customerVisit Table.
For example, if CustomerVisit model has "phelebotomist_id" foreign key that points to Employee Model, you can get all customerVisit records related to Employee Model by below queries
CustomerVisit(models.Model):
phelebotomist_id = models.ForeignKey(Employee, related_name="employee_customer_visit")
emp = Employee.objects.get(pk=<emp_id>)
customer_visits_related_to_emp = emp.employee_customer_visit.all()
You can filter out further depending on the date range and any other fields.

How can I fetch data by joining two tables in django?

Looking for help got stuck at a point, I am new to python and django. There ARE two payments corresponding to one order, one COLLECTION and multiple TRANSFER and i need the payment corresponding to an order whose direction is COLLECTION only NOT transfered yet so that i can initiate TRANSFER against that order
models.py
class Orders(models.Model):
id= models.AutoField(primary_key=True)
payment_gateway_code = models.CharField(max_length=20,choices=[('PAYTM','PAYTM')])
is_active = models.BooleanField(default=True)
class Payments(models.Model):
id = models.AutoField(primary_key=True)
orders = models.ForeignKey(Orders, on_delete=models.CASCADE)
direction = models.CharField(max_length=20,choices=[('COLLECTION','COLLECTION'),
('TRANSFER','TRANSFER')])
settlement_status = models.CharField(max_length=50,blank=True, null=True,choices=[('YES','YES'),
('NO','NO')])
is_active = models.BooleanField(default=True)
qualified_orders = Orders.objects.filter(payment_gateway_code='CASHFREE',
Exists(Payments.objects.filter(order=OuterRef('pk'), direction='COLLECTION',
settlement_status='YES')), ~Exists(Payments.objects.filter(order=OuterRef('pk'),
direction='TRANSFER')))
But above query is not working
What is OuterRef('pk')?
First, I'd suggest changing orders to order.
Then, the query you're trying to achieve will be something like this (Assuming order_id contains the ID of the order):
Paymen.objects.filter(order_id=order_id, direction="COLLECTION")
You can use views.py for that as follows
Models.py
class Orders(models.Model):
id= models.AutoField(primary_key=True)
payment_gateway_code = models.CharField(max_length=20,choices=[('PAYTM','PAYTM')])
is_active = models.BooleanField(default=True)
class Payments(models.Model):
id = models.AutoField(primary_key=True)
orders = models.ForeignKey(Orders, on_delete=models.CASCADE)
direction = models.CharField(max_length=20,related_name="direction",choices=[('COLLECTION','COLLECTION'),
('TRANSFER','TRANSFER')])
settlement_status = models.CharField(max_length=50,blank=True, null=True,choices=[('YES','YES'),
('NO','NO')])
is_active = models.BooleanField(default=True)
views.py
from App.models import orders, payments
#in case if you need objects of order this is for that
def orderfunc():
order = Orders.objects.all()
def paymentfunc():
payment = Payment.objects.all()
# from here you can check for what record you want using conditional operator
#if direction == COLLECTION:
#then do what you need

What is the "instance" being passed to the to_representation function of my ListSerializer?

The goal of this project is to create an API that refreshes hourly with the most up to date betting odds for a list of games that I'll be scraping hourly from the internet. The goal structure for the JSON returned will be each game as the parent object and the nested children will be the top 1 record for each of linesmakers being scraped by updated date. My understanding is that the best way to accomplish this is to modify the to_representation function within the ListSerializer to return the appropriate queryset.
Because I need the game_id of the parent element to grab the children of the appropriate game, I've attempted to pull the game_id out of the data that gets passed. The issue is that this line looks to be populated correctly when I see what it contains through an exception, but when I let the full code run, I get a list index is out of range exception.
For ex.
class OddsMakerListSerializer(serializers.ListSerializer):
def to_representation(self, data):
game = data.all()[0].game_id
#if I put this here it evaluates to 1 which should run the raw sql below correctly
raise Exception(game)
data = OddsMaker.objects.filter(odds_id__in = RawSQL(''' SELECT o.odds_id
FROM gamesbackend_oddsmaker o
INNER JOIN (
SELECT game_id
, oddsmaker
, max(updated_datetime) as last_updated
FROM gamesbackend_oddsmaker
WHERE game_id = %s
GROUP BY game_id
, oddsmaker
) l on o.game_id = l.game_id
and o.oddsmaker = l.oddsmaker
and o.updated_datetime = l.last_updated
''', [game]))
#if I put this here the data appears to be populated correctly and contain the right data
raise Exception(data)
data = [game for game in data]
return data
Now, if I remove these raise Exceptions, I get the list index is out of range. My initial thought was that there's something else that depends on "data" being returned as a list, so I created the list comprehension snippet, but that doesn't resolve the issue.
So, my question is 1) Is there an easier way to accomplish what I'm going for? I'm not using a postgres backend so distinct on isn't available to me. and 2) If not, its not clear to me what instance is that's being passed in or what is expected to be returned. I've consulted the documentation and it looks as though it expects a dictionary and that might be part of the issue, but again the error message references a list. https://www.django-rest-framework.org/api-guide/serializers/#overriding-serialization-and-deserialization-behavior
I appreciate any help in understanding what is going on here in advance.
Edit:
The rest of the serializers:
class OddsMakerSerializer(serializers.ModelSerializer):
class Meta:
list_serializer_class = OddsMakerListSerializer
model = OddsMaker
fields = ('odds_id','game_id','oddsmaker','home_ml',
'away_ml','home_spread','home_spread_odds',
'away_spread_odds','total','total_over_odds',
'total_under_odds','updated_datetime')
class GameSerializer(serializers.ModelSerializer):
oddsmaker_set = OddsMakerSerializer(many=True, read_only=True)
class Meta:
model = Game
fields = ('game_id','date','sport', 'home_team',
'away_team','home_score', 'away_score',
'home_win','away_win', 'game_completed',
'oddsmaker_set')
models.py:
class Game(models.Model):
game_id = models.AutoField(primary_key=True)
date = models.DateTimeField(null=True)
sport=models.CharField(max_length=256, null=True)
home_team = models.CharField(max_length=256, null=True)
away_team = models.CharField(max_length=256, null=True)
home_score = models.IntegerField(default=0, null=True)
away_score = models.IntegerField(default=0, null=True)
home_win = models.BooleanField(default=0, null=True)
away_win = models.BooleanField(default=0, null=True)
game_completed = models.BooleanField(default=0, null=True)
class OddsMaker(models.Model):
odds_id = models.AutoField(primary_key=True)
game = models.ForeignKey('Game', on_delete = models.CASCADE)
oddsmaker = models.CharField(max_length=256)
home_ml = models.IntegerField(default=999999)
away_ml = models.IntegerField(default=999999)
home_spread = models.FloatField(default=999)
home_spread_odds = models.IntegerField(default=9999)
away_spread_odds = models.IntegerField(default=9999)
total = models.FloatField(default=999)
total_over_odds = models.IntegerField(default=999)
total_under_odds = models.IntegerField(default=999)
updated_datetime = models.DateTimeField(auto_now=True)
views.py:
class GameView(viewsets.ModelViewSet):
queryset = Game.objects.all()
serializer_class = GameSerializer
Thanks
To answer the question in the title:
The instance being passed to the Serializer.to_representation() is the instance you pass when initializing the serializer
queryset = MyModel.objects.all()
Serializer(queryset, many=True)
instance = MyModel.objects.all().first()
Serializer(data)
Usually you don't have to inherit from ListSerializer per se. You can inherit from BaseSerializer and whenever you pass many=True during initialization, it will automatically 'becomeaListSerializer`. You can see this in action here
To answer your problem
from django.db.models import Max
class OddsMakerListSerializer(serializers.ListSerializer):
def to_representation(self, data): # data passed is a queryset of oddsmaker
# Do your filtering here
latest_date = data.aggregate(
latest_date=Max('updated_datetime')
).get('latest_date').date()
latest_records = data.filter(
updated_date_time__year=latest_date.year,
updated_date_time__month=latest_date.month,
updated_date_time__day=latest_date.day
)
return super().to_representation(latest_records)

Django dates getting sorted wrong DRF

I have a django models-
class CompanyForLineCharts(models.Model):
company = models.TextField(null=True)
class LineChartData(models.Model):
foundation = models.ForeignKey(CompanyForLineCharts, null=True)
date = models.DateField(auto_now_add=False)
price = models.FloatField(null=True)
And views for these models-
arr = []
for i in range(len(entereddate)):
date = entereddate[i]
if entereddate[i] in dates:
foundat = (dates.index(entereddate[i]))
allprices = Endday.objects.raw("SELECT id, eop FROM drf_endday where company=%s", [comp[i]])
allendofdayprices = ''
for a in allprices:
allendofdayprices=(a.eop)
tempprices = allendofdayprices.split(',')
stringprices = tempprices[foundat:]
finald = dates[foundat:]
finalp = []
for t in range(len(stringprices)):
finalp.append(float(re.sub(r'[^0-9.]', '', stringprices[t])))
company = CompanyForLineCharts.objects.get(company=comp[i])
for j in range(len(finalp)):
arr.append(
LineChartData(
foundation = company,
date = finald[j],
price = finalp[j]
)
)
LineChartData.objects.bulk_create(arr)
Where entereddate is a list of dates(date object) entered by the user, dates is a big list of dates(also date object, in chronological order) and tempprices is a list of prices that corresponds to the dates list.
I have a serializer setup for these-
class LineChartDataSerializer(serializers.ModelSerializer):
class Meta:
model = LineChartData
fields = ('date','price')
class CompanyForLineChartsSerializer(serializers.ModelSerializer):
data = LineChartDataSerializer(many=True, source='linechartdata_set')
class Meta:
model = CompanyForLineCharts
fields = ('company', 'data')
As you see LineChartData model is associated to CompanyForLineCharts model via foundation.
Now the problem that I'm facing is when drf serialises these fields, the order of dates go haywire.
So I tried these as well-
In views-
xy = zip(finald, finalp)
sort = sorted(xy)
finald = [x[0] for x in sort]
finalp = [x[1] for x in sort]
Well, that did not change any order in the serialised output.
So I tried ordering serializer-
order_by = (('date',))
ordering = ['-date']
And none of them worked. What to do now?
#edit I'm sorry, but it shouldn't change anything I just checked Documentation and default values of auto_now_add and auto_now are False.
DateField(auto_now_add=False) -> DateField(auto_now_add=False, auto_now=False) should solve your problem.
If auto_now is true then it set date everytime when .save() method is called. auto_now_add do the same when you call constructor.
auto_now is used when you want date of last modification, while auto_now_add when you need date of creation.
You're not in any of these causes so you needs to set boths argumments as False

map raw sql to django orm

Is there a way to simplify this working code?
This code gets for an object all the different vote types, there are like 20 possible, and counts each type.
I prefer not to write raw sql but use the orm. It is a little bit more tricky because I use generic foreign key in the model.
def get_object_votes(self, obj):
"""
Get a dictionary mapping vote to votecount
"""
ctype = ContentType.objects.get_for_model(obj)
cursor = connection.cursor()
cursor.execute("""
SELECT v.vote , COUNT(*)
FROM votes v
WHERE %d = v.object_id AND %d = v.content_type_id
GROUP BY 1
ORDER BY 1 """ % ( obj.id, ctype.id )
)
votes = {}
for row in cursor.fetchall():
votes[row[0]] = row[1]
return votes
The models im using
class Vote(models.Model):
user = models.ForeignKey(User)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
payload = generic.GenericForeignKey('content_type', 'object_id')
vote = models.IntegerField(choices = possible_votes.items() )
class Issue(models.Model):
title = models.CharField( blank=True, max_length=200)
The code Below did the trick for me!
def get_object_votes(self, obj, all=False):
"""
Get a dictionary mapping vote to votecount
"""
object_id = obj._get_pk_val()
ctype = ContentType.objects.get_for_model(obj)
queryset = self.filter(content_type=ctype, object_id=object_id)
if not all:
queryset = queryset.filter(is_archived=False) # only pick active votes
queryset = queryset.values('vote')
queryset = queryset.annotate(vcount=Count("vote")).order_by()
votes = {}
for count in queryset:
votes[count['vote']] = count['vcount']
return votes
Yes, definitely use the ORM. What you should really be doing is this in your model:
class Obj(models.Model):
#whatever the object has
class Vote(models.Model):
obj = models.ForeignKey(Obj) #this ties a vote to its object
Then to get all of the votes from an object, have these Django calls be in one of your view functions:
obj = Obj.objects.get(id=#the id)
votes = obj.vote_set.all()
From there it's fairly easy to see how to count them (get the length of the list called votes).
I recommend reading about many-to-one relationships from the documentation, it's quite handy.
http://www.djangoproject.com/documentation/models/many_to_one/

Categories