django query use aggregate on joined table - django

In my project , Each candidate can take part in some assessments, each assessment has some tests and each test has some questions in it and candidates should answer the questions.
at the end of the test , scores of the questions are saved in question_score field (in QuestionResult model) automatically and the score of test is saved in test_score (which is average of question scores)
In TestOfAssessment model each test has a weight and I want to add a field to candidate model as assessment_score and write a method in candidate class model which calculate the score of assessment based on weight of each test and score of it
How can I use aggregate in my query with these joins on tables?
the simplified models are :
Assessment:
class Assessment(BaseModel):
title = models.CharField(max_length=255)
tests = models.ManyToManyField(
'exam.Test',
related_name='assessments',
blank=True,
through='TestOfAssessment',
)
candidates = models.ManyToManyField(
'user.User',
related_name='taken_assessments',
blank=True,
through='candidate.Candidate'
)
def __str__(self):
return self.title
Test:
class Test(BaseModel):
class DifficultyLevel(models.IntegerChoices):
EASY = 1
MEDIUM = 2
HARD = 3
questions = models.ManyToManyField(
'question.Question',
related_name='tests',
blank=True,
help_text='Standard tests could have multiple questions.',
)
level = models.IntegerField(default=1, choices=DifficultyLevel.choices)
title = models.CharField(max_length=255)
summary = models.TextField()
def __str__(self):
return self.title
TestOfAssessment:
class TestOfAssessment(models.Model):
assessment = models.ForeignKey('Assessment', on_delete=models.CASCADE)
test = models.ForeignKey('exam.Test', on_delete=models.CASCADE)
weight = models.PositiveSmallIntegerField(default=1)
order = models.IntegerField(default=0)
class Meta:
unique_together = ('assessment', 'test')
def __str__(self) -> str:
return f"{self.assessment} - {self.test}"
Question :
class Question(BaseModel):
question_text = models.TextField()
def __str__(self):
return truncatewords(self.question_text, 7)
TestResult:
class TestResult(BaseModel):
candidate = models.ForeignKey(
'Candidate',
on_delete=models.CASCADE,
related_name='test_results',
)
test = models.ForeignKey(
'exam.Test',
on_delete=models.CASCADE,
)
test_score = models.DecimalField(default=0.00, max_digits=5, decimal_places=2)
def __str__(self):
return f'{self.candidate.user.email} - {self.test.title}'
Candidate :
class Candidate(BaseModel):
assessment = models.ForeignKey(
'assessment.Assessment',
on_delete=models.CASCADE,
)
user = models.ForeignKey(
'user.User',
on_delete=models.CASCADE,
)
is_rejected = models.BooleanField(default=False)
def __str__(self):
return f'{self.user.email} - {self.assessment.title}'
QuestionResult :
class QuestionResult(BaseModel):
test = models.ForeignKey(
'TestResult',
on_delete=models.CASCADE,
related_name='question_results',
)
question = models.ForeignKey(
'question.Question',
on_delete=models.CASCADE,
related_name='results',
)
result = models.TextField(
null=True,
blank=True,
)
answer_score = models.DecimalField(default=0.00, max_digits=5, decimal_places=2)
def __str__(self):
return f'{self.test.candidate.user.email} - {self.question}'

Related

I am working on a django project that involves three models as indicated below Client,Loan,Payment

