Django getting information from three related tables. Joining tables - python

I have three tables that are related.
class Book(models.Model):
year_published = models.IntField()
author = models.ForeignKey(Author)
class Author(models.Model):
author_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=50)
agent = models.ForeignKey(LitAgent)
class LitAgent(models.Model):
agent_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=50)
Ok, I can get a LitAgent like so
getla = LitAgent.objects.get(agent_id=1)
I can get the authors like so
getauthors = Author.objects.filter(agent=getla.agent_id)
But how can I get all the books that an author has too and make sure the books line up to the right author? I also need access to the data in LitAgent and Author too

From my understanding, you want to get the books by using an agent_id. If this is what you want then you can accomplish this using
books = Book.objects.filter(author__agent__agent_id=1)
This will return a list of all books that the author related to the agent with id = 1. If you want to access the author for each book you can use
for book in books:
print book.author.name
# in order to print the author agent
print book.author.agent.name
On the other side you can reach the books from the LitAgent model.
Lets say
agent = LitAgent.objects.get(agent_id=1)
Then to get the authors it will be
authors = agent.author_set.all()
Now you can iterate
for author in authors:
for book in author.book_set.all()
print book

Related

Django - SubQuery e function F()

I have 2 models (author and book). I want to annotate in the author model the highest book price for every authors (in order to manipulate it later). I would like to make a query with an internal sub-query using the F() function but the problem is that the F() is refered to the book model but I would like to refer it to the author model. I'll show that with an example. The models are shown below:
class author:
authorID = models.AutoField(primary_key = True, auto_created = True, unique = True)
name = models.CharField(max_length=100)
surname = models.CharField(max_length=100)
class book:
ownerID = models.ForeignKey(author, on_delete = models.CASCADE, related_name='hook')
title = models.CharField(max_length=100)
price = models.IntegerField()
The query in question is as follows:
value = author.objects.annotate(maxPrice = (book.objects.filter(ownerID = F('authorID')).order_by('-price') [0]))
F('authorID') is refered to the book DB and so Django returns an error but I want to refer it to the author DB to achieve my goal. How can I do that? Thanks

Django chain multiple queries in view

I have three models:
Course
Assignment
Term
A course has a ManyToManyField which accesses Django's default User in a field called student, and a ForeignKey with term
An assignment has a ForeignKey with course
Here's the related models:
class Assignment(models.Model):
title = models.CharField(max_length=128, unique=True)
points = models.IntegerField(default=0, blank=True)
description = models.TextField(blank=True)
date_due = models.DateField(blank=True)
time_due = models.TimeField(blank=True)
course = models.ForeignKey(Course)
class Course(models.Model):
subject = models.CharField(max_length=3)
number = models.CharField(max_length=3)
section = models.CharField(max_length=3)
professor = models.ForeignKey("auth.User", limit_choices_to={'groups__name': "Faculty"}, related_name="faculty_profile")
term = models.ForeignKey(Term)
students = models.ManyToManyField("auth.User", limit_choices_to={'groups__name': "Student"}, related_name="student_profile")
When a user logs in to the page, I would like to show them something like this bootstrap collapse card where I can display each term and the corresponding classes with which the student is enrolled.
I am able to access all of the courses in which the student is enrolled, I'm just having difficulty with figuring out the query to select the terms. I've tried using 'select_related' with no luck although I may be using it incorrectly. So far I've got course_list = Course.objects.filter(students = request.user).select_related('term'). Is there a way to acquire all of the terms and their corresponding courses so that I can display them in the way I'd like? If not, should I be modeling my database in a different way?
https://docs.djangoproject.com/en/1.11/ref/models/querysets/#values
You could use values or values_list here to get the fields of the related model Term.
For example expanding on your current request:
To retrieve all the Terms' name and duration for the Courses in your queryset
Course.objects.filter(students = request.user).values('term__name', 'term__duration')
I am not sure what the fields are of your Term model, but you would replace name or duration with whichever you are trying to get at.
I think it helps you
terms = Terms.objects.filter(....) # terms
cources0 = terms[0].course_set.all() # courses for terms[0]
cources0 = terms[0].course_set.filter(students=request.user) # courses for terms[0] for user

Last object of foreign key in bulk - Django

