Django dates getting sorted wrong DRF - python

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

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.

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)

how to apply a condition to a queryset in django

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()

Django ORM Issue

I am learning RestAPI and When I try to post data to update my database columns the modified_on column should automatically populated to current date and time but it is not updating.
I am currently using django cassandra engine ORM where there is no functionality like auto_add_now() or auto_now().
Can any one give a suggestion where am I going wrong?
Model Class:
class Mydb(DjangoCassandraModel):
id = columns.UUID(primary_key=True, default=uuid.uuid4())
user_name = columns.Text()
user_email = columns.Text(default=None)
user_password = columns.Text()
description = columns.Text()
creation_date = columns.DateTime(default=datetime.datetime.today(), static=True)
modified_on = columns.DateTime(default=datetime.datetime.today())
My Serialization class:
class TaskSerializer(serializers.Serializer):
# id = serializers.UUIDField(default=uuid.uuid4)
USER_ID = serializers.UUIDField(default= uuid.uuid4(),source='id')
# user_name = serializers.CharField(max_length=50)
USER_NAME_FIELD = serializers.CharField(max_length=50, source='user_name')
USER_EMAIL = serializers.CharField(source='user_email')
USER_PASSWORD = serializers.CharField(max_length=20, source='user_password')
EXPLANATION = serializers.CharField(max_length=100, source='description')
MODIFIED_AT = serializers.DateTimeField(default=datetime.datetime.today(), source='modified_on')
CREATED_ON = serializers.DateTimeField(default=datetime.datetime.today(), source='creation_date')
def create(self, validated_data):
return Mydb.objects.create(**validated_data)
def update(self, instance, validated_data):
# instance.id = validated_data.get('id', instance.id)
instance.user_name = validated_data.get('user_name', instance.user_name)
instance.user_email = validated_data.get('user_email', instance.user_email)
instance.user_password = validated_data.get('user_password', instance.user_password)
instance.description = validated_data.get('description',instance.description)
instance.modified_on = validated_data.get('modified_on', instance.modified_on)
instance.save()
# instance.creation_date = validated_data.get('creation_date', instance.creation_date)
You should rather use utils now for timezone aware times
from django.utils.timezone import now
also in model you should set function not evaluated value ( no parenthesis after now )
MODIFIED_AT = serializers.DateTimeField(default=now, source='modified_on')
MODIFIED_AT = serializers.DateTimeField(default=datetime.datetime.today(), source='modified_on')
to
MODIFIED_ON = serializers.DateField(default=datetime.datetime.today(), source='modified_on')
change MODIFIED_AT to MODIFIED_ON
You can try:
create_date = models.DateField(auto_now_add=True,
verbose_name=u'Create date')
update_date = models.DateTime(auto_now=True,
verbose_name=u'Update date')
auto_now_add automatically set the field to now when the object is first created.
auto_now=True automatically set the field to now every time the object is saved.
Doc is here.
Please make sure to add the auto_now=True for your modified_at filed, in your model.
It automatically sets the field to now every time the object is saved. Useful for “last-modified” timestamps. Note that the current date is always used; it’s not just a default value that you can override.
Example:
class Mydb(DjangoCassandraModel):
creation_date = columns.DateTime(auto_now_add=True)
modified_on = columns.DateTime(auto_now=True)
Docs Here:
https://docs.djangoproject.com/en/1.11/ref/models/fields/#django.db.models.DateField.auto_now
You use default=datetime.datetime.today() as your default value for the fields. Since you call the function immediately (by adding ()), the function is called exactly once on the first load of the code and the datetime at that moment is put into the default value and not updated until you reload the code (a.k.a. restart the server).
If you want to always use the then current time, leave away the () to cause Django to call the function each time. default=datetime.datetime.today
It's preferable for you to use now though, like iklinac did in his answer, as that also respects your timezone settings. His anwer also leaves out the parenteses, yielding the correct result.
from django.utils.timezone import now
...
MODIFIED_AT = serializers.DateTimeField(default=now, source='modified_on')

Query for items using filter for most recent entry in a related table