I am getting alot of duplicates in my template when i try to call the calculated loan payments in templates.
My models:
class Client(models.Model):
full_name = models.CharField(max_length=200,blank=True) staff=models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.SET_NULL,null=True,blank=True,related_name="client")
date = models.DateTimeField(default=timezone.now)
class Loan(models.Model):
ref = ShortUUIDField(length=6,max_length=6,alphabet="ABCDZXFQFHKRKL0123456789",unique=True)
loan_amount = models.IntegerField(blank=True,null=True)
staff=models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.SET_NULL,null=True,blank=True,related_name="loans")
search_client=models.ForeignKey(Client,on_delete=models.SET_NULL,null=True,blank=True)
#cached_property
def loan_repayments(self):
myfilter = Loan.objects.filter(ref=self.ref,payment__payment_reason='loan repayment')
result=myfilter.aggregate(total=Sum(F('payment__amount')))
total = result['total']
if total is None:
return 0
return total
class Payment(models.Model):
ref = ShortUUIDField(length=6,max_length=6,alphabet="ABCDZXFQFHKRKL0123456789",unique=True)
payment_reason = models.CharField(max_length=200, null=True, blank=True,choices=PAYMENT_REASON,default='loan repayment',db_index=True)
amount = models.IntegerField(blank=True, null=True)
lender = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL,
blank=True, null=True, related_name="payments")
loan = models.ForeignKey(Loan, on_delete=models.CASCADE,
blank=True, null=True)
my view:
class Loan(LoginRequiredMixin,ListView):
query_set =Loan.objects.filter(status="active",action="creating loan").select_related('staff','search_client')
context_object_name = 'transactions'
paginate_by = 15
my template:
duplicates am getting:
duplicates in the toolbar

Django convert FK field from INT to CHAR in order to use FIXTURES

MODEL DEPENDENCIA
class DependenciaManager(models.Manager):
def get_by_natural_key(self, descripcion, departamento):
return self.get(descripcion=descripcion, departamento=departamento)
class Dependencia(models.Model):
descripcion = models.CharField(max_length=300, blank=False, null=False)
cod_institucion = models.PositiveIntegerField(
blank=True,
null=True,
)
departamento = models.ForeignKey(
Departamento,
on_delete=models.PROTECT,
blank=False,
null=True,
to_field="descripcion",
)
objects = DependenciaManager()
class Meta:
constraints = [
models.UniqueConstraint(
fields=["descripcion", "departamento"], name="unico_nombre_pordpto"
)
]
def natural_key(self):
return (self.descripcion, self.departamento)
def __str__(self):
return f"{self.descripcion}"
MODEL PUESTO
class Puesto(models.Model):
numero = models.PositiveIntegerField(blank=False, null=False, primary_key=True)
cargo = models.ForeignKey(
Cargo,
on_delete=models.PROTECT,
blank=False,
null=True,
to_field="descripcion_cargo",
)
dependencia = models.ForeignKey(
Dependencia,
on_delete=models.PROTECT,
blank=False,
null=True,
)
def __str__(self):
return f"{self.numero}"
What I'm trying to accomplish is to have the "dependencia" field on Puesto model as Charfield, in order to pass for example this "[NTRA. SRA. DE LA ASUNCION,Capital]" and that can be mapped to the Dependencia Model, in the fields "Descripcion" and "Departamento".
The "descripcion" field in "Dependencia" can't have the argument unique= True, that's why I use the constraint of unique together.
Right now dependencia field in the puesto model is of type INT, because is pointing to ID (pk) in Dependencia model.

Getting Count Result With Multiple Conditions

