Django Foreign key query - python

I have the following modle
class PatientContact(models.Model):
uid = models.CharField(max_length=10)
name = models.CharField(max_length=100)
phone = PhoneNumberField()
class Patient(models.Model):
name = models.CharField(max_length=100)
date_of_birth = models.DateField()
contact = models.ForeignKey(PatientContact)
class Appointment(models.Model):
patient = models.ForeignKey(Patient)
time = models.DateTimeField()
I can get the list of patients registered under a user:
Patient.objects.filter(contact=uid)
How could I get the list of appointment for a user from the above model?
Used case:
The list of appointments scheduled by user (uid=1234)
Not sure how to perform a backward relationship to get list of appointments for a given uid.

If I understood you correctly, this isn't backward, it's just two levels deep:
Appointment.objects.filter(patient__contact__uid=1234)

Related

How to filter a table based on data from another table

there are three tables:
class Course(models.Model):
name = models.CharField(max_length=255)
description = models.CharField(max_length=255)
start_date = models.CharField(max_length=255)
end_date = models.CharField(max_length=255)
def get_count_student(self):
count = CourseParticipant.objects.filter(course=self.id)
return len(count)
def __str__(self):
return f'{self.name}'
class Student(models.Model):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
email = models.CharField(max_length=255)
def __str__(self):
return f'{self.first_name}'
class CourseParticipant(models.Model):
course = models.ForeignKey(Course, related_name='course', on_delete=models.CASCADE)
student = models.ForeignKey(Student, related_name='student', on_delete=models.CASCADE)
completed = models.BooleanField(default=False)
I want to get students who do not participate in specific courses, I fulfill the following request
potential = Student.objects.exclude(courseparticipants__course=pk)
where in pk I indicate the id of the course, in response I get:
django.core.exceptions.FieldError: Cannot resolve keyword 'courseparticipants' into field. Choices are: email, first_name, id, last_name, student
The related_name is the name that is used by the related model's reverse accessor and is also the default related query name. Hence when you write the following in CourseParticipant:
student = models.ForeignKey(Student, related_name='student', on_delete=models.CASCADE)
It means Student now will have a reverse accessor named student which can be used to access its related CourseParticipant instances. Looking at this you would realize that you have chosen an incorrect (at least semantically) value for the related_name. Hence with this related name your query should be:
potential = Student.objects.exclude(student__course=pk) # Very confusing, yes?
A better solution would be to change the related name to something more suitable:
student = models.ForeignKey(Student, related_name='course_participants', on_delete=models.CASCADE)
Now you can write your query as:
potential = Student.objects.exclude(course_participants__course=pk)
Since you did not specify related_name in CourseParticipant model it is set to courseparticipant_set by default, so your query should be:
potential = Student.objects.exclude(courseparticipant_set__course=pk)

django models.py - migrating from one model class to another

I am trying to break up an existing model class. The original class is not optimal so I want to move all customer relevant information from CustomerOrder into a new class Customer. What is the best way to do this in Django?
Old model class:
class CustomerOrder(models.Model):
# Customer information fields
first_name = models.CharField(max_length=200) # Customer first name
last_name = models.CharField(max_length=200) # Customer last name
email = models.EmailField() # Customer email address
address = models.CharField(max_length=255) # Address to deliver (e.g. 1532 Commonwealth St. Apt 302)
city = models.CharField(max_length=200) # City to deliver (e.g. Fullerton, CA 92014)
# Order information fields
note = models.TextField() # Any notes the customer may have about shipping
shipping_method = models.CharField(max_length=200) # Shipping in LA or OC
total_price = models.FloatField(default=0) # Total price of the order
delivery_date = models.DateField() # When to deliver the order. Order is "live" until the next
# day after delivery. So if delivery date is Jan 3, it's "live" until Jan 4.
order_date = models.DateField() # When the customer ordered
time_slot = models.CharField(max_length=200) # What time to deliver the product
is_cancelled = models.BooleanField(default=False) # If the order is cancelled or refunded, we mark it here.
created_at = models.DateTimeField(auto_now_add=True) # When the order entry was saved into database
updated_at = models.DateTimeField(auto_now=True) # When the order was last updated in database
def __str__(self):
return self.first_name + " " + self.last_name
New model class:
class Customer(models.Model):
first_name = models.CharField(max_length=200) # Customer first name
last_name = models.CharField(max_length=200) # Customer last name
email = models.EmailField() # Customer email address
address = models.CharField(max_length=255) # Address to deliver (e.g. 1532 Commonwealth St. Apt 302)
city = models.CharField(max_length=200) # City to deliver (e.g. Fullerton, CA 92014)
There are duplicates in the old model so i want to remove those as well.
It depends on your database type. read this
You should be careful to dont loose your data!
I think the question is more to do with the whole relational database schema.
I would have all customer related stuff in one table just like the new CustomerOrder (rename this to Customer) class you have, then create another class for Orders then link the two with a one to many relationship. For example one customer can place many orders. If you want to implement this one to many relationship, simply add the following to the order class:
class Order(models.Model):
# The relavant order fields which you require, i.e. order number etc.
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
Now when you create a new order instance, you can assign the customer.
p.s. to access in reverse i.e. from customer to order you basically do customer.order_set() method (Customer can place many orders).

