Accessing fields in a Queryset from a ManytoManyFIeld - python

Pretty new to Django and models and I am trying to make a wishlist where people can add to the wishlist an then view what is in their wishlist by clicking on the link to wishlist. I created a separate model for the wishlist that has a foreignfield of the user and then a many to many field for the items they want to add to the wish list. For right now i am trying to view the wishlist that i created for the user using the admin view in Django.
The problem that i am having is that when I try to print their wishlist to the template the below comes up on the page.
<QuerySet [<listings: item: Nimbus, description:this is the nimbus something at a price of 300 and url optional(https://www.google.com/ with a category of )>, <listings: item: broom, description:this is a broom stick at a price of 223 and url optional(www.youtube.com with a category of broom)>, <listings: item: wand, description:this is a wand at a price of 3020 and url optional(www.twitter.com with a category of sales)>]>
What i ideally want is the query set to be split such that the two listings and their information would be on seperate lines on the the html page when i iterate through then the items based on the user. I know it must be from the string representation that i have set up on the model itself but don't know how to manage to accomplish this. I trie .all,.values,.values_list,.prefetch_related, and i still get the same outcome when i go to page and or not iterable
if anything what would be nice is to have access to the the item,description, and price and print that onto the page for every item in the wishlist.
is this possible to do or is my approach wrong and should the wishlist be added to one of the other forms but i think this should work somehow. Don't know if i am close or there is something i am missing in one of my files or need to create a new separate view.
code below:
models.py
class User(AbstractUser):
pass
class listings(models.Model):
item = models.CharField(max_length=100)
description = models.CharField(max_length=100)
price = models.IntegerField()
url = models.CharField(max_length=100,blank=True)
category = models.CharField(max_length=100,blank=True)
def __str__(self):
return f"item: {self.item}, description:{self.description} at a price of {self.price} and url optional({self.url} with a category of {self.category})"
class bids(models.Model):
desired = models.ForeignKey(listings,on_delete=models.CASCADE,related_name="desired",null=True)
bid = models.IntegerField()
def __str__(self):
return f"{self.desired} Bid: {self.bid}"
class comments(models.Model):
information = models.ForeignKey(listings,on_delete=models.CASCADE, related_name ="Review",null=True)
title = models.CharField(max_length=100)
comment = models.CharField(max_length=100)
def __str__(self):
return f"title {self.title} Comment: {self.comment}"
class wl(models.Model):
user = models.ForeignKey(User ,on_delete=models.CASCADE, related_name="users")
product = models.ManyToManyField(listings, related_name="item_wished")
def __str__(self):
return f"{self.product.all()}"
views.py
def watch_list(request):
user = wl.objects.filter(user_id = request.user.id).prefetch_related('product')
return render(request, 'auctions/wishlist.html',{
'wishes': user
})
html template
{% extends "auctions/layout.html" %}
{% block body %}
<h2>Active Listings</h2>
{% for i in wishes.all %}
<li> {{ i }} <li>
{% endfor %}
{% endblock %}

Your code seems fine. Try tweaking your template a bit with structure, maybe an HTML table:
{% extends "auctions/layout.html" %}
{% block body %}
<h2>Active Listings</h2>
<table>
{% for w in wishes %}
<tr>
<td>{{ w.pk }}</td>
<td>{{ w.product.item }}</td>
<td>{{ w.product.description }}</td>
<td>{{ w.product.price }}</td>
</tr>
{% endfor %}
</table>
{% endblock %}

The query would return all wl objects. With:
{% for w in wishes %}
You iterate over all wl objects. Each "w" has "product" field which is a Many to many relation - it contains multiple objects and needs to be iterated again:
{% for each_wl in wishes %}
{% for each_product in each_wl %}
{{ each_product.item }}
Also, name your variables/Classes to something more verbose.

Related

Django object.filter returns Object (1) on search bar

So I have a Django website Project that contains a database of all the different books stored in it. With my search bar, if I type in the name it will show results from the database. The problem is that whenever I type in said name (One Piece or Attack On Titan), instead of showing its title name, it will either show Book Object (1) or Book Object (2) depending on what name I type and I don't know why.
This is where I defined my classes:
class Book(models.Model):
title = models.CharField(max_length=255)
author = models.CharField(max_length=255)
editor = models.CharField(max_length=255)
year_published = models.IntegerField()
number_in_stock = models.IntegerField()
daily_rate = models.FloatField(null=True)
genre = models.ForeignKey(Genre, on_delete=models.CASCADE)
date_created = models.DateTimeField(default=timezone.now)
manga_image = models.ImageField(null=True, blank=True, upload_to='images/')
And this is where I defined my requests:
def search_manga(request):
if request.method == "POST":
searched = request.POST[('searched')]
mangas = Book.objects.filter(title__contains=searched)
return render(request, 'books/search_manga.html', {'searched': searched, 'mangas': mangas})
else:
return render(request,'books/search_manga.html', {})
Also this is the HTML document I'm trying to show the results on:
{% extends 'base.html' %}
{% block content %}
<style>
h1 {
text-align: center;
}
</style>
{% if searched %}
<h1>You Searched For {{searched}}</h1>
<br/>
{% for manga in mangas %}
{{ manga }}<br/>
{% endfor %}
{% else %}
<h1>Hey! You Forgot To Search For A Manga</h1>
{% endif %}
{% endblock %}
Please note I'm very new to Django by the way.
Your render() method is returning a QuerySet of Books (mangas) to the template. You need to iterate over this set of books, and render the attributes you care about in your template like so:
{% for x in mangas %}
name is {{ x.title }}
{% endfor %}

Django: How to query based on a ForiegnKey and display related data for each ForeignKey?

I am brand new to Django and to programming and I'm trying to make a page that will display the Workout with all the associated Exercises listed under each work out.
For example:
Chest
Chest Press
Incline Press
Flat Flyes
Shoulders
Shoudler Press
Arnold Press
Back/Legs
Wide Grip Pull Up
Neutral Grip Pull Up
Bent Over Row
Here is my code:
models.py
class Workout(models.Model):
title = models.CharField(max_length=100)
def __str__(self):
return self.title
class Exercise(models.Model):
workout = models.ForeignKey(Workout, on_delete=models.CASCADE, related_name='workouts')
title = models.CharField(max_length=100)
weight = models.DecimalField(decimal_places=0, max_digits=10000)
date_posted = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.title
views.py
def home(request):
context = {
'workouts': Workout.objects.all()
}
return render(request, 'workouts/home.html', context)
def workout(request):
context = {
'workouts': Workout.objects.all(),
'exercises': Exercise.objects.all()
}
return render(request, 'workouts/workout.html', context)
workout.html
{% extends 'workouts/base.html' %}
{% block content %}
{% for workout in workouts %}
<h1>{{ workout.title }}</h1>
{% for exercise in exercises %}
<h3>{{ exercise.title }}</h3>
<p>{{ exercise.weight }}</p>
{% endfor %}
{% endfor %}
{% endblock content %}
In my view.py I have it set to Exercise.objects.all() which just displays all of the exercises under each Workout title, I can figure out how to get only the exercises that are associated with the Workout.
Like I said I am brand new to all of this and I'd appreciate any help! Thanks!
You can define property to Workout model to retrieve exercises related to the instance. Just add a new method with property decorator to retrieve Exercises related with that Workout.
class Workout(models.Model):
title = models.CharField(max_length=100)
def __str__(self):
return self.title
#property
def exercises(self):
return self.workouts.all()
Then you can use exercises in your html file like:
{% extends 'workouts/base.html' %}
{% block content %}
{% for workout in workouts %}
<h1>{{ workout.title }}</h1>
{% for exercise in workout.exercises %}
<h3>{{ exercise.title }}</h3>
<p>{{ exercise.weight }}</p>
{% endfor %}
{% endfor %}
{% endblock content %}
Another approach may be grouping Exercises with workouts in your view and pass them to template. For more information, you can check regroup
When you define FK relationship between two models, Django adds a manager to target model to query related objects. When you use this manager, you basicly run a query something like Exercise.objects.filter(workout_id=workout_instance_id). This is a queryset, so you can join with features of queryset features like filter, first and extra. You can use a plenty of queryset features on related objects. This is basicly the power of Django ORM mechanism. You can find a bit more in documentation if you need to.

Apply a filter to a child that is within its parents loop

This is driving me mad (I really have looked everywhere - but I know it must be easy and I'm just being a tad think)
How do I add a filter to a child of a parent (one to many)? The code below provides a list of companies in a table, then on the same page/ table, each company has a list of "charges" which is attributed to that company; thanks to the ForeignKey and using "charge_set" it works great. However, I would like to add a filter to the "charges" for status (so exclude "outstanding" status)
In ROR I would have simply placed the following
<% company.charges.where(status: "Outstanding").each do |charge| %>
AIUI, I can't do this with Python/ Django in the view; so how would I go about adding a simple filter to the child of the parent within this loop?
from django.db import models
class Company(models.Model):
name = models.CharField(max_length=100)
class Charge(models.Model):
company = models.ForeignKey(Company, on_delete=models.CASCADE)
charge_id = models.CharField(max_length=100)
status = models.CharField(max_length=100)
from django.shortcuts import render
from companies.models import Company, Charge, Filing
from django.http import HttpResponse
def watch_list(request):
companies = Company.objects.order_by('-data_date')
return render(request,'company_watch/watch_list.html',{'companies':companies})
{% for company in companies %}
<tr>
<td>{{company.name}}</td>
<td>
<ul>
{% for charge in company.charge_set.all %}
<li>{{charge.charge_id}}</li>
{% endfor %}
</ul>
</td>
</tr>
{% endfor %}
You can just grab the company and filter the children. If you want to the children on the backend:
company = Company.objects.get('...')
outstanding_children = Charge.objects.filter(company = company, status = "Outstanding")
If you want to display the children on the frontend:
{% for company in companies %}
<tr>
<td>{{company.name}}</td>
<td>
<ul>
{% for charge in company.charge_set.all %}
{% if charge.status == "Outstanding" %}
<li>{{charge.charge_id}}</li>
{% endif %}
{% endfor %}
</ul>
</td>
</tr>
{% endfor %}

Backward relationship in Django templates

I am trying to display data from different models in my template and I have no idea why it doesn't work properly.
Models.py:
class Company(models.Model):
name = models.CharField(max_length=100)
class Location(models.Model):
company = models.ForeignKey('Company',
related_name='locations')
Views.py:
def sth(request):
loc_list = Location.objects.all()
return render(request, 'blabla/index.html', {'loc_list': loc_list})
Template:
{% for loc in loc_list %}
{% for entry in loc.company_set.all %}
{{entry.name}}
{% endfor %}
{% endfor %}
Why the name of the company is not showing?
You foreign key relationship is the wrong way around... the way you have currently defined them, a Location can have only one Company associated with it, but in your template you are trying to fetch a list of Companys.
For your template logic to work, your models would have to be defined as follows:
class Company(models.Model):
name = models.CharField(max_length=100)
location = models.ForeignKey('Location')
class Location(models.Model):
# You probably need some other fields in here.
Then this would work:
{% for loc in loc_list %}
{% for entry in loc.company_set.all %}
{{entry.name}}
{% endfor %}
{% endfor %}
Only use "_set" when accessing backwards relationships. There is no
loc.company_set.all
because each location only has one company (that is what a ForeignKey is. You can access the location's company by doing loc.company). If you want location to have multiple companies, either see solarissmoke's answer (where you put the ForeignKey attribute on Company and not on Location), or use a ManyToManyField relationship (this will allow companies to have multiple locations and each location to have multiple companies).
Then you can access all the companies of a given location by doing this in the template:
{% for loc in loc_list %}
{% for entry in loc.company.all %}
{{entry.name}}
{% endfor %}
{% endfor %}
You can also access all the locations for a given company by using the related_name (company.locations).
Short answer:
{% for loc in loc_list %}
{{loc.company.name}}
{% endfor %}

Foreign Key - how to solve this in template - django

i have 3 models:
Book, Topiccenter and EntryBook.
these are model definitions:
class Book(models.Model):
title = models.TextField()
language = models.TextField()
class Topiccenter(models.Model):
title = models.TextField():
description = models.TextField()
class EntryBook(models.Model):
book = models.ForeignKey(Book,related_name="b_entries")
topiccenter = models.ForeignKey(Topiccenter,related_name="tc_books")
Now I am in Topiccenter T. and i search for books and get all books in DB. As you see, each book can be in multiple topiccenters.
What i want to do is, in the search result, i want to show whether each book is contained in current Topiccenter or not:
I will take all books books = Book.objects.all() and the current topiccenter as tc and render them to template and in template,
{% for book in books %}
{% for entry in book.b_entries.all %}
{% if entry.topiccenter.id == tc.id %}
already in this Topiccenter
{% else %}
add to this topiccenter
{% endif %}
{% endfor %}
{% endfor %}
but the problem is that one book is in two topiccenters and in template i am getting both already in this Topiccenter and add to this topiccenter which is nonesense. How can i repair my logic so that I can check if the book in this current topiccenter, and if not, show them add button
thanks
See how you can move it to the view. In this case, get all books associated with the tc and send that in the context.
Now, the template logic would be:
{% for book in books %}
{% if book in tc_books %}
already in this Topiccenter
{% else %}
add to this topiccenter
{% endif %}
{% endfor %}
Where (in the view)
tc_books = Books.objects.filter(b_entries__topiccenter = tc)
and send that in the context

Categories

Resources