I have models named Class, StudentList, Child, TakingQuiz and TakingQuizAnswer. Students can take exams. In this case, when they start the exam, data is added to the 'TakingQuiz' table. With each new answer, the answers are also recorded in the TakingQuizAnswer table.
The result I want to reach -> The question with the most mistakes in the exams solved by the students in a class.
I tried to use Count for this. I'm filtering answer_is_correct to False but that is insufficient. I also need to filter this data for the question column. So I need to get rows where both question and answer_is_correct = False columns are the same and return the first few most repetitive data as results.
I always get a general result in my experiments. I can't include rows where the question column is the same. How can I access the questions with the most mistakes in exams solved by students studying in a class?
Serializer
class ClassSerializerReport(ModelSerializer):
instructor = InstructorSerializerReport(source="instructor.user")
students = StudenListSerializerReport(many=True,
source="student_list_class")
max_incorrect_question = serializers.SerializerMethodField()
class Meta:
model = Class
exclude = [
"created_at",
"updated_at",
"school",
]
def get_max_incorrect_question(self, obj):
data = Class.objects.filter(id = obj.id).values('student_list_class__child__child_taking_quiz__taking_quizes').annotate(res = Count('student_list_class__child__child_taking_quiz__taking_quizes__question', filter = Q(student_list_class__child__child_taking_quiz__taking_quizes__answer_is_correct = False)))
print(data)
return {"question_id" : "I couldn't access that result yet."}
Related Models
class Class(AbstractSchoolBaseModel):
school = models.ForeignKey(
"school.School",
on_delete=models.CASCADE,
related_name="classes_school",
)
instructor = models.ForeignKey(
"account.InstructorProfile",
on_delete=models.CASCADE,
related_name="instructors_school",
)
name = models.CharField(
max_length=50,
)
grade = models.IntegerField(
)
class StudentList(AbstractSchoolBaseModel):
school_class = models.ForeignKey(
"school.Class",
on_delete=models.CASCADE,
related_name="student_list_class",
)
child = models.ForeignKey(
"account.ChildProfile",
on_delete=models.CASCADE,
related_name="student_list_children",
)
class ChildProfile(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
primary_key=True,
related_name="user_child")
city = models.ForeignKey(
"country.City",
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name="city_child_profiles")
hobbies = models.CharField(
max_length=500,
null=True,
blank=True,
)
class TakingQuiz(AbstractQuizBaseModel):
quiz = models.ForeignKey("quiz.Quiz", on_delete=models.DO_NOTHING, related_name="quiz_taking_quiz")
child = models.ForeignKey("account.ChildProfile", on_delete=models.CASCADE, related_name = "child_taking_quiz")
title = models.CharField(max_length=150, editable=False, default="-")
total_point = models.PositiveIntegerField(default=0)
class TakingQuizAnswer(AbstractQuizBaseModel):
taking_quiz = models.ForeignKey("quiz.TakingQuiz", on_delete=models.CASCADE, related_name="taking_quizes")
question = models.ForeignKey("quiz.Question", on_delete=models.DO_NOTHING, related_name="question_taking_quiz"e)
answer = models.ForeignKey("quiz.Answer", on_delete= models.DO_NOTHING, related_name="answer_taking_quiz")
taking_quiz_title = models.TextField(editable=False, null=True, blank=True)
question_text = models.TextField(editable=False, null=True, blank=True)
question_topic_content = models.TextField(editable=False, null=True, blank=True)
answer_text = models.TextField(editable=False, null=True, blank=True)
answer_is_correct = models.BooleanField(editable=False, null=True, blank=True)
class Quiz(AbstractQuizBaseModel):
ENABLED_CHOICES = (
(True, _("Active")),
(False, _("Not Active")),
)
book = models.ForeignKey("book.Book", on_delete= models.CASCADE, related_name="book_quiz")
title = models.CharField(max_length=150)
enabled = models.BooleanField(choices=ENABLED_CHOICES, default=False)
class Question(AbstractQuizBaseModel):
quiz = models.ForeignKey("quiz.Quiz", on_delete=models.DO_NOTHING, related_name="question_quiz")
question = models.CharField(max_length=500)
topic = models.CharField(max_length=500)
class Answer(AbstractQuizBaseModel):
IS_CORRECT_CHOICES = (
(True, _("Correct Answer")),
(False, _("Wrong Answer"))
)
question = models.ForeignKey("quiz.Question", on_delete=models.CASCADE, related_name = "question_answer")
answer = models.CharField(max_length=500)
is_correct = models.BooleanField(choices=IS_CORRECT_CHOICES, default=False)

Django ORM Count Without Duplicate Column

