Filtering two models - python

I have a problem with following thing: using models described below, I need to search for a car, that has more than x km of mileage and latest visit has date of more than year ago. Of course one car can have more than one visit.
class Car(models.Model):
...
id = models.CharField(max_length=10, primary_key=True, db_index=True)
mileage = models.PositiveIntegerField(db_index=True)
class Visit(models.Model):
...
id = models.ForeignKey(Car, db_column='id', db_index=False)
date = models.DateField(db_index=True)
In views.py I have code like this
def search_car(request):
time_threshold = datetime.now() - timedelta(days=365)
cars = Car.objects.filter(mileage__gte=500000,
id=Visit.objects.filter(data__lt=time_threshold.date()))
return render(request, 'myapp/search_car.html', {'cars': cars})
Unfortunately, it doesn't work. Any ideas?
EDIT Exact code:
models.py
class Samochod(models.Model):
marka = models.CharField(max_length=30)
model = models.CharField(max_length=30)
nr_rejestracyjny = models.CharField(max_length=10, primary_key=True, db_index=True)
nr_VIN = models.CharField(max_length=17, unique=True, validators=[validators.MinLengthValidator(17)])
przebieg = models.PositiveIntegerField(db_index=True)
id_uzytkownika = models.ForeignKey(User, db_column='id_uzytkownika', db_index=True)
class Wizyta(models.Model):
id_wizyty = models.IntegerField(primary_key=True, db_index=True)
data = models.DateField(db_index=True)
status = models.CharField(max_length=6, choices=STAN_CHOICE, db_index=True)
id_uzytkownika = models.ForeignKey(User, db_column='id_uzytkownika', db_index=True)
nr_rejestracyjny = models.ForeignKey(Samochod, db_column='nr_rejestracyjny', db_index=False)
przebieg_w_momencie_wizyty = models.PositiveIntegerField()
opis = models.CharField(max_length=200)
id_czesci = models.ForeignKey(Czesci, db_column='id_czesci')
cena = models.PositiveIntegerField()
czas_pracownikow = models.PositiveIntegerField(validators=[validators.MaxValueValidator(1000)])
id_sprzetu = models.ForeignKey(Sprzet, db_column='id_sprzetu', db_index=True)
views.py
def search_car(request):
time_threshold = datetime.now() - timedelta(days=365)
samochody = Samochod.objects.distinct().filter(przebieg__gte=500000).exclude(wizyta__date__gte=time_threshold)
return render(request, 'warsztat_app/search_car.html', {'samochody': samochody})

cars = Car.objects.distinct().filter(mileage__gte=500000) \
.exclude(visit__date__gte=time_threshold)
For your real models code should look like this:
samochody = Samochod.objects.distinct().filter(przebieg__gte=500000) \
.exclude(wizyta__data__gte=time_threshold)

Related

Optimizing serialization in Django

I've got the following models:
class Match(models.Model):
objects = BulkUpdateOrCreateQuerySet.as_manager()
id = models.AutoField(primary_key=True)
betsapi_id = models.IntegerField(unique=True, null=False)
competition:Competition = models.ForeignKey(Competition, on_delete=models.CASCADE, related_name='matches')
season:Season = models.ForeignKey(Season, on_delete=models.CASCADE, related_name='season_matches', null=True, default=None)
home:Team = models.ForeignKey(Team, on_delete=models.CASCADE, related_name='home_matches')
away:Team = models.ForeignKey(Team, on_delete=models.CASCADE, related_name='away_matches')
minute = models.IntegerField(default=None, null=True)
period = models.CharField(max_length=25, default=None, null=True)
datetime = models.DateTimeField()
status = models.IntegerField()
opta_match = models.OneToOneField(OptaMatch, on_delete=models.CASCADE, related_name='match', default=None, null=True)
updated_at = models.DateTimeField(auto_now=True)
created_at = models.DateTimeField(auto_now_add=True)
class Event(models.Model):
objects = BulkUpdateOrCreateQuerySet.as_manager()
id = models.AutoField(primary_key=True)
betsapi_id = models.IntegerField(unique=True)
name = models.CharField(max_length=255)
minute = models.IntegerField()
player_name = models.CharField(max_length=255, null=True, default=None)
extra_player_name = models.CharField(max_length=255, null=True, default=None)
period = models.CharField(max_length=255)
team:Team = models.ForeignKey(Team, on_delete=models.CASCADE, related_name='events')
match:Match = models.ForeignKey(Match, on_delete=models.CASCADE, related_name='events')
updated_at = models.DateTimeField(auto_now=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self) -> str:
return f"{self.betsapi_id} | {self.name} | {self.minute}"
And the following snippet of my serializer:
class TestMatchSerializer(serializers.Serializer):
home = TeamSerializer(many=False, read_only=True)
away = TeamSerializer(many=False, read_only=True)
competition = CompetitionSerializer(many=False, read_only=True)
events = serializers.SerializerMethodField()
class Meta:
model = Match
fields = ['id', 'home', 'away', 'competition', 'status']
def get_events(self, instance : Match):
events = instance.events.filter(name__in=["Corner", "Goal", "Substitution", "Yellow Card", "Red Card"]).order_by('-id')
return EventSerializer(events, many=True).data
When I serialize 25 objects using the following code including the events it takes about 0.72s.
all_matches_qs = Match.objects.all().prefetch_related('statistics').select_related('home', 'away', 'competition', 'competition__country')
TestMatchSerializer(all_matches_qs[:25], many=True, read_only=False).data
However when I change prefetch the events and the nested relationship events__team the serialization speed remains the same (0.72s). I used the following code to do so:
all_matches_qs = Match.objects.all().prefetch_related('events', 'events__team').select_related('home', 'away', 'competition', 'competition__country')
Now when I change the events variable in the serializer to events = EventSerializer(many=True, read_only=True). The time to serialize is reduced.
However I would like to filter the events before serializing it, how can I reliaze that?