How to join multiple models and get the result in pythonic way?

I have 4 models.
class User(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField()
class Subscription(models.Model):
user_id = models.ForeignKey(User)
title = models.CharField()
class Address(models.Model):
user_id = models.ForeignKey(User)
street = models.CharField()
class Wallet(models.Model):
user_id = models.ForeignKey(User)
balance = models.DecimalField(max_digits=6, decimal_places=2)
Here I want to get the subscription rows along with the respected user address and wallet balance. Is that possible to retrieve in a single query (ORM)?
I heard about select_related() and prefetch_related(). But not sure how to put all together in a single queryset.
How can I achieve this in pythonic way?
Have you tried to follow this snippet from documentation?
Having a User object instance you can do something like this to access subscriptions:
user.subscription_set.all()
It will require separate calls to different managers to collect all your data though.
First of all remove _id from FK fields. You'll still have subscription.user_id (int) and subscription.user which is User. Right now you have to write subscription.user_id_id for accessing id.
Do you understand that user can have multiple wallets and addresses with you db design?
It is not possible to do it in a single query with ORM. But it is possible to do it in 3 queries (doesn't matter how many records).
UPDATED:
class User(models.Model):
name = models.CharField()
class Subscription(models.Model):
user = models.ForeignKey(User, related_name='subscriptions')
title = models.CharField()
class Address(models.Model):
user = models.ForeignKey(User, related_name='addresses')
street = models.CharField()
class Wallet(models.Model):
user = models.ForeignKey(User, related_name='wallets')
balance = models.DecimalField(max_digits=6, decimal_places=2)
subscriptions = Subscription.objects.select_related('user').prefetch_related(
'user__wallets', 'user__addresses')
for s in subscriptions:
print(s.user.name)
for wallet in s.user.wallets.all():
print(wallet.balance)
for address in s.user.addresses.all():
print(address.street)

Models in Python Django not working for Many to Many relationships

I am trying to create the proper Django model that could fit the following reqs:
Person Class has 1 to many relations with the Address Class
Person Class has many to many relations with the Group Class
Book Class contains the collections of the Persons and the Groups
This is my code:
class Person(models.Model):
first_name = models.CharField(max_length=15)
last_name = models.CharField(max_length=20)
def __str__(self):
return self.first_name+ ' - ' + self.last_name
class Address(models.Model):
person = models.ForeignKey(Person)
address_line = models.CharField(max_length=200)
def __str__(self):
return self.address_line
class Group(models.Model):
group_name = models.CharField(max_length=12)
persons = models.ManyToManyField(Person)
def __str__(self):
return self.group_name
class Book(models.Model):
record_name = models.CharField(max_length=12)
person = models.ForeignKey(Person )
group = models.ForeignKey(Group )
def __str__(self):
return self.record_name
However it's not correct:
1) A Group can now contain multiple Persons but the Persons do not contain any Group.
I am not sure if I should add to the Person class the following code:
groups = models.ManyToManyField(Group)
2) The Book class now contains only 1 record of Person & Group per Book record.
3) When I added the Foreign Keys to the models, I removed
on_delete tag:
person = models.ForeignKey(Person, on_delete=models.CASCADE())
because it does not compile it, asking for some params.
I know how to make all this for C#, but I am a kinda stucked with this simple task in Python/Django.
1) The ManyToMany field should appear only in one of the models, and by looks of things you probably want it in the Person model.
Its important to understand that the data about the ManyToMany field is saved in a differant table. Django only allows this field to be visable through buth models (so basiclly, choose where it is move convinient).
2)By the look of your structure I will suggest you use a ManyToMany field through a different table. here is an example:
class Activity(models.Model):
name = models.CharField(max_length=140)
description = models.TextField(blank=True, null=True)
class Route(models.Model):
title = models.CharField(max_length=140)
description = models.TextField()
activities_meta = models.ManyToManyField(Activity, through = 'RouteOrdering')
class RouteOrdering(models.Model):
route = models.ForeignKey(Route, on_delete=models.CASCADE)
activity = models.ForeignKey(Activity, on_delete=models.CASCADE, related_name='activita')
day = models.IntegerField()
order = models.IntegerField(default=0)
that way the data is binded to the ManyToMany field

