Django ORM Issue - python

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

Related

How to update a field of Django Model Object whenever that particular object is fetched as a part of QuerySet from Database

I have a field called pending_since for a Ticket model. This contains the the difference between the date when the ticket is created ( created_on field ) and the current date.
Now, when a single ticket is fetched, then I am able to update this field as below.
views.py
def pending_days_calculator(date1):
current_date = timezone.now()
diff = current_date - date1
diff_in_days = diff.total_seconds() / ( 60*60*24)
pending_days = round(diff_in_days,2)
return pending_days
#login_required(login_url=settings.CUSTOM_LOGIN_URL)
def ticket_detail(request, ticket_no):
ticket = Ticket.objects.get(ticket_no=ticket_no)
ticket.pending_since = pending_days_calculator(ticket.created_on)
ticket.save()
if request.method == 'POST':
.....other logic here.....
But, when a bunch of Ticket objects are fetched at a time as shown below, is there any way to update this field for each object, other than looping through the queryset.
#login_required(login_url=settings.CUSTOM_LOGIN_URL)
def common_pool(request):
tickets = request.user.ticket_set.exclude(ticket_status='closed').order_by('sla')
Ticket model has ForeignKey reference to user model GHDUser
models.py for reference
class Ticket(models.Model):
ticket_no = models.CharField(max_length=10, blank=True)
raised_by_user = models.ForeignKey(GHDUser, on_delete=models.CASCADE,related_name='raised_ticket', default=1)
created_on = models.DateTimeField(default=timezone.now)
pending_since = models.FloatField(default=0.0)
If you want to calculate pending_since for each object of Django Model, you can use a property method for it
#property
def pending_since(self):
return pending_days_calculator(self.created_on)
This would do the job. You can also move the logic in pending_days_calculator in side the property.

Update a queryset in django

I need to update the data on the database once I get all the values of that data with current DateTime..i.e
My Model:
class Load_Balancing(models.Model):
instance_name = models.CharField(max_length=100)
instance_visit = models.DateTimeField(null=True)
sequence = models.IntegerField()
I want to get the value with the last sequence number inserted in the database and update its time to the current time.
I tried:
instances = Load_Balancing.objects.all().order_by("-sequence")[:1]
a = Load_Balancing.objects.filter(sequence=instances.sequence).update(instance_visit= datetime.datetime.now())
But it's not working.
If you want to update the latest one, you can do that with:
from django.utils import timezone
instance = Load_Balancing.objects.all().latest('sequence')
instance.instance_visit = timezone.now()
instance.save()

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

django model: get primary key of the model just created

The Model is defined as below:
class UnitTab(models.Model):
unit_id = models.PositiveIntegerField(primary_key=True)
create_time = models.PositiveIntegerField()
update_time = models.PositiveIntegerField()
read_db_connection = 'game_center_admin_db'
write_db_connection = 'game_center_admin_db'
class Meta:
db_table = u'unit_tab'
def save(self, *args, **kwargs):
curr_time = int(time.time())
if not self.create_time:
self.create_time = curr_time
self.update_time = curr_time
super(UnitTab, self).save(*args, **kwargs)
def __unicode__(self):
return u'unit_tab_%s' % (self.unit_id)
And I am just saving the a UnitTab with UnitTab.objects.create() to create a new object. The unit_id has auto_increment, so I did not have to set it.
But if I use "u = UnitTab.objects.create()", the object "u" I get back is with unit_id as None — although the save is successful. So how can I can get the primary key(unit_id) of the UnitTab I just saved/created?
Edit: I am using Django 1.6.11 for my project
Edit: I logged those attributes and found that after u.save(), the unit_id is None. create_time is OK and the entity is saved successfully.
Edit: After changing from PositiveIntegerField to AutoField the unit_id field is auto assigned after save(). Just not sure why this is the case.
After you create your new object:
u = UnitTab.objects.create()
follow it up by refreshing its value from the db using the refresh_from_db() method.
u.refresh_from_db()
You can find this info here:
https://docs.djangoproject.com/en/1.9/ref/models/instances/#refreshing-objects-from-database
EDIT:
If you're on django 1.6, use the save() method and you should be able to access it like this:
>>> b2 = Blog(name='Cheddar Talk', tagline='Thoughts on cheese.')
>>> b2.id # Returns None, because b doesn't have an ID yet.
>>> b2.save()
>>> b2.id # Returns the ID of your new object.
https://docs.djangoproject.com/en/1.6/ref/models/instances/#auto-incrementing-primary-keys
Is there a particular reason you don't want to use models.AutoField instead?
unit_id = models.AutoField(primary_key=True)

Categories