I have a table called Reading History. I want to find the average number of reads in this table. I wrote the following method for this, but I can't get the right result. Records are made in the table once (student-book records with the same values). When the same record comes, the counter value is increased by one.
For example, suppose that two different students read two different books. I expect total reads / 2 but the result I get is total reads / 4 because there are 4 rows in the table. How can I calculate this? For example, if a student reads 4 different books once, the average will be 1, but the average should be 4.
I tried to use distinct and values but I couldn't get the result I wanted. Maybe I didn't manage to use it correctly. Also I tried to use Avg. When avg didn't give the correct result, I tried to break it down and get the values myself. Normally, Avg was written in Sum.
Serializer
class ClassReadingHistoryReportSerializer(ModelSerializer):
instructor = InstructorForClassSerializer(source="instructor.user")
students = StudenListReadingHistoryReportSerializer(many=True,
source="student_list_class")
avg_read_book = serializers.SerializerMethodField()
class Meta:
model = Class
exclude = [
"created_at",
"updated_at",
"school",
]
def get_avg_read_book(self, obj):
sum_read_book = Class.objects.filter(id = obj.id).aggregate(sum_read=Sum('student_list_class__child__child_reading_history__counter'))
count_child_record = Class.objects.filter(id = obj.id).aggregate(count_child=Count('student_list_class__child__child_reading_history'))
return None
Models
class ChildProfile(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
primary_key=True,
verbose_name=AccountStrings.ChildProfileStrings.user_verbose_name,
related_name="user_child")
city = models.ForeignKey(
"country.City",
on_delete=models.SET_NULL,
null=True,
blank=True,
verbose_name=AccountStrings.ChildProfileStrings.city_verbose_name,
related_name="city_child_profiles")
hobbies = models.CharField(
max_length=500,
null=True,
blank=True,
verbose_name=AccountStrings.ChildProfileStrings.hobbies_verbose_name)
class Meta:
verbose_name = AccountStrings.ChildProfileStrings.meta_verbose_name
verbose_name_plural = AccountStrings.ChildProfileStrings.meta_verbose_name_plural
#property
def get_full_name(self):
return f"{self.user.first_name} {self.user.last_name}"
def __str__(self):
return self.get_full_name
def clean(self) -> None:
"""
This method will check if the user type is a child during creation.
"""
if self.user.user_type != 2:
raise ValidationError(AccountStrings.ChildProfileStrings.user_type_error)
class School(AbstractSchoolBaseModel):
city = models.ForeignKey(
"country.City",
on_delete=models.DO_NOTHING,
related_name="city_schools",
verbose_name=SchoolStrings.SchoolStrings.city_verbose_name)
name = models.CharField(
max_length=250,
verbose_name=SchoolStrings.SchoolStrings.name_verbose_name)
address = models.CharField(
max_length=250,
verbose_name=SchoolStrings.SchoolStrings.address_verbose_name)
website = models.CharField(
max_length=250,
verbose_name=SchoolStrings.SchoolStrings.website_verbose_name)
class Meta:
verbose_name = SchoolStrings.SchoolStrings.meta_verbose_name
verbose_name_plural = SchoolStrings.SchoolStrings.meta_verbose_name_plural
def __str__(self):
return self.name
class Class(AbstractSchoolBaseModel):
school = models.ForeignKey(
"school.School",
on_delete=models.CASCADE,
related_name="classes_school",
verbose_name=SchoolStrings.ClassStrings.school_verbose_name)
instructor = models.ForeignKey(
"account.InstructorProfile",
on_delete=models.CASCADE,
related_name="instructors_school",
verbose_name=SchoolStrings.ClassStrings.instructor_verbose_name)
name = models.CharField(
max_length=50,
verbose_name=SchoolStrings.ClassStrings.name_verbose_name)
grade = models.IntegerField(
verbose_name=SchoolStrings.ClassStrings.grade_verbose_name)
class Meta:
verbose_name = SchoolStrings.ClassStrings.meta_verbose_name
verbose_name_plural = SchoolStrings.ClassStrings.meta_verbose_name_plural
ordering = ["name", "grade"]
def __str__(self):
return f"{self.school.name} - {self.name} - Grade: {self.grade}"
def clean(self) -> None:
"""
This method checks whether the teacher trying to be assigned to the class is working in that school.
"""
if self.instructor.school != self.school:
raise ValidationError(SchoolStrings.ClassStrings.instructor_not_working_at_this_school_error)
class StudentList(AbstractSchoolBaseModel):
school_class = models.ForeignKey(
"school.Class",
on_delete=models.CASCADE,
related_name="student_list_class",
verbose_name=SchoolStrings.StudentListStrings.school_class_verbose_name
)
child = models.ForeignKey(
"account.ChildProfile",
on_delete=models.CASCADE,
related_name="student_list_children",
verbose_name=SchoolStrings.StudentListStrings.child_verbose_name)
class Meta:
verbose_name = SchoolStrings.StudentListStrings.meta_verbose_name
verbose_name_plural = SchoolStrings.StudentListStrings.meta_verbose_name_plural
def __str__(self):
return f"{self.school_class.name} : {self.child.user.first_name} {self.child.user.last_name}"
def clean(self) -> None:
result = StudentList.objects.filter(school_class = self.school_class, child = self.child)
if not self.pk and result.exists():
raise ValidationError(SchoolStrings.StudentListStrings.child_already_added_to_this_class_error)
class ReadingHistory(AbstractBookBaseModel):
IS_FINISHED = ((False,
BookStrings.ReadingHistoryStrings.is_finished_false),
(True, BookStrings.ReadingHistoryStrings.is_finished_true))
book = models.ForeignKey(
"book.Book",
on_delete=models.CASCADE,
related_name="book_reading_history",
verbose_name=BookStrings.ReadingHistoryStrings.book_verbose_name)
child = models.ForeignKey(
"account.ChildProfile",
on_delete=models.CASCADE,
related_name="child_reading_history",
verbose_name=BookStrings.ReadingHistoryStrings.child_verbose_name)
is_finished = models.BooleanField(
choices=IS_FINISHED,
verbose_name=BookStrings.ReadingHistoryStrings.is_finished_verbose_name
)
counter = models.PositiveIntegerField(
verbose_name=BookStrings.ReadingHistoryStrings.counter_verbose_name,
default=0)
class Meta:
verbose_name = BookStrings.ReadingHistoryStrings.meta_verbose_name
verbose_name_plural = BookStrings.ReadingHistoryStrings.meta_verbose_name_plural
def __str__(self):
return f"{self.child.user.first_name} {self.child.user.last_name} - \"{self.book.name}\" "
def clean(self) -> None:
result = ReadingHistory.objects.filter(child=self.child,
book=self.book)
if not self.pk and result.exists():
raise ValidationError(
BookStrings.ReadingHistoryStrings.exists_error)
I forgot to add the counter column in the BookReadingHistory table to the diagram. Diagram and Table data are shown in the images below.
Table
Diagram