Django Models relations

Below is my Django models code
from django.db import models
class BookUser(models.Model):
email= models.CharField(max_length=254,primary_key=True) #mail address key
name = models.CharField(max_length=254) #max 64 char (lower case?)
contact= models.CharField(max_length=12)
imei = models.CharField(max_length=16) #imei number
address= models.TextField() #list of address ids
booksInShelf:[] #list of user book's unique ids
booksUnderCirculation:[] #list of user book's unique ids
class Meta:
ordering = ('email',)
class Book(models.Model):
isbn = models.CharField(max_length=13)
title=models.CharField(max_length=500)
description =models.TextField()
author = models.CharField(max_length=200)
userRating = models.CharField(max_length=1)
users = #list of user ids hold this book in shelf
class UserBook(models.Model):
#id: generated by django
bookId: #id of parent book
rent= models.BooleanField(default=False) #boolean is ready to rent
sell= models.BooleanField(default=False) #boolean is ready to sell
price =models.FloatField() #selling price
rentBase=models.FloatField() #base price of rent
rentPeriod=models.IntegerField() #days after which extra rent would apply
dateModified =models.DateTimeField(auto_now=True) #track date it came into shelf
dateAdded = models.DateTimeField(auto_now_add=True)
Here BookUser is the actual user who has some books in two categories i.e booksinShelf and bookUnderCirculation
class Book is central repository of all books, I need to define a one to many relation to BookUser.What is the easy way to do this?
User Book is specific to BookUser and it should be uniquely pointing to Class Book , So its many to one relation to Book Class.
I am confused on how to handle ids of UserBook and Book?
Also how to store the list of ids of UserBooks in class BookUser??
After looking at the Models and explanation provided below the Book model the users field should have ForeignKey relationship with the BookUser model.
so Book model should look like
class Book(models.Model):
isbn = models.CharField(max_length=13)
title=models.CharField(max_length=500)
description =models.TextField()
author = models.CharField(max_length=200)
userRating = models.CharField(max_length=1)
users = models.ForeignKey(BookUser, null=True, blank=True)
if you are using Postgresql and if you just need the pk list of booksInShelf and booksUnderCirculation then your BookUser model should look like
class BookUser(models.Model):
email= models.CharField(max_length=254,primary_key=True)
name = models.CharField(max_length=254)
contact= models.CharField(max_length=12)
imei = models.CharField(max_length=16)
address= models.TextField()
booksInShelf = models.ArrayField(models.IntegerField())
booksUnderCirculation = models.ArrayField(models.IntegerField())
and if you wish to have the full information of booksInShelf and booksUnderCirculation (not just the pk but other information related to the book as well), then you need to define it as ManyToMany relation.
class BookUser(models.Model):
email= models.CharField(max_length=254,primary_key=True)
name = models.CharField(max_length=254)
contact= models.CharField(max_length=12)
imei = models.CharField(max_length=16)
address= models.TextField()
booksInShelf = models.ManyToMany(UserBook)
booksUnderCirculation = models.ManyToMany(UserBook)
also rather than creating two ManyToMany fields in the BookUser model you can have two flags in your UserBook model called is_in_shelf and is_under_circulation. These fields would be BooleanField, you can check more about the model fields in Django Documentation here: https://docs.djangoproject.com/en/1.10/topics/db/models/#fields
This should do what you want :
class UserBook(models.Model):
bookId = models.ForeignKey('Book')
Here a UserBook has a reference to a Book item, and severals users can have the same book, but it's still a unique reference in you table Book.
Hope it helps

Categories