Queryset for models FK relations in django - python

These are my models and fields:
Models.py
Course:
title
slug
CoursePrerequisite
this_course = ForeignKey(Course)
prerequisite_of_course = ForeignKey(Course)
Curriculum:
course = ForeignKey(Course,)
title
slug
Enrollment:
student = ForeignKey(User)
curriculum =ForeignKey(Curriculum)
date
Brif of my system:
As seen from my model file, in this system, the courses have a
pre-requisite state.Untile preson can't pass pre-requisite of course, can't take the course.
Each course is presented for enrollment in model named:
'Curriculum'.
And finally my problem is:
In fact, I know that I must first check student enrollment and find the 'Curriculum' that he have,and by this, find all course of student. Then,among the course I will find the course that have prerequisite_of_course and finally check for student for each of this prerequisite course check that student enroll in course curriculum!
It's very hard for me to write this query? Can you help me?

Check this, this can help your query
# all student enrollments
all_enrollment = Enrollement.objects.filter(student=user)
# all students curriculum_ids
all_curriculum_ids = all_enrollment.values_list('curriculum', flat=True)
# all curriculum object list
all_curriculum = Curriculum.objects.filter(pk__in=all_curriculum_ids)
# all student curriculum courses
all_courses_ids = all_curriculum.values_list('course', flat=True)
# we have all courses that student participated
all_courses = Course.objects.filter(pk__in=all_courses_ids)
# Now getting prerequisite_of_course ids
all_prerequisite_of_course_ids = CoursePrerequisite.objects.filter(this_course=this_course,prerequisite_course__isnull=False).value_list('prerequisite_course')
# here checking if student took all prequisite courses
for prerequisite_of_course_id in all_prerequisite_of_course_ids:
if all_courses.filter((pk__in=prerequisite_of_course_id).exists():
print("Paticipated")
else:
print("In this course id student did not participated", prerequisite_of_course_id)
print("Tell Student to go and complete this course")

Related

Django: How to access the previous model class instances while creating new instance of the same class?

I have a model in my django app like below:
models.py
class Profit(models.Model):
client = models.ForeignKey(Client, null=True, on_delete=models.CASCADE)
month = models.CharField(max_length=100)
amount = models.IntegerField()
total_profit = models.IntegerField()
Now, what I want to do is that whenever a new instance/object is created for this class, the user puts the month and the amount of profit for that month, But I want that it also calculates the total profit the user got up till the current profit, by adding all the profits that was being added in the past.
For example.
if the user is adding the profit for month April, then it add all the values in the amount field of previously added objects of (March, February, January and so on..) and put it in the field total_profit. So that the user can see how much total_profit he got at each new entry.
My views.py where I am printing the list of profits is given below:
views.py
class ProfitListView(ListView):
model = Profit
template_name = 'client_management_system/profit_detail.html'
context_object_name = 'profits'
# pk=self.kwargs['pk'] is to get the client id/pk from URL
def get_queryset(self):
user = get_object_or_404(Client, pk=self.kwargs['pk'])
return Profit.objects.filter(client=user)
Client is the another model in my models.py to which the Profit class is connected via ForeignKey
I also don't exactly know how to use window functions inside this view.
As stated in the comments one should generally not store things in the database that can be calculated from other data. Since that leads to duplication and then makes it difficult to update data. Although if your data might not change and this is some financial data one might store it anyway for record keeping purposes.
Firstly month as a CharField is not a very suitable field of yours for your schema. As firstly they are not easily ordered, secondly it would be better for you to work with a DateTimeField instead:
class Profit(models.Model):
month = models.CharField(max_length=100) # Remove this
made_on = models.DateTimeField() # A `DateTimeField` is better suited
amount = models.IntegerField()
total_profit = models.IntegerField()
Next since you want to print all the Profit instances along with the total amount you should use a Window function [Django docs] which will be ordered by made_on and we will also use a frame just in case that the made_on is same for two entries:
from django.db.models import F, RowRange, Sum, Window
queryset = Profit.objects.annotate(
total_amount=Window(
expression=Sum('amount'),
order_by=F('made_on').asc(),
frame=RowRange(end=0)
)
)
for profit in queryset:
print(f"Date: {profit.made_on}, Amount: {profit.amount}, Total amount: {profit.total_amount}")

Verify a Django model field inside a Django model

I have a Django model called Attendance that has the clock in and clock in times of an employee along with the status of that entry, to see whether it's authorized or not. I then, am making another model called Payroll. I want this to check inside the Attendance entries to see all the Authorized entries and then do some action on them. How do I check all the status fields for all the entries in Attendance?
EDIT: Updated to better elaborate my question.
To better elaborate my question, this is how I've setup my Attendance model:
class CWorkAttendance(models.Model):
AUTO_ATT = "AU"
MANUAL_ATT = "MA"
WORK_ENTRY_TYPES = (
(AUTO_ATT, "Auto-Attendance"),
(MANUAL_ATT, "Manual-Attendance"),
)
AUTHORIZED = "AU"
UNAUTHORIZED = "UA"
WORK_ENTRY_STATUSES = (
(AUTHORIZED, "Athorized"),
(UNAUTHORIZED, "Un-Authorized"),
)
#Thank you motatoes
def face_locations_in(self, instance):
now = datetime.datetime.now()
return "attendance/{}/{}/in".format(instance.work_employee, now.strftime("%Y/%m/%d"))
def face_locations_out(self, instance):
now = datetime.datetime.now()
return "attendance/{}/{}/out".format(instance.work_employee, now.strftime("%Y/%m/%d"))
work_employee = models.ForeignKey('CEmployees', on_delete=models.CASCADE,)
work_start_time = models.DateTimeField()
work_end_time = models.DateTimeField(null=True)
work_duration = models.IntegerField(null=True)
work_entry_type = models.CharField(max_length=2,choices=WORK_ENTRY_TYPES)
work_entry_status = models.CharField(max_length=2, choices=WORK_ENTRY_STATUSES, default=WORK_ENTRY_STATUSES[1][0])
employee_face_captured_in = models.ImageField(upload_to=face_locations_in,)#////////
employee_face_captured_out = models.ImageField(upload_to=face_locations_out,)
If you look closely at the work_entry_status, it's a choice CharField that will contain the status of the entry (UNAUTHORIZED by default).
I want to create a Payroll model that will check for all the rows in the CWorkAttendance model and check their work_entry_status fields to see if they are Authorized, which is what I want to learn how to do.
If those fields are authorized, I want the grab the row's work_employee, work_duration and also some details from the original CEmployees row for the employee.
This is what I want my Payslip/Payroll model to look like:
class Payslip(models.Model):
GENERATED = "GEN"
CONFIRMED = "CON"
PAYSLIP_STATUS = (
(GENERATED, "Generated-UNSAVED"),
(CONFIRMED, "Confirmed-SAVED"),
)
payslip_number = models.IntegerField()#MM/YY/AUTO_GENERATED_NUMBER(AUTO_INCREMENT)
payslip_employee = models.ForeignKey('CEmployees', on_delete=models.CASCADE,)#Choose the employee from the master table CEmployees
payslip_generation_date = models.DateTimeField(default=datetime.datetime.now())#Date of the payroll generation
payslip_total_hours = models.IntegerField()#Total hours that the employee worked
payslip_from_date = models.DateField()"""The date from when the payslip will be made. The payslip will be manual for now, so generate it after choosing a a date to generate from."""
payslip_total_basic_seconds = models.IntegerField()#Total seconds the employee worked
payslip_total_ot_seconds = models.IntegerField()#Total overtime seconds the employee worked
payslip_basic_hourly_rate = models.IntegerField()#The basic hourly rate of the employee mentioned here. Take from the master employees table.
payslip_basic_ot_rate = models.IntegerField()#Taking the basic overtime rate from the master table
payslip_total_amount = models.FloatField()#The total amount of the payslip
payslip_entry_status = models.CharField(max_length=3, default=GENERATED)#The status of the pay slip.
Thanks,
Not sure if I understand your requirements well, so let me know if I misunderstood.
# `employee` is the work_employee in question
# if you don't want to filter by employee, remove `work_employee=employee`
attendances = CWorkAttendance.objects.filter(work_entry_status=CWorkAttendance.AUTHORIZED, work_employee=employee)
for attendances in attendances:
# do things with this attendance record
attendance.work_duration
attendance.employee
# ....
Update
Since you would like to do it manually, I would suggest having a separate view to generate the Payslip. The important thing is to know the date_from and the date_to for this payslip. I imagine that it is the managers who would have access to this view, so you would need the proper access controls set for it. I also think you need to have a payslip_to_date even if you are going to generate it until the current date, which will be useful for record keeping. I assume you have that column in the code below.
views.py:
from django.views import View
class GeneratePayslip(View):
"""
make sure you have the right access controls set to this view
"""
def post(self, request, **kwargs):
employee_id = kwags.POST.get("employee_id")
date_from = kwargs.POST.get("from_date")
date_to = kwargs.POST.get("to_date")
# we fetch all the objects within range
attendances = CWorkAttendance.objects.filter( \
work_entry_status=CWorkAttendance.AUTHORIZED, \
work_employee_id=employee_id, \
work_start_time__gte=date_from, \
work_end_time__lte=date_to \
)
hours = 0
for attendance in attendances:
# perform calculations to compute total sum and rate
pass
# create the payslip object here ..
# redirect to a success page and return
If you wanted to do it automatically later on, you may want to generate payslips automatically, once a month. For that you could use something like Celery to have periodic tasks that run in the background, for each employee. If this is the case you could move the above code to a file such as utils.py. you can create a method which takes employee_id, from_date, to_date, and then generate the payslip object, returning the payslip_id to the calling method

deal with many2many field in odoo

I have two models skills and res_users.
I want that each user can have many skills and also each skill can have many users on it. I tried to do that but without success.
This is my skills:
class technicians_skills(osv.osv):
_name = 'skills'
_description = 'Technicians Skills'
_columns = {
'name': fields.char(string='name', size=50),
'description': fields.text(string="description"),
'member_ids': fields.many2many('res.users', 'skill', string='Technicians')
}
and this is the users :
class res_users(osv.osv):
_inherit = 'res.users'
_columns = {
'skill': fields.many2many('skills', relation='skills.rel', column1='name', column2='skill', string='Skill'),
}
and I want to know the skills of each user, but when I call this :
test = http.request.env['skills.rel'].search([])
It shows me this error
KeyError: 'skills.rel'
You need to specify all key words in your declaration to create the same relation tables
fields.many2many(
comodel_name='model.name',
relation='valid_postgres_name',
colum1='current_model_m2o_field_name',
column2='comodel_m2o_name',
string='Label')
And in the other definition keep the same name of the relation but inverse the other keyword.
In skills
user_ids = fields.many2many('re.users', 'user_skill_rel','user_id','skill_id', 'Users')
In users
skill_ids = fields.many2many('skills', 'user_skill_rel', 'skill_id', 'user_id', 'Skills')
See how i inversed the definition only the relation is the same.
Keep the same names of columns
EDITS:
don't execute search on relation because they are not models. you need to execute the search on the model then access the many2many fields.
Let say you want to get skill of the current user.
self.env.user.skill_ids # this will return the list of the skills for the current user
if you want to get the skills of more than one user.
result = self.env['res.users'].search([your_domain]])
# if you need to show user information then it's skill
for rec in result:
# use loop
rec.name # user name
rec.skill_ids
# but if you want to get the list of skill and you don't need users
skills = result.mapped('skills_ids') # mapped will return all the skills without duplication