Hello I seem be having a problem with querying. I have a list of items. Any Item can have a status set to it (In, out, Collected, Destroyed, etc.). Here is my views.
def client_summary(request, client_id):
client = None
items = None
try:
client = models.Client.objects.get(pk = client_id)
items = client.storageitem_set.all()
total_items = items.count()
except:
return HttpResponse(reverse(return_clients))
return render_to_response('client_summary.html', {'items':items, 'total_items':total_items, 'client':client}, context_instance = RequestContext(request))
If I have in my template
{%for item in items%}
{{item.itemstatushistory_set.latest}}
{%endfor%}
This will display the all the latest status. Now I want to only to print out all items that their status is Destroyed only. For some reason I can't seem to do this.
Here is some more information from my models as well.
class StorageItem(models.Model):
type = models.ForeignKey(StorageObject)
client = models.ForeignKey(Client)
company_id = models.PositiveIntegerField(unique = True, blank = True, null = True)
content = models.TextField(blank = True)
alternative_id = models.CharField(verbose_name = 'Client no.', max_length = 60, blank = True)
title = models.CharField(max_length = 100)
format = models.ForeignKey(Format, blank = True, null = True)
location = models.CharField(max_length = 20, blank = True)
item_class = models.TextField(blank = True)
def __unicode__(self):
return self.title
class Status(models.Model):
description = models.CharField(max_length = 60)
notes = models.TextField(blank = True)
def __unicode__(self):
return self.description
class Meta:
verbose_name_plural = 'Status'
get_latest_by = 'date'
ordering = ['date']
class ItemStatusHistory(models.Model):
date = models.DateTimeField(auto_now = True)
contact = models.ForeignKey(Contact)
item = models.ForeignKey(StorageItem)
status = models.ForeignKey(Status)
user = models.ForeignKey(User)
def __unicode__(self):
return str(self.status
EDIT: There are still some problems because the relation between an item could have many statuses. But I want to only list the most recent status only for destroyed items.
Example: Supposing there are 3 items and they have sets item1 = [in, out, destroyed], item2 = [destroyed, in], item3 = [destroyed, collected, destroyed], item4 = [in] where [1st status, 2nd status, 3rd status, etc]. I only want to display the latest status for that item.
Both Mike and kriegar will get a result like [item1, item2, item3, item3].
Because Yuji used the distinct function, he will get [item1, item2, item3].
The answer I need to get at the end should be [item1, item3].
kriegar's solution will work. There's also this one, which searches by Status id instead of text matching on description:
destroyedStatus = Status.objects.get(description="destroyed")
clients_destroyed_items = StorageItem.objects.filter(client=client,
itemstatushistory__status=destroyedStatus)
This assumes descriptions are unique, but you have no such constraint in your model. I have no idea which implementation is faster.
EDIT: By the way, if you've got some crazy system where you have more than one Status with a description of "destroyed", and you wanted to query by Status ids instead of description, you would just do:
destroyedStatusIDs = Status.objects.filter(description="destroyed").values_list("id", flat=True)
clients_destroyed_items = StorageItem.objects.filter(client=client,
itemstatushistory__status__in=destroyedStatusIDs)
BTW, it's considered good practice to set related_name on your ForeignKey, OneToOneField, and ManyToManyField relationships, usually to plurals. So your history class becomes:
class ItemStatusHistory(models.Model):
date = models.DateTimeField(auto_now=True)
contact = models.ForeignKey(Contact, related_name="history")
item = models.ForeignKey(StorageItem, related_name="history")
status = models.ForeignKey(Status, related_name="history")
user = models.ForeignKey(User, related_name="history")
which would change my first example to:
destroyedStatus = Status.objects.get(description="destroyed")
clients_destroyed_items = StorageItem.objects.filter(client=client,
history__status=destroyedStatus)
EDIT 2: Ah, so you only want to consider the current (i.e. latest) Status. This is where aggregation and F objects come in. Basically, the idea is to have the database create a "fake column" in the table which has the date of the latest (i.e. maximum date) Status, then require the date to match as well as the status:
from django.db.models import F, Max
destroyedStatus = Status.objects.get(description="destroyed")
clients_destroyed_items = StorageItem.objects.annotate(
last_change_date=Max("itemstatushistory__date")).filter(client=client,
itemstatushistory__status=destroyedStatus,
itemstatushistory__date=F("last_change_date"))
I haven't tested this, this is the first time I've tried this, and there may be a better way, so comments are welcome.
If you want a queryset of the items that belong to a client and are destroyed:
clients_destroyed_items = StorageItem.objects.filter(client=client,
itemstatushistory__status__description='destroyed')
Lookups that span relationships¶
Django offers a powerful and intuitive
way to "follow" relationships in
lookups, taking care of the SQL JOINs
for you automatically, behind the
scenes. To span a relationship, just
use the field name of related fields
across models, separated by double
underscores, until you get to the
field you want.
This example retrieves all Entry
objects with a Blog whose name is
'Beatles Blog':
Entry.objects.filter(blog_name_exact='Beatles
Blog')
This spanning can be as deep as you'd
like.
It works backwards, too. To refer to a
"reverse" relationship, just use the
lowercase name of the model.

Categories