Django - how to get data from relationships? - python

I try to get data over a many-to-many and a one-to-many relationship.
view.py
class PublisherDetailView(generic.DetailView):
model = Publisher
template_name = 'store/publisher_detail_view.html'
models.py
class Publisher(models.Model):
name = models.CharField(null=False, max_length=30)
image = models.ImageField(upload_to='publisher_images/')
class Book(models.Model):
title = models.CharField(null=False, max_length=30)
description = models.CharField(max_length=1000)
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
class reader(models.Model):
name = models.CharField(max_length=40)
book = models.ManyToManyField(Book)
publisher_detail_view.html
{% for reader in publisher.book_set.readers.all %}
<p>{{ reader.name }} </p>
{% endfor %}
I just want to get all readers from a specfic publisher. What is the right code in the template? publisher.book_set.readers.all makes sense to me (early beginner), but doesn't work

book_set.readers doesn't work because book_set is a manager that manages a list of books. To get the readers, you have to iterate through the books:
{% for book in publisher.book_set.all %}
{% for reader in book.reader_set.all %}
<p>{{ reader.name }} </p>
{% endfor %}
{% endfor %}

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 %}

Include Object and Object's Foreign Keys in One Query Django

I have the following models:
class Document(models.Model):
name = models.CharField(max_length=30, null=True, blank=True)
reference = models.CharField(max_length=30, null=True, blank=True)
def __str__(self):
return self.Name
class Subdocument(models.Model)
document = models.ForeignKey(Document, null=True, default=None)
pdf = models.FileField(upload_to='media')
Ultimately I want to show both the name from Document and the pdf from Subdocument in the same <li> in my template within a for loop. So it could be something like:
{% for item in something %}
<li class="list-group-item">
{{ item.Name }} {{ item.pdf }}
</li>
{% endfor %}
My issue is because they are in separate models, I'm not sure how to get fields from both. So what query, or queries could I run in my view in order to make this possible? Any other approach is welcome, this is just to illustrate my end goal.
Thank you!
EDIT:
views.py
def doc_view(request):
something = Subdocument.objects.filter(document__isnull=False)
return render(request, 'my_template.html', context={'something': something})
Have you tried something like this,
# views.py
def my_view(request):
docs = Subdocument.objects.filter(document__isnull=False) # filtering out empty documents
return render(request, 'my_template.html', context={'docs': docs})
# my_template.html
{% for doc in docs %}
<li class="list-group-item">
{{ doc.document.name }} {{ doc.pdf.url }}
</li>
{% endfor %}
Try this
models.py
replace
name = models.CharField(max_length=30, null=True, blank=True)
to
name = models.CharField(max_length=30, null=True, blank=False)
template
{% for item in something %}
<li class="list-group-item">
{{ item.document.name }} {{ item.pdf }}
</li>
{% endfor %}

How to create a form field for every foreignkey in manytomany relationship in Django

I don't understand how to build a specific form in Django.
First of all here are my models:
class Category(models.Model):
name = models.CharField(max_length=200, unique=True)
class Assessment(models.Model):
name = models.CharField(max_length=200)
pub_date = models.DateTimeField(verbose_name=_('date published'), default=timezone.now)
classgroup = models.ForeignKey(ClassGroup, verbose_name=_('class'), on_delete=models.CASCADE, related_name='+')
category = models.ManyToManyField(Category, through='AssessmentScale', through_fields=('assessment', 'category'),)
total = models.IntegerField()
class AssessmentScale(models.Model):
assessment = models.ForeignKey(Assessment, on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
value = models.IntegerField()
I would like to have a form like this html form. Actually, an assessment scale is sub-divided into different categories. So when I create an assessment, I'd like have a form field for each category allowing to add a value via my custom intermediary model AssessmentScale. But I really don't know the Django way to build this form. I read this post, which is similar I think, and someone advised the use of Inline model formsets. But I don't understand how to solve my problem with the latter. Could you help me?
I had no answer from Stackoverflow but a friend of mine solved my problem like this with inline formset:
# forms.py
class AssessmentForm(ModelForm):
class Meta:
model = Assessment
exclude = ('category',)
CategoryAssessmentFormSet = inlineformset_factory(
Assessment,
Assessment.category.through,
fields=['category', 'value'],
can_delete=False,
extra=Category.objects.count(),
max_num=Category.objects.count(),
widgets={'category': Select(attrs={'hidden': 'true'})}
)
in my view, to render the formset:
# views.py
initial = [{'category': category} for category in Category.objects.all()]
formset = CategoryAssessmentFormSet(initial=initial)
Select is hidden but I still want the name of the selected field, in my template:
# template
{{ formset.management_form }}
{% for form in formset %}
<div class="p-2">
{% for value,selected in form.fields.category.choices %}
{% if value == form.category.value %}{{ selected }}{% endif %}
{% endfor %}
{{ form.category }}
</div>
<div>
{{ form.value}}
</div>
{% endfor %}

Check if a record from one model exists in a list with records from another model in Django

I have two simple models defined in Django... one contains album names, and another one that links albums and users.
class Album(models.Model):
name = models.CharField(max_length=255)
class UserAlbum
category = models.ForeignKey(Album, on_delete=models.CASCADE)
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
In my view I get the list of all albums, and I check which albums the user owns:
albums = Album.objects.order_by('name')
my_albums = UserAlbum.objects.filter(user_id=request.user.id)
This all works well. However, I now need to display the list with albums online, and a little icon should appear if a user owns an album. I'm not sure how to do this. This is what I have:
<ul>
{% for info in albums %}
<li>{{ info.name %} {% if SOME_CONDITION %} <span class="owner"></span>{% endif %}</li>
{% endif %}
I am not sure how to formulate SOME_CONDITION. It should basically say: if this album id is also in the my_albums list. But how can I do this?
You don't really need the UserAlbum model, unless you want to attach extra fields to the m2m relation. Instead just use a ManyToManyField.
from django.contrib.auth import get_user_model
User = get_user_model()
class Album(models.Model):
name = models.CharField(max_length=255)
users = models.ManyToManyField(User)
Then you can test for membership in Album().users.all() in your template.
{% for album in albums %}
<li>{{ album.name }}
{% if request.user in album.users.all %}
<span class="owner"></span>
{% endif %}
</li>
{% endfor %}
If you have some plan with the UserAlbum model, you can use it as a intermediate model.
class Album(models.Model):
name = models.CharField(max_length=255)
users = models.ManyToManyField(User, through='UserAlbum')

Django Model Manager not cooperating

I have the following models setup:
class Link(models.Model):
votes = LinkVoteManager()
class Vote(models.Model):
voter = models.ForeignKey(User)
link = models.ForeignKey(Link)
However; I can't get link.votes to display anything, it's just empty. Any ideas? I'm completely stuck.
Thanks!
you dont need custom Manager here for this purpose:
just do
class Link(models.Model):
titlename = models.CharField(max_length=100)
class Vote(models.Model):
voter = models.ForeignKey(User)
link = models.ForeignKey(Link, related_name="link_votes")
then to get the votes for a link do this:
{% for link in link_list %}
{{link.titlename}}'s voters:
{# here, we are showing all voters for a given link: #}
{% for vote in link.link_votes.all %}
voter's name: {{ vote.voter.username }}
{% endfor %}
{% endfor %}

Categories

Resources