I have these three models (I've summarize them):
class Tourist(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
class Etablissement(models.Model):
name = models.CharField(max_length=30)
class Arrival(models.Model):
tourist = models.ForeignKey(Tourist, on_delete=models.CASCADE)
place = models.ForeignKey(Etablissement, on_delete=models.CASCADE)
I want, for a Tourist, to have all his arrivals, per year.
I've tried this:
def detailTourist(request, id):
touriste = Tourist.objects.get(id=id)
datas = Arrival.objects.annotate(year=TruncYear('arrival_date')).values('year').annotate(total=Arrival.objects.filter(tourist=touriste)).order_by()
but it give me an error: sub-select returns 19 columns - expected 1 (the arrival model has 19 field so i guest that's why it says 19.
So finnaly, how can I do it please ?
You can use itertools.groupby(…) [Python-doc] to group the items, given it is already ordered by year:
from itertools import groupby
from operator import attrgetter
def detailTourist(request, id):
datas = Arrival.objects.annotate(year=TruncYear('arrival_date')).order_by('year')
datas = { y: list(vs) for y, vs in groupby(datas, attrgetter('year')) }
# …
Here it will create a dictionary that maps a year to a list of Arrival objects.
Related
class GenderTypeEnum:
FEMALE = 1
MALE = 2
UNKNOWN = 3
types = (
(FEMALE, _("Female")),
(MALE, _("Male")),
(UNKNOWN, _("Unknown"))
)
class PersonModel(models.Model):
identity = models.CharField(max_length=50, unique=True)
name = models.CharField(max_length=75)
last_name = models.CharField(max_length=75)
gender = models.PositiveIntegerField(choices=GenderTypeEnum.types)
class StaffModel(models.Model):
person = models.ForeignKey('PersonModel', on_delete=models.CASCADE, related_name='staffs')
registration_number = models.CharField(max_length=50, unique=True)
start_date = models.DateField()
finish_date = models.DateField(null=True, blank=True)
I am using the following query to list the gender statistics of the staff
StaffModel.objects.values("person__gender").annotate(count=Count("person__gender"))
output:
[
{"person__gender":1, "count":1},
{"person_gender":2, "count":5}
]
But gender field is a choices field so that, output that I want like this:
[
{"person__gender":1, "gender_exp":"Male", "count":1},
{"person_gender":2, "gender_exp":"Female", "count":5}
]
I created the following class by looking at the answer given to #bachkoi32 Display name of a choice field in Django while using annotate
In order to output, I use this class:
class WithChoices(Case):
def __init__(self, model, field, condition=None, then=None, **lookups):
fields = field.split('__')
for f in fields:
model = model._meta.get_field(f)
if model.related_model:
model = model.related_model
choices = dict(model.flatchoices)
whens = [When(**{field: k, 'then': Value(v)}) for k, v in choices.items()]
return super().__init__(*whens, output_field=CharField())
I changed my query:
qs = StaffModel.objects.values("person__gender").annotate(gender_exp=WithChoices(StaffModel, 'person__gender'), count=Count("person__gender")).values("person__gender","gender_exp","count")
When I want to print the query result, it raise the error;
django.db.utils.ProgrammingError: can't adapt type 'proxy'
qs = StaffModel.objects.values("person__gender").annotate(gender_exp=WithChoices(StaffModel, 'person__gender'), count=Count("person__gender")).values("person__gender","gender_exp","count")
print(qs)
# raise error;
# django.db.utils.ProgrammingError: can't adapt type '__proxy__'
The labels for your choices are lazy translations, these can't be passed as values to a query, they need to be converted to strings using force_str
from django.utils.encoding import force_str
class WithChoices(Case):
def __init__(self, model, field, condition=None, then=None, **lookups):
fields = field.split('__')
for f in fields:
model = model._meta.get_field(f)
if model.related_model:
model = model.related_model
choices = dict(model.flatchoices)
whens = [When(**{field: k, 'then': Value(force_str(v))}) for k, v in choices.items()]
return super().__init__(*whens, output_field=CharField())
I am learning django and I have not been able to properly do two things within model clearance:
Within modelRetrieve the name fields that correspond to the imo number selected.
Autopopulate a date field with the current day plus 7 days.
Any ideas what I am doing wrong? Here is my code:
from django.db import models
from django.core.exceptions import ValidationError
from django.utils import timezone
from datetime import timedelta, datetime
def imo_validator(value):
if value < 0 or value > 9999999:
raise ValidationError(
'This is not a valid IMO number',
params={'value':value},
)
class ship(models.Model):
imo = models.IntegerField(unique=True,validators=[imo_validator])
name = models.CharField(max_length=20)
rpm = models.FloatField()
power = models.FloatField()
main_engine = models.IntegerField()
class Meta:
ordering = ['imo']
def __str__(self):
return "{}, (IMO:{})".format(self.name, self.imo)
class clearance(models.Model):
STATUSES = [
('PENDING','PENDING'),
('REJECTED','REJECTED'),
('APPROVED','APPROVED'),
]
PORTS = [
('PACAN','PACAN'),
('PABLB','PABLB'),
('PACCT','PACCT'),
('PAANP','PAANP'),
('PAANA','PAANA'),
]
date_of_request = models.DateField(default=timezone.now,blank=False,editable=True)
imo = models.ForeignKey(ship, on_delete=models.PROTECT)
port = models.CharField(max_length=20,null=True,choices=PORTS)
eta = models.DateField(null=False)
name = ship.name.get(imo=imo)
calculated_eta = models.DateField(datetime.today + timedelta(days=1))
aduanas = models.FileField(blank=True)
aduanas_ok = models.CharField(max_length=15,default='PENDING',choices=STATUSES,editable=False)
minsa = models.FileField(blank=True)
minsa_ok = models.CharField(max_length=15,default='PENDING',choices=STATUSES,editable=False)
def __str__(self):
return "{}, ETA:{}".format(self.imo, self.eta)
class Meta:
ordering = ['eta']
To add a default to a DateField that is 7 days in the future you need to create a function that returns the date 7 days in the future and then pass that to the "default" parameter of the field
def seven_days_from_now():
return datetime.date.today() + datetime.timedelta(days=7)
class clearance(models.Model):
...
calculated_eta = models.DateField(default=seven_days_from_now)
...
Your "name" field should be a property that returns the name of the associated "imo"
class clearance(models.Model):
...
#property
def name(self):
return self.imo.name
...
Here is my model:
HomePhone = models.CharField(max_length=12, null=True)
Phone2 = models.CharField(max_length=12, null=True)
Phone3 = models.CharField(max_length=12, null=True)
Here is the filter:
class optionFilter(django_filters.FilterSet):
class Meta:
model = option2019
fields = {
'LastName': ['icontains',],
'FirstName':['icontains',],
'aidecode':['exact',],
'SSN':['icontains',],
'HomePhone':['exact',],
}
From the model, every one would have 3 phone numbers. How do I get the filter to look for all 3 phone number columns and return all info for the 1 person?
Thank you!
You have to declare a custom filter and use the method argument. In your case it would be something like
import django_filters
from django.db.models import Q
class optionFilter(django_filters.FilterSet):
phone = django_filters.CharFilter(method='phone_filter')
class Meta:
model = option2019
fields = {
'LastName': ['icontains',],
'FirstName':['icontains',],
'aidecode':['exact',],
'SSN':['icontains',],
'phone': ['exact',],
}
def phone_filter(self, queryset, name, value):
return queryset.filter(Q(HomePhone=value) | Q(Phone2=value) | Q(Phone3=value))
Im quite lost in this models, i want to Enter data in CourseScore. Course score will point to one student, and one course which the student registered.
I want to do automatic calculation at the time of data entry.
from django.db import models
from student.models import Student
# Create your models here.
class Course(models.Model):
name = models.CharField(max_length=200)
finternalmark=models.IntegerField(default=40)
fexternalmark = models.IntegerField(default=100)
fullmark = models.IntegerField()
def CalculateFullMark(self):
self.fullmark = self.finternalmark + self.fexternalmark
def __str__(self):
return f'{self.name}-{self.fintegermark}-{self.fexternalmark}'
class CourseRegistration(models.Model):
student = models.OneToOneField(Student, on_delete=models.CASCADE)
courses = models.ManyToManyField(Course)
def __str__(self):
return f'{self.student}'
class CourseScore(models.Model):
#entering marks for one course
CourseRegn = models.OneToOneField(CourseRegistration, on_delete=models.CASCADE)
internalmark = models.IntegerField()
externalmark = models.IntegerField()
marks = models.IntegerField()
def CalculateMarks(self):
self.marks = self.internalmark + self.externalmark
class SemesterResult(models.Model):
student = models.OneToOneField(Student, on_delete=models.CASCADE)
courses= models.ForeignKey(CourseScore,on_delete=models.CASCADE) # course in which the student is registered and marks are entered
totalmarks=models.IntegerField()
grandtotal = models.IntegerField()
def CalculateTotalMarks(self):
pass
#calculate totalmarks = sum of marks scored in courses that the students opted
def CalculateGrandTotal(self):
pass
#calculate grandtotal = sum of all fullmarks of the course that the student opted
I suggest you make the attributes you want to automatically calculate property methods using the #property decorator instead of calculating it in your model function :
#property
def marks(self):
return self.internalmark + self.externalmark
I want to filter query based on three user inputs. Depart City, Arrive City and Date. Depart City and Arrive city are on the same table called Route while the TravelDate is a foreign key in Route.
My model
class TravelDate(models.Model):
start_date = models.DateField(null = True)
interval = models.IntegerField(null = True)
class Route(models.Model):
depart_city = models.CharField(max_length=50, null=True, blank=False)
arrive_city = models.CharField(max_length=50, null=True, blank=False)
driver = models.ForeignKey(Driver)
schedule = models.ForeignKey(Schedule)
traveldate = models.ForeignKey(TravelDate)
My View
def newpage(request):
if 'origin' in request.GET and request.GET['origin']:
q = request.GET['origin']
c = request.GET['dest']
d = request.GET['travelDate']
results = Route.objects.filter(depart_city=q, arrive_city=c)
return render(request,'busapp/newpage.html', {'results': results})
else:
return render(request, 'busapp/newpage.html',{})
In Views how can i make one query that will filter depart_city, arrive_city, and TravelDate of those routes based on user inputed. If a bus is available on that date from city A to city B will be calculated by doing doing something like this if (d - TravelDate.start_date)% TravelDate.interval =0 then display the results to the user.
I cannot get this right. I'm new to Django and trying to learn.
Keep interval as IntegerField
views.py
from datetime import datetime, timedelta
q = request.GET['origin']
c = request.GET['dest']
d = request.GET['travelDate']
# d format is '20171122',convert str to date
start_date = datetime.strptime(d, "%Y%m%d").date()
results = Route.objects.filter(depart_city=q, arrive_city=c)
routes = []
for route in results:
if (start_date > date) and ((start_date - route.traveldate.start_date) % timedelta(days=route.traveldate.interva)) == timedelta(days=0):
routes.append(route)
return render(request,'busapp/newpage.html', {'results': routes})