Additional computed fields in Model - python

I have two simple models in my Django app. Here's what they look like:
class Host(models.Model):
url = models.URLField(max_length= 200)
ssl = models.BooleanField(default = False)
class Query(models.Model):
host = models.ForeignKey(Host)
date = models.DateTimeField(auto_now_add = True)
latency = models.FloatField(null = True)
success = models.BooleanField(default = False)
error = models.CharField(max_length= 2000, null = True)
When i access the Host model, I only have access to the two fields url and ssl. When querying the Host model, I would like three extra fields to computed and returned dyanmicaly. These are the average_latency which would be the average of the not-null latency field of all the child Query records so i can access it something like this:
t = Tracker.objects.get(id = 1)
t.url
t.average_latency
Could someone please explain how I can do this or point me to some examples/documentation?
Thank you.

You can just use class properties:
class Host(models.Model):
.
.
.
#property
def average_latency(self):
# calculate latency from Query model ...
return latency
Bear in mind that this is a read-only property.

You can check django-denorm, it's pretty much about what you're trying to achievie. I also have some flashbacks that there are other similar django apps.

Related

Update model field after some period in Django

I want automatically update field status in my model after 14 days.
Here is my model. I want to change status_of_renting to 0 after 15 days from date_of_rental (if date.today() if greater than date_of_return)
class RentCar(models.Model):
NORMAL = 1
PENALTY = 0
STATUS = (
(NORMAL, 'All is fine'),
(PENALTY, 'Penalty for using car')
)
car = models.ForeignKey('Car', on_delete = models.CASCADE, related_name = 'car')
person = models.ForeignKey('Person', on_delete = models.CASCADE, related_name = 'client')
date_of_rental = models.DateField(blank= True, default=timezone.now)
date_of_return = models.DateField(blank= True, default=date.today() + timedelta(days=14))
status_of_renting = models.IntegerField(choices = STATUS, default = 1)
def __str__(self):
return f'{self.rental} - {self.car} / {self.client.fullname}'
I can override def get_queryset() or dispatch in my generics.ListView, but I*m sure it's terrible decision. Is there some better solution to change the status in field status_of_renting.
views.py
class RentCatView(ListView):
model = RentCar
def get_queryset(self):
self.model.objects.filter(Q(status_of_renting = 1)&Q(date_of_return__lte = date.today())).update(status_of_renting=0)
return self.model.objects.all()
Trying to update database in queryset is indeed bad idea - it will execute every time someone try to fetch list of RentCar which will pollute your database with requests.
You need to setup cron job to run your query to update RentCar. Good thing is that you can run it only once a day, since it is only time that status_of_renting should be changed.
You can use one of django app, such as django-cron or django-background-tasks.
For example, this is what you need to do with django-background-tasks:
from background_task import background
from .models import RentCar
#background(schedule=24*60*60)
def update_status_of_renting(user_id):
RentCar.objects.filter(Q(status_of_renting = 1)&Q(date_of_return__lte = date.today())).update(status_of_renting=0)

Reverse foreignkey query with peewee

I'm using the peewee orm and I would like to know how to do a reverse foreignkey query.
These are my models:
class Device(BaseModel):
mac = CharField()
ip = CharField()
class Metrics(BaseModel):
device = ForeignKeyField(Device, related_name="metrics")
sensor = CharField()
analog = FloatField(null = True)
timestamp = DateTimeField()
I would like to know the simplest way to get all the Devices that have a Metric with a field sensor="temperature".
I can solve it with various querys and some iteration, but I wonder if there is a more direct way to do it.
Thanks
One way:
Device.select().join(Metric).where(Metric.sensor == 'temperature')
Another way:
Device.select().where(fn.EXISTS(
Metric.select().where((Metric.sensor == 'temperature') & (Metric.device == Device.id))
))

How to use Django join

Hi I am making a backend server in Django for storing user data from an app.
Below are my models.
class Subscriber(models.Model):
subId = models.IntegerField(max_length=20,unique=True,blank=False)
Name = models.CharField(max_length=25,blank=True)
class SMS(models.Model):
subscriberId = models.ForeignKey(Subscriber, null=False)
epochTime = models.IntegerField(null = False)
time = models.CharField(max_length= 250 ,blank = False)
class Call(models.Model):
subscriberId = models.ForeignKey(Subscriber, null=True)
epochTime = models.IntegerField(null = False)
time = models.CharField(max_length= 50 ,blank = False)
Date = models.CharField(max_length= 50 ,blank = False)
I need to write a Django query which I will give subscriberId and Django will return me to use the data for that user from Call and SMS (basically wants to use Join ).
earlier I have applied this in mysql.
select * from Server_Text JOIN (Server_Call) ON (Server_SMS.subscriberId_id = 11 and Server_Call.subscriberId_id = 11) ;
where Server is my mysql Database.
You shouldn't think in terms of joins and sql queries when you're using Django; the point is that the model layer abstracts these away. You just want to get the Subscriber, then follow the relationships to get the SMS and Call info:
subscriber = Subscriber.objects.get(subId=my_subscriber_id)
print subscriber.sms_set.all() # all SMSs for that subscriber
print subscriber.call_set.all() # all Calls for that subscriber
If you're doing this a lot, you can make it a bit more efficient by using prefetch_related('sms', 'call') in the initial query.