Multiple For Loops Django

I have the following two models ASPBoookings and Athlete. The Athlete model is linked to the ASPBookings model by the foreign key named athlete.
I am trying to create a loop that will cycle through all of the bookings in the ASPBooking table and find out which is the most recent booking by each athlete (the table can contain multiple bookings each to the same or different athletes (athlete_id).
Once I have this information (booking_date and athlete_id), I then want to be able to automatically update the "Lastest ASP Session Field" in the Athlete Model.
This is what I have tried so far. I can cycle through the bookings in the ASPBookings table and retrieve and update the "Latest ASP Session Field" using the booking_date and athlete_id, but I cannot do this for multiple different athletes that are within the table. Currently the view just identifies the latest booking and the assigned athlete_id and then updates the field.
Thanks in advance for any help.
Below is the code:
ASPBookings Model
class ASPBookings(models.Model):
asp_booking_ref = models.CharField(max_length=10, default=1)
program_type = models.CharField(max_length=120, default='asp')
booking_date = models.DateField()
booking_time = models.CharField(max_length=10, choices=booking_times)
duration = models.CharField(max_length=10, choices=durations, default='0.5')
street = models.CharField(max_length=120)
suburb = models.CharField(max_length=120)
region = models.CharField(max_length=120, choices=regions, default='Metro')
post_code = models.CharField(max_length=40)
organisation_type = models.CharField(max_length=120,choices=organisation_types, default='Government School')
audience_number = models.CharField(max_length=10)
presentation_form = models.CharField(max_length=120, choices=presentation_form_options, default='Face to Face')
contact_name = models.CharField(max_length=80)
email = models.EmailField()
phone_number = models.CharField(max_length=120)
comments = models.TextField()
status = models.CharField(max_length=80, choices=statuses, default='TBC')
email_sent = models.BooleanField(default=False)
athlete = models.ForeignKey(Athlete, default= '1', on_delete=models.CASCADE)
def __str__(self):
return self.contact_name
# return URL after the POST has been submitted.
def get_absolute_url(self):
return reverse('vistours:success')
Athlete Model
class Athlete(models.Model):
athlete_ref = models.CharField(max_length=10, default=1)
athlete_name = models.CharField(max_length=80)
email = models.EmailField()
phone_number = models.CharField(max_length=120)
home = models.CharField(max_length=120)
education = models.CharField(max_length=120)
sport = models.CharField(max_length=120, choices=sports, default='1500m Runner')
notes = models.TextField(default='None')
gender = models.CharField(max_length=120, choices=genders, default='Not Specified')
para_athlete = models.BooleanField(blank=True)
working_with_children = models.BooleanField(blank=True)
expiry_date = models.DateField(blank=True, null=True)
available = models.BooleanField(blank=True)
available_from = models.DateField(blank=True, null=True)
bfbw = models.BooleanField(blank=True)
latest_bfbw_session = models.DateField(blank=True, null=True)
number_bfbw_sessions = models.CharField(blank=True, null=True, max_length=10)
asp = models.BooleanField(blank=True)
latest_asp_session = models.DateField(blank=True, null=True)
number_asp_sessions = models.CharField(blank=True, null=True, max_length=10)
tours = models.BooleanField(blank=True)
latest_tours_session = models.DateField(blank=True, null=True)
number_tours_sessions = models.CharField(blank=True, null=True, max_length=10)
def __str__(self):
return self.athlete_name
# return URL after the POST has been submitted.
def get_absolute_url(self):
return reverse('home')
View
# Complete first loop for inital values.
for date in asp_data:
if date.booking_date != None:
first_loop = date.booking_date
athl_id = date.athlete_id
break
# If next value is greater than inital value, replace current values.
for date in asp_data:
if date.booking_date != None:
if date.booking_date > first_loop:
first_loop = date.booking_date
athl_id = date.athlete_id
print(first_loop)
print(athl_id)
update_date = Athlete.objects.get(id=athl_id)
update_date.latest_asp_session = first_loop
update_date.save()
No need for loops. You can do this for all athletes in just one go using subqueries to leave all the heavy-lifting to your database:
from django.db.models import F, OuterRef, Subquery
bookings = ASPBookings.objects.filter(
athlete=OuterRef('pk')
).order_by('-booking_date')
Athlete.objects.annotate(
latest_asp_booking_date=Subquery(
bookings.values('booking_date')[:1]
)
).update(
latest_asp_session=F('latest_asp_booking_date')
)

Query using Joins in Django

class Students(models.Model):
id = models.BigAutoField(primary_key=True)
admission_no = models.CharField(max_length=255)
roll_no = models.CharField(unique=True, max_length=50, blank=True, null=True)
academic_id = models.BigIntegerField()
course_parent_id = models.BigIntegerField()
course_id = models.BigIntegerField()
first_name = models.CharField(max_length=20)
middle_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
user_id = models.BigIntegerField()
date_of_birth = models.DateField(blank=True, null=True)
date_of_join = models.DateField(blank=True, null=True)
class Courses(models.Model):
id = models.BigAutoField(primary_key=True)
parent_id = models.IntegerField()
course_title = models.CharField(max_length=50)
slug = models.CharField(unique=True, max_length=50)
tenant_user = models.ForeignKey('Users', models.DO_NOTHING, default='')
course_code = models.CharField(max_length=20)
course_dueration = models.IntegerField()
grade_system = models.CharField(max_length=10)
is_having_semister = models.IntegerField()
is_having_elective_subjects = models.IntegerField()
description = models.TextField()
status = models.CharField(max_length=8)
created_at = models.DateTimeField(blank=True, null=True)
updated_at = models.DateTimeField(blank=True, null=True)
class Meta:
managed = True
db_table = 'courses'
def __unicode__(self):
return self.course_title
class StudentProfileSerializer(ModelSerializer):
class Meta:
model = Students
depth = 0
fields = '__all__'
The first two tables/class contains the course and student table and the third contains the serializer. Can anyone please help how to query using the joins in django. I need to fetch the course_title from Courses table and first_name from Students table.
IMHO, you should review your models; course_id in Students should be a course=models.ForeignKey('Courses', ...); this way you can refer to the course title using dot notation;
student=Student.objects.filter(pk=...)
to refer to your required fields:
student.last_name, student.course.course_title
Besides, if I understood your models, you could get some incongruence... what if the value stored in course_parent_id in Students model is different from the value stored in parent_id in Courses model? maybe the first one is redundant.
To query a field from a related object use a double underscore. So you could do
Student.objects.filter(**kwargs).values('first_name', 'last_name', 'course__course_name')

How to annotate field by filer from manytomanyfield

my models
class Project(models.Model):
name = models.CharField(max_length=255, unique=True)
info = models.CharField(max_length=255, unique=True)
m2mStatus = models.ManyToManyField("ProjectStatus")
class ProjectStatus(models.Model):
status = models.BooleanField(default=False)
startTime = models.DateTimeField(auto_now=True)
description = models.CharField(max_length=255)
I want to annotate like this:
pj = Project.objects.filter(name="abc")
ps = pj.m2mStatus.last()
Project.objects.filter(name="abc").annotate(status=ps.status)
any help ?

How to optimize Django SQL SELECT Query on views.py?

These are the models involved in the view :
class Movie(models.Model):
title_original = models.CharField(max_length=300,
db_column='titulooriginal')
title_translated = models.CharField(max_length=300, blank=True,
db_column='titulotraducido')
thumbnail = models.CharField(max_length=300, blank=True,
db_column='imagen')
length = models.CharField(max_length=75, db_column='duracion')
rating = models.CharField(max_length=75, db_column='censura')
genre = models.CharField(max_length=75, db_column='genero')
country_of_origin = models.CharField(max_length=150, db_column='pais')
trailer = models.CharField(max_length=300, blank=True, db_column='trailer')
synopsis = models.CharField(max_length=3600, blank=True,
db_column='sinopsis')
cast = models.CharField(max_length=300, blank=True, db_column='elenco')
director = models.CharField(max_length=150, db_column='director')
slug = models.SlugField(unique=True, blank=True)
tsc = models.DateTimeField(auto_now=False, auto_now_add=True, db_column='tsc', null=True)
tsm = models.DateTimeField(auto_now=True, auto_now_add=True, db_column='tsm', null=True)
class Meta:
db_table = u'peliculas'
def __unicode__(self):
return self.title_original
class ShowTime(models.Model):
LANGUAGE_ESPANOL = 'Espanol'
LANGUAGE_SUBTITLED = 'Subtitulada'
LANGUAGE_CHOICES = (
(LANGUAGE_ESPANOL, LANGUAGE_ESPANOL),
(LANGUAGE_SUBTITLED, LANGUAGE_SUBTITLED))
movie = models.ForeignKey(Movie, db_column='idpelicula')
theater = models.ForeignKey(Theater, db_column='idcine',
null=True)
time = models.TimeField(null=True, db_column='hora')
type_3d = models.NullBooleanField(db_column=u'3d')
type_xd = models.NullBooleanField(null=True, db_column='xd')
type_gtmax = models.NullBooleanField(null=True, db_column='gtmax')
type_vip = models.NullBooleanField(null=True, db_column='vip')
type_imax = models.NullBooleanField(null=True, db_column='imax')
language = models.CharField(max_length=33, blank=True, db_column='idioma',
choices=LANGUAGE_CHOICES,
default=LANGUAGE_ESPANOL)
city = models.ForeignKey(City, db_column='idciudad')
start_date = models.DateField(blank=True, db_column='fecha_inicio')
end_date = models.DateField(blank=True, db_column='fecha_fin')
visible = models.NullBooleanField(null=True, db_column='visible')
tsc = models.DateTimeField(auto_now=False, auto_now_add=True, db_column='tsc', null=True)
tsm = models.DateTimeField(auto_now=True, auto_now_add=True, db_column='tsm', null=True)
class Meta:
db_table = u'funciones'
def __unicode__(self):
return (unicode(self.theater) + " " + unicode(self.movie.title_original) + " " + unicode(self.time))
Additionally this is the view that queries the models:
def list_movies(request, time_period):
city = utils.get_city_from_request(request)
if time_period == 'proximas-dos-horas':
(start_date,
end_date,
hours_start,
hours_end) = utils.get_datetime_filters_from_time_period(time_period)
else:
(start_date,
end_date) = utils.get_datetime_filters_from_time_period(time_period)
if not start_date: # 404 for invalid time periods
raise Http404
movies = Movie.objects.filter(
showtime__city=city.code,
showtime__visible=1,
).order_by('-tsm').distinct()
if time_period == 'proximas-dos-horas':
movies = movies.filter(
showtime__start_date__lte=start_date,
showtime__end_date__gte=end_date,
showtime__time__range=(hours_start, hours_end))
elif time_period == 'proximos-estrenos':
movies = movies.filter(
showtime__start_date=None,
showtime__end_date=None,
)
else:
movies = movies.filter(
showtime__start_date__lte=start_date,
showtime__end_date__gte=end_date)
context = {'movies': movies, 'city': city, 'time_period': time_period}
return render_to_response('list_movies.html', context,
context_instance=RequestContext(request))
Currently this view is consuming a lot of resources in the database and this results in low response time of the web transaction on the browser. I connected the app with New Relic monitoring software to analyze the transactions on app and DB level. This is the trace detail that i got:
I would like to get somo advice on optimizing this view so that the consumption of DB resources drops to the minimum
Thanks a lot!
I don't know the context of your problem, but my 2 advises are:
First, consider some changes in your data model. The ShowTime class have a foreign key to City and a foreign key to Theater and it seems a bit redundant. Personally, I prefer de-normalize addresses, for example:
class Theater(models.Model):
name = models.CharField(max_length=48)
# Location fields.
geo_country = models.CharField(max_length=48)
geo_country_code = models.CharField(max_length=2)
geo_locality = models.CharField(max_length=48)
geo_street = models.CharField(max_length=48, blank=True, default="")
geo_address = models.CharField(max_length=120, blank=True, default="")
class ShowTime(models.Model):
theater = models.ForeignKey(Theater)
This way, you can save a JOIN to the City table and it can be erased from your data model.
Second, read the select_related feature of the Django ORM.
Wish you fun.

Categories