Generate input fields based on a input and store it properly

I have a field called subjects that asks users how many subjects do they have and based on the number they input I want to generate the input fields of same number. And How and where do I store those inputs.
MODELS.PY
#this field will determine how many input fields to generate
subjects = models.IntegerField()
VIEWS.PY
def generate_forms(request):
no_of_fields = request.GET.get('subjects')
if no_of_fields:
#generate other inupts
#save it in the database
Besides generating the input, how do I save those data in the database.
Thanks in advance
If you use postgres you can use django postgres specefic models fields(Like ArrayField).django specefic fields documention
For another databases you can create model for your subjects and for each subject you can insert new data in Subject model.
class Subject(models.Model):
desc = models.CharField(max_length=50)
other_filed = models.ForeignKey(OtherModel)
def generate_forms(request):
other_field = 1
subjects = request.GET.get('subjects')
if subjects and subjects != '':
for subject in subjects:
Subject.objects.create(desc=subject, other_field=other_field)

How to select records in the case of a many to many relation with ponyorm

I am new to ponyorm.
Suppose I have these two classes and a many-to-many relation among them:
class Student(db.Entity):
id = PrimaryKey(str)
name = Required(str)
courses = Set("Course")
class Course(db.Entity):
id = PrimaryKey(str)
name = Required(str)
semester = Required(int)
students = Set(Student)
And I want to select some courses which are followed by a particular student. What I do is:
student = Student.select(lambda s: s.id == id).get()
courses = Course.select(lambda c: c.students == student).get()
And I get this error:
Incomparable types 'Set of Student' and 'Student' in expression: c.students == student
What is the correct way to do this?
Thanks
I don't know the exact library but I think the issue is that c.students specifies the set of all students so testing for equality just like that doesn't make too much sense.
You might want to change your second line to something like this (I didn't test it though):
Course.select(lambda c: student in c.students).get()
This leaves me wondering if there is actually a better way to do this. If all you are trying is to retrieve the courses a specific students attends why don't you just retrieve the courses field from the variable student?
Something like
student = Student.select(lambda s: s.id == id).get()
student.courses # do something with it

Categories

Resources