Django - How to link tables

Hello to the stackoverflow team,
I have the following two django tables:
class StraightredFixture(models.Model):
fixtureid = models.IntegerField(primary_key=True)
soccerseason = models.IntegerField(db_column='soccerSeason') # Field name made lowercase.
hometeamid = models.IntegerField()
awayteamid = models.IntegerField()
fixturedate = models.DateTimeField()
fixturestatus = models.CharField(max_length=24)
fixturematchday = models.IntegerField()
hometeamscore = models.IntegerField()
awayteamscore = models.IntegerField()
class Meta:
managed = False
db_table = 'straightred_fixture'
class StraightredTeam(models.Model):
teamid = models.IntegerField(primary_key=True)
teamname = models.CharField(max_length=36)
teamcode = models.CharField(max_length=5)
teamshortname = models.CharField(max_length=24)
class Meta:
managed = False
db_table = 'straightred_team'
In the views.py I know I can put the following and it works perfectly:
def test(request):
fixture = StraightredFixture.objects.get(fixtureid=136697)
return render(request,'straightred/test.html',{'name':fixture.hometeamid})
As I mentioned above, this all works well but I am looking to return the teamname of the hometeamid which can be found in the StraightredTeam model.
After some looking around I have been nudged in the direction of "select_related" but I am unclear on how to implement it in my existing tables and also if it is the most efficient way for this type of query. It feels right.
Please note this code was created using "python manage.py inspectdb".
Any advice at this stage would be greatly appreciated. Many thanks, Alan.
See model relationships.
Django provides special model fields to manage table relationships.
The one suiting your needs is ForeignKey.
Instead of declaring:
hometeamid = models.IntegerField()
awayteamid = models.IntegerField()
which I guess is the result of python manage.py inspectdb, you would declare:
home_team = models.ForeignKey('<app_name>. StraightredTeam', db_column='hometeamid', related_name='home_fixtures')
away_team = models.ForeignKey('<app_name>. StraightredTeam', db_column='awayteamid', related_name='away_fixtures')
By doing this will, you tell the Django ORM to handle the relationship under the hood, which will allow you to do such things as:
fixture = StraightredFixture.objects.get(fixtureid=some_fixture_id)
fixture.home_team # Returns the associated StraightredTeam instance.
team = StraightredTeam.objects.get(team_id=some_team_id)
team.home_fixtures.all() # Return all at home fixtures for that team.
I am not sure if this makes sense for Managed=False, but I suppose the sane way of doing it in Django would be with
home_team = models.ForeignKey('StraightRedFixture', db_column='fixtureid'))
And then just using fixture.home_team instead of doing queries by hand.

Django mysql table name did not validate

I added classes to Django app model to create mysql tables. I have 'downloads' table, and 'downloads' column in 'songs' table.
When i want to sync db, Django returns me error:
CommandError: One or more models did not validate:
mp3mid.downloads: Reverse query name for field 'song' clashes with field 'songs.downloads'. Add a related_name argument to the definition for 'song'.
Why it's impossible to give same name to table and column?
this is my models.py:
from django_evolution.mutations import *
from django.db import models
class singers(models.Model):
name = models.CharField(max_length = 255)
category = models.ForeignKey(categories)
class songs(models.Model):
name = models.CharField(max_length = 255)
singer = models.ForeignKey(singers)
downloads = models.IntegerField(max_length = 11)
exclusive = models.BooleanField(default = 0)
hit = models.BooleanField(default = 0)
date = models.DateTimeField(auto_now_add = True)
link = models.CharField(max_length = 255)
class downloads(models.Model):
song = models.ForeignKey(songs)
date = models.DateTimeField(auto_now_add = True)
Django allows you to make queries that span relationships.
In your case, the foreign key from downloads to songs means you could usually make queries that follow the relationship backwards from song to downloads:
from datetime import datetime
# fetch all songs with a download with a date on or after 2013-05-01.
songs = song.objects.filter(downloads__date__gte=datetime(2013,5,1))
However, you can't do that in this case, because downloads clashes with your songs.downloads field.
You have a couple of options. First, you can set related_name for your foreign key, as suggested by your error message.
class downloads(models.Model):
song = models.ForeignKey(songs, related_name="related_downloads")
Or, you can rename your song.downloads field.
class songs(models.Model):
...
num_downloads = models.IntegerField(max_length = 11)
As an aside, I recommend you rename your models to Singer, Song and Download (capitalized, singular instead of plural), to follow the Django convention.

Categories