business generated has to come based on dcr(daily call report)

I have DCR & SalesMIS model. I want to get the business generated count. And if count is it should return the business_genrated else saleMIS.amount
I wrote a method in DCR model i.e. get_business_generated(self) and apply filter on SaleMIS model. Then trying to get the count of business_generated
ERROR:D:\Projects\Python\Django\kingllp\venv\lib\site-packages\django\db\models\base.py", line 95, in new
"INSTALLED_APPS." % (module, name)
RuntimeError: Model class builtins.DCR doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.
This is DCR model
class DCR(models.Model):
STATUSES = (
('1N', 'Need Analysis'),
('2P', 'Proposal Stage'),
('3C', 'Competitive Selling'),
('4D', 'Decision Stage'),
)
prospect = models.ForeignKey(Prospect, on_delete=models.CASCADE, related_name='dcrs')
date = models.DateField(blank=True)
status = models.CharField(choices=STATUSES, max_length=2, default='1N')
discussion_points = models.CharField(max_length=2047, blank=True)
business_generated = models.IntegerField(default=0)
is_new_business = models.BooleanField(default=False)
def get_business_generated(self):
date = self.date
client = self.prospect
sale = SalesMIS.objects.filter(date=date,client = Prospect)
salecount = sale.count()
if salecount==0:
return DCR.business_generated
else:
return SalesMIS.amount
This is SaleMIS model
class SalesMIS(models.Model):
class Meta:
verbose_name_plural = _("Sale MIS")
date = models.DateField()
fls = models.ForeignKey(Employee, blank=True, null=True, on_delete=models.SET_NULL, related_name='sales')
amount = models.DecimalField(max_digits=20, decimal_places=2)
po_number = models.CharField(max_length=255, null=True, blank=True)
products = models.CharField(max_length=255, null=True, blank=True)
client = models.ForeignKey(Client, blank=True, null=True, on_delete=models.SET_NULL, related_name='client_mis')
def __str__(self):
return str(self.date) + ":" + self.fls.full_name()
Business share has to come based on DCR/MIS.