Insert values in related models based on foreign key - django

I'm trying to insert values for related one to many models through a form. I'm having some difficulties.
I have three related models:
class Member(models.Model):
member_id = models.AutoField(primary_key=True)
first_name = models.CharField(max_length=50, default='test first name')
last_name = models.CharField(max_length=50, default='test last name')
class Loans (models.Model):
loan_id = models.AutoField(primary_key = True)
member = models.ForeignKey('Member',related_name='loans')
class Transactions (models.Model):
transaction_id = models.AutoField(primary_key=True)
amount = models.DecimalField(max_digits = 10, decimal_places = 2)
loans = models.ForeignKey('Loans', related_name='transactions')
Basically, one Member can have one to many Loans, one Loan can have one to many Transactions (although it should be 0 to many, but I'm just testing at the moment).
I have a form that asks for member's full name, loan id and amount.
Basically I'm trying to find the Member based on the full name, then get the loan based on the id provided, and then create a new transaction for that loan.
What I have done in my view:
fullName = request.GET.get('full_name')
loanID = request.GET.get('loan_id')
amount = request.GET.get('amount')
#to get first name
firstName = fullName.partition(' ')[0]
#to get last name
lastName = fullName.rsplit(None, 1)[-1]
#to get the member
member = Member.objects.filter(first_name=firstName, last_name = lastName)
#get member's loan based on loanID
l = Loans(loan_id = loanID)
t = Transactions.objects.create(amount = amount, transactions = l)
t.save()
I get an error when I submit the form:
'transactions' is an invalid keyword argument for this function
Am I using the correct approach but not understanding model relationships?
Or am I totally in the wrong track?
Any help/direction would be appreciated,
Thanks in advance

Try t = Transactions.objects.create(amount = amount, loans = l)
There's no transactions field in Transactions. There are amount and loans and loans is the Loans instance you got in l

It can also work as follows:
l = Loans.objects.get(loan_id = loanID)
t = Transactions.objects.create(loans = l,amount = amount, ,transaction_id=uuid.uuid4())
t.save()
And you can get transaction_id also as a primary key , which further you can use as foreign key for another table.

Related

Query with two ForeignKeys in a model and filter on one of the ForeignKey

I have the three models:
class SegmentEffort(models.Model):
id = models.BigIntegerField(primary_key=True)
activity = models.ForeignKey(to=Activity)
segment = models.ForeignKey(to=Segment)
class Segment(models.Model):
id = models.BigIntegerField(primary_key=True)
name = models.CharField(max_length=255)
class Activity(models.Model):
id = models.BigIntegerField(primary_key=True)
user = models.ForeignKey(to=settings.AUTH_USER_MODEL)
name = models.CharField(max_length=255)
I want to get all distinct segments from SegmentEffort where SegmentEffort is filtered by Activity belonging to a specific user.
I can get a list of all the segment ids by:
sids = SegmentEffort.objects.filter(activity__user=10).order_by('segment_id').values_list('segment_id',
flat=True).distinct()
But I can't get my head around getting distinct a segment queryset... Not enough experience with queries on two ForeignKeys in a model (SegmentEffort).
Thanks for your help, and don't hesitate to ask for clarification id the question is unclear!

Filter objects from a table based on ManyToMany field

I am working on a messaging app.
The models are as follows.
class ChatRoom(SafeDeleteModel):
_safedelete_policy = SOFT_DELETE_CASCADE
room_name = models.CharField(max_length=100, null=True, blank=True)
participants = models.ManyToManyField(User)
class Meta:
db_table = TABLE_PREFIX + "chat_room"
class Message(SafeDeleteModel):
_safedelete_policy = SOFT_DELETE_CASCADE
chat_room = models.ForeignKey(ChatRoom, on_delete=models.CASCADE)
message = models.TextField()
sent_by = models.ForeignKey(User, on_delete=models.CASCADE)
created_on = models.DateTimeField(default=django.utils.timezone.now)
class Meta:
db_table = TABLE_PREFIX + "chat_message"
I have to filter ChatRoom object which contains a list of users.
Eg: On sending data like this to the api
{
"participants": [2,3]
}
It should return a ChatRoom object which contains both user '2' and user '3' as participants.
I had tried filtering it with
room = ChatRoom.objects.filter(participants__in=serializer.validated_data['participants'])
but it returns a list of room objects with user '1' and user '2'.
I had also tried using get() but it returns an error.
What am I doing wrong and how can i do it right?
Thanks for looking into my problem. Hope you have a solution.
You said you are using Query..
ChatRoom.objects.filter(participants__in=serializer.validated_data['participants'])
filter function returns a list of objects of the model matching the conditions.
get function only return a single object of model and if none or more than one item matches the condition then an exception is thrown. That is why get is only used for candidate keys or unique resultant conditions.
In your case, I suppose both participants can be part of many rooms, also there might be a possibility that there is no such room. if you want only one queryset to be returned you can use this.
room_list= ChatRoom.objects.filter(participants__in=serializer.validated_data['participants']
if len(room_list) >0:
room = room_list[0]
else:
room = None
This will return the first room in which all the given participants are present, you can replace 0 with any valid value or add something more in the query if you want it to return a specific room.

Django query complex query in one to one field model

I have two models of Student and Parent
Student models.py:
class StudentInfo(models.Model):
admissionNumber = models.BigIntegerField(primary_key=True,default=0)
firstName = models.CharField(max_length=20)
lastName = models.CharField(max_length=20)
fullName = models.CharField(max_length=50)
gender = models.CharField(max_length=20)
dob = models.DateField(null=True)
classSection = models.CharField(max_length=20)
Parent models.py
class ParentInfo(models.Model):
student = models.OneToOneField(StudentInfo,primary_key=True, on_delete=models.CASCADE)
fatherName = models.CharField(max_length=20)
motherName = models.CharField(max_length=20)
I have a form to search students through their fatherName.
So, what I want is to filter those students whose father's name contains 'some name'.
I tried this but it resultes in query set of ParentInfo:
parentInfo = ParentInfo.objects.all()
studentsInfo = parentInfo.filter(parent__fName = fName).select_related('student')
You should filter the opposite way, like:
StudentInfo.objects.filter(parentinfo__fatherName='name of father')
You here thus obtain a QuerySet of StudentInfos which contains zero, one, or more StudentInfos where there is a related ParentInfo object where the fatherName field is, in this case 'Name of father'.
Note: It might be better to implement a ForeignKey in the opposite order, such that multiple students can refer to the same ParentInfo object. Right now, a ParentInfo object can refer to exactly one StudentInfo. If there are students with the same parents (so siblings), then you introduce data duplication in the database.
# You can use contains attribute on the field of model and your query can be like this
student = models.ParentInfo.objects.values('student__firstName', 'student__lastName').filter(fatherName__contains='your value')
print(student[0]['student__firstName'])
print(student[0]['student__lastName'])

django query with prefetch_related

I am struggling to get at the data I need from a prefetch-related query.
I have a table of events (the calendar table), a table of members and an attendee table which links the two.
My models look like:
class Member(models.Model):
firstname = models.CharField(max_length=40)
lastname = models.CharField(max_length=50)
email = models.EmailField(blank=True, verbose_name ='e-mail')
phone = models.CharField(max_length=40)
membershipnum = models.CharField(max_length=40)
class Attendee(models.Model):
memberid = models.ForeignKey(Member, on_delete=models.SET(0), related_name="attendingmembers")
calendarid = models.ForeignKey(Calendar, on_delete=models.SET(0))
attended = models.BooleanField(default=0)
paid = models.BooleanField(default=0)
class Meta:
db_table = 'attendee'
For a particular event I want a list of attending members with the attended and paid fields from the attendee table.
In my view I have
attendees = Member.objects.filter(attendingmembers__calendarid_id=id).prefetch_related('attendingmembers')
I am getting the right members, but I don't know if this is the best way to do it? And I can't figure out how to get at the attendee fields.
If I do
for thisone in attendees:
print(thisone)
print(thisone.attendingmembers)
I get the expected return from the first print, but the second just gives me
myapp.Attendee.None
Any advice much appreciated.
You still need .all() to get the list of items of your relation:
for this one in attendees:
print(thisone.attendingmembers.all())
Btw, do you wish to get all attendingmembers or only the ones with the right calendar_id ?
attendees = Member.objects.filter(attendingmembers__calendar_id=id).prefetch_related('attendingmembers')
# return all Members having at least one attendingmember with calendar_id=id, and prefetch all of their attendingmembers
attendees = Member.objects.filter(attendingmembers__calendar_id=id).prefetch_related(Prefetch('attendingmembers', queryset=Attendee.objects.filter(calendar_id=id)))
# return all Members having at least one attendingmember with calendar_id=id, and prefetch their attendingmembers matching the filter
The documentation shows you how to use the to_attr argument in the Prefetch objects ;)

Django: Filter in multiple models linked via ForeignKey?

I'd like to create a filter-sort mixin for following values and models:
class Course(models.Model):
title = models.CharField(max_length=70)
description = models.TextField()
max_students = models.IntegerField()
min_students = models.IntegerField()
is_live = models.BooleanField(default=False)
is_deleted = models.BooleanField(default=False)
teacher = models.ForeignKey(User)
class Session(models.Model):
course = models.ForeignKey(Course)
title = models.CharField(max_length=50)
description = models.TextField(max_length=1000, default='')
date_from = models.DateField()
date_to = models.DateField()
time_from = models.TimeField()
time_to = models.TimeField()
class CourseSignup(models.Model):
course = models.ForeignKey(Course)
student = models.ForeignKey(User)
enrollment_date = models.DateTimeField(auto_now=True)
class TeacherRating(models.Model):
course = models.ForeignKey(Course)
teacher = models.ForeignKey(User)
rated_by = models.ForeignKey(User)
rating = models.IntegerField(default=0)
comment = models.CharField(max_length=300, default='')
A Course could be 'Discrete mathematics 1'
Session are individual classes related to a Course (e.g. 1. Introduction, 2. Chapter I, 3 Final Exam etc.) combined with a date/time
CourseSignup is the "enrollment" of a student
TeacherRating keeps track of a student's rating for a teacher (after course completion)
I'd like to implement following functions
Sort (asc, desc) by Date (earliest Session.date_from), Course.Name
Filter by: Date (earliest Session.date_from and last Session.date_to), Average TeacherRating (e.g. minimum value = 3), CourseSignups (e.g. minimum 5 users signed up)
(these options are passed via a GET parameters, e.g. sort=date_ascending&f_min_date=10.10.12&...)
How would you create a function for that?
I've tried using
denormalization (just added a field to Course for the required filter/sort criterias and updated it whenever changes happened), but I'm not very satisfied with it (e.g. needs lots of update after each TeacherRating).
ForeignKey Queries (Course.objects.filter(session__date_from=xxx)), but I might run into performance issues later on..
Thanks for any tipp!
In addition to using the Q object for advanced AND/OR queries, get familiar with reverse lookups.
When Django creates reverse lookups for foreign key relationships. In your case you can get all Sessions belonging to a Course, one of two ways, each of which can be filtered.
c = Course.objects.get(id=1)
sessions = Session.objects.filter(course__id=c.id) # First way, forward lookup.
sessions = c.session_set.all() # Second way using the reverse lookup session_set added to Course object.
You'll also want to familiarize with annotate() and aggregate(), these allow you you to calculate fields and order/filter on the results. For example, Count, Sum, Avg, Min, Max, etc.
courses_with_at_least_five_students = Course.objects.annotate(
num_students=Count('coursesignup_set__all')
).order_by(
'-num_students'
).filter(
num_students__gte=5
)
course_earliest_session_within_last_240_days_with_avg_teacher_rating_below_4 = Course.objects.annotate(
min_session_date_from = Min('session_set__all')
).annotate(
avg_teacher_rating = Avg('teacherrating_set__all')
).order_by(
'min_session_date_from',
'-avg_teacher_rating'
).filter(
min_session_date_from__gte=datetime.now() - datetime.timedelta(days=240)
avg_teacher_rating__lte=4
)
The Q is used to allow you to make logical AND and logical OR in the queries.
I recommend you take a look at complex lookups: https://docs.djangoproject.com/en/1.5/topics/db/queries/#complex-lookups-with-q-objects
The following query might not work in your case (what does the teacher model look like?), but I hope it serves as an indication of how to use the complex lookup.
from django.db.models import Q
Course.objects.filter(Q(session__date__range=(start,end)) &
Q(teacher__rating__gt=3))
Unless absolutely necessary I'd indeed steer away from denormalization.
Your sort question wasn't entirely clear to me. Would you like to display Courses, filtered by date_from, and sort it by Date, Name?