I have two models:
class Author(models.Model):
name = models.CharField(max_length=30)
age = models.CharField(max_length=40)
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey(Author)
publication_date = models.DateField()
I need find last books of authors, who are 10 years old to list:
[(author1.name, book32.title), (author5.name, book75.title), ...]
I can do:
books = []
authors = Author.objects.filter(age=10)
books = [(a.name, a.book_set.last().title) for a in authors]
but it works too long.
How can i do that entirely by ORM and database?
You can use prefetch_related. It will not make a second query for the related items.
Author.objects.filter(age=10).prefetch_related('book_set')
On a side note, use an IntegerField instead for age (if you would be storing age in years only). It will be more efficient for such queries, and you would also be able to make queries to fetch all non-adult authors:
child_authors = Author.objects.filter(age__lt=18)
First, your age field should be an IntegerField:
age = models.IntegerField(max_length = 3)
and if you want the last, let's say, 3 books of each ten years author you can query like this:
ten_years_authors = Author.ojects.filter(age=10)
ten_years_authors_and_their_last_books = ten_year_authors.select_related('book_set')[:3]

Django ForeignKey getting results

I've tried following other questions but I'm still having some problems.
I have 2 models:
class Media(models.Model):
name = models.CharField(max_length=100)
media = models.CharField(max_length=10, choices=MEDIA_TYPE)
class Review(models.Model):
message = models.CharField(max_length=10)
submitter = models.ForeignKey(User)
media = models.ForeignKey(Media, related_name='rev_media')
I want to go do something like
blaw = Media.objects.all()
for a in blaw:
print (all the reviews to have to do with this one media object)
Since you have a related_name, you can use a.rev_media.all() to get the list of associated objects.
Now, you can do:
media_qs = Media.objects.all()
for media in media_qs:
reviews = media.rev_media.all() #basically, this is the queryset of all the associated reviews for this media object.
if reviews.exists():
print ", ".join([review.message for review in reviews])
rev_media, your related_name, should give you all the reviews that have it as a foreign key:
blaw = Media.objects.all()
for a in blaw:
print media.rev_media.all()

How to connect data between author and book table which has ManyToMany relation in Django

I am learning Django and have been complete Model's chapter by "The Django Book" but didn't get the way to insert value in ManyToMany and ForeignKey for below question:
In this below model, How do i insert detail of "Author" and "Publisher" for book name = "The book" with publication-date = "28/10/2013"
And after inserting value, how do i get back "Author" and "Publisher" for book name = "The book"
class Author(models.Model):
first_name = models.CharField(max_length = 20)
last_name = models.CharField(max_length = 20, blank = True)
email = models.EmailField(blank = True)
class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField()
class Book(models.Model):
title = models.CharField(max_length=100)
publisher = models.ForeignKey(Publisher)
authors = models.ManyToManyField(Author)
publication_date = models.DateField()
if book is already there in database.
just simply run like
book_obj = Book.objects.get(title="Test Title")
author1 = Author.objects.get(name="test author1")
author2 = Author.objects.get(name="test author2")
author3 = Author.objects.get(name="test author3")
book_obj.authors.add(author1, author2, author3)
Same you can add Publisher if book is already in database.
If you want to create new entry of book.
publisher = Publisher.objects.get(name='Test publisher')
author = Author.objects.get(name='Test author')
Book.objects.create(title='Title1', publication_date='28/10/2013', authors=author, publisher=publisher)
Let's say you want to add a Stephen King's book Pet Semetary. You need to have the publisher and author instances already before adding the book object. Then it's very simple:
publisher = Publisher.objects.get(name='Simon & Schuster')
author = Author.objects.get(name='Stephen King')
new_book = Book(title='Pet Semetary',
publication_date='28/10/2013',
authors=author,
publisher=publisher)
new_book.save()
Is this the solution you were looking for?
update on comment
If the book object exists you can just apply it like so:
# create Author and Publisher:
new_author = Author(first_name='Stephen', last_name='King')
new_author.save()
new_publisher = Publisher(...bla bla...)
new_publisher.save()
# link them to your already existing book instance
book_instance = Book.objects.get(title='Pet Semetary')
book_instance.author = new_author
book_instance.publisher = new_publisher
Of course, you should use less general names than new_author or book_instance but you get the idea

Categories