As the title says I have a detailed view that I'm presenting via Django templates. I have a foreign key that I'd also like to present within that detailed view and I just can't get it to work. I've tried everything, but all I get is the basic detailed view template with no foreign key info. Any help would be greatly appreciated.
Here's what I've got so far:
Models:
class Cust(models.Model): #this is the main model
id = models.UUIDField(
primary_key=True,
default=uuid.uuid4,
editable=False)
email = models.CharField(max_length=200)
firstName = models.CharField(max_length=200)
lastName = models.CharField(max_length=200)
watchmanSlug = models.CharField(max_length=200, unique=True)
class Watchman(models.Model):
group = models.ForeignKey(Cust, on_delete=models.CASCADE,to_field='watchmanSlug',
related_name='watchman_group_slug')
uid = models.CharField(max_length=500)
computer_name = models.CharField(max_length=500)
computer_url = models.CharField(max_length=500)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
Views
class CustomerDetailView(DetailView):
model = Cust
template_name = 'cust/cust_detail.html'
def get_context_data(self, ** kwargs):
context = super(CustomerDetailView, self).get_context_data( ** kwargs)
context['computer_name'] = Watchman.objects.all()
return context
Detail Template
<tbody>
<ul>
{% for p in watchman_group_slug.all %}
<li>{{ watchman.computer_name }}</li>
{% endfor %}
</ul>
</tbody>
You access the related Watchman objects with:
<tbody>
<ul>
{% for p in object.watchman_group_slug.all %}
<li>{{ p.computer_name }}</li>
{% endfor %}
</ul>
</tbody>
so with object.watchman_group_slug.all, and with the .computer_name of p.
Related
I'm having a problem with an html template not displaying model fields sent from a view in a context dictionary called content. This dictionary holds a nested dictionary like:
content = {'indredients': {recipe id1: QuerySet 1,
recipe id2: QuerySet 2, ... } }
In model.py:
class Ingredients(models.Model):
id = models.IntegerField(primary_key=True)
recipe = models.ForeignKey(Recipes, on_delete=models.CASCADE, related_name='ingredients')
ingredient = models.CharField(max_length=128)
class Meta:
managed = False
db_table = 'ingredients'
verbose_name_plural = 'Ingredients'
def __str__(self):
return f"{self.id} {self.recipe} - {self.ingredient}"
class Recipes(models.Model):
id = models.IntegerField(primary_key=True)
category = models.TextField(db_column='Category', null=False)
submitted_by = models.TextField(
db_column='Submitted_By', null=False)
origin = models.TextField(db_column='Origin', null=False)
title = models.TextField(db_column='Title', null=False)
directions = models.TextField(
db_column='Directions', null=False)
comments = models.TextField(db_column='Comments', null=False)
created = models.DateTimeField(null=False)
modified = models.DateTimeField(null=True)
def __str__(self):
return f"{self.id} - {self.title}"
class Meta:
managed = False
db_table = 'recipes'
verbose_name_plural = 'Recipes'
In views.py:
recipes = Recipes.objects.all().order_by(
"category", "title")
content['ingredients'] = {}
for recipe in recipes:
ingredients = Ingredients.objects.filter(
recipe=recipe.id).order_by("id")
content['ingredients'][recipe.id] = ingredients
content['recipes'] = recipes
return render(
request,
"myApp/recipes.html",
context=content)
In recipes.html:
{% for recipe in recipes %}
<div id="id-{{recipe.id}}" class="grid-item {{recipe.category}} {{recipe.submitted_by}}">
<div class="row">
<div class="col-12 col-md-3 ingredients">
{% for queryQbject in ingredients.recipe.id %}
{{ queryQbject.ingredient }}<br>
{% empty %}
<span>No ingredients provided</span>
{% endfor %}
</div>
</div>
{% endfor %}
I do get the correct data from the sqlite database and the Queryset is stored in the dictionary 'content' that is passed correctly into the html file. However, the html template doesn't display any of the data and only prints the 'No ingredients provided' {% empty %} case.
See debug info:
What do I need to do to fix this problem?
nigel239's answer got me thinking and researching some more. I found this post
https://fedingo.com/how-to-lookup-dictionary-value-with-key-in-django-template/
to write a custom filter to lookup a dictionary value with a key.
This is my custom_tags.py:
#register.filter
def get_item(dictionary, key):
try:
key = int(key)
value = dictionary.get(key)
except:
value = None
return value
and my updated recipes.html:
<div class="col-12 col-md-3 ingredients">
{% for queryset in ingredients|get_item:recipe.id %}
{{ queryset.ingredient }}<br>
{% empty %}
<span>No ingredients provided</span>
{% endfor %}
</div>
Now the code correctly pulls all the ingredients from the Django Queryset that was passed into the html template in a dictionary called 'ingredients' using the 'recipe.id' as keys.
You are trying to loop over the ID, which is an integer. Not an iterable.
Change
{% for queryQbject in ingredients.recipe.id %}
To
{% for queryQbject in ingredients.recipe %}
I'm working in Django 2.2 trying to build a view for a database that compiles everything for a specific company (locations of all of their stores and notes on the companies) into a single view. I've tried methods in several different answers, but still cannot seem to get data from related foreign keys to show in the template.
models.py
class Company(models.Model):
name = models.CharField(max_length=30, primary_key=True)
official_name = models.CharField(max_length=50)
corporate_address1 = models.CharField(max_length=50)
corporate_address2 = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.ForeignKey('Country', on_delete=models.CASCADE)
slug = models.SlugField(max_length=30, unique=True)
def __str__(self):
return self.name
class Stores(models.Model):
store_name = models.CharField(max_length=30, primary_key=True)
owner = models.ForeignKey('Company', on_delete=models.CASCADE)
store_address1 = models.CharField(max_length=50)
store_address2 = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.ForeignKey('Country', on_delete=models.CASCADE)
type = models.CharField(max_length=30,choices=store_types)
slug = models.SlugField(max_length=30, unique=True)
def get_absolute_url(self):
return reverse("store-detail", kwargs={"slug": self.slug})
class notes(models.Model):
title = models.CharField(max_length=120)
content = models.TextField()
posted = models.DateTimeField(db_index=True, auto_now_add=True)
category = models.ForeignKey('Company', on_delete=models.CASCADE)
active = models.BooleanField(default=True)
def get_absolute_url(self):
return reverse("article-detail", kwargs={"id": self.id})
class Country(models.Model):
country = models.CharField(max_length=30,choices=countries,primary_key=True)
class Meta:
ordering = ["-country"]
db_table = 'country'
def __str__(self):
return self.country
views.py
class CompanyOverView(LoginRequiredMixin, DetailView):
model = Company
template_name = "company-overview.html"
slug_url_kwarg = 'slug'
query_pk_and_slug = True
pk_url_kwarg = "company.name"
template
<div align="center">
<p>{{ object.name }}<br>({{ object.official_name }})</p>
<p>{{ object.corporate_address1 }}<br>{{ object.corporate_address2 }}<br>
{{ object.city }}<br>{{ object.state_province }}<br>
{{ object.country }}</p>
</div>
<p>List of Stores</p>
<p>
{% for instance in object_list %}
{{ instance.company.stores.store_name }}
{{ instance.company.stores.store_address1 }}
{{ instance.company.stores.store_address2 }}
{{ instance.company.stores.city }}
{{ instance.company.stores.state_province }}
{{ instance.company.stores.country }}
{% endfor %}
</p>
<p>Notes</p>
<p>
{% for instance in object_list %}
{{ instance.company.notes.title }}
{{ instance.company.notes.posted }}
{% endfor %}
</p>
With the above code, the only thing that appears when you enter in the company's name is everything at the top (e.g."object.name" appears on the page as "Acme Corporation"). Nothing in the for loop appears on the web page.
Looking at the documentation, object_list is the default name for context unless specified. I have tried different combinations such as "for store_name in company.store_set.all" and other combinations I found in other posts, but none have worked. I've combed the documentation for everything related to foreign keys, but can't find a solution that works.
Thanks in advance if you can help.
No. object_list is the default context name in a ListView. But you have a DetailView, and you already know what the default context name is for those because you're already using it: object. You just need to iterate over the reverse relation from there:
{% for store in object.stores_set.all %}
{{ store.store_name }}
{{ store.store_address1 }}
...
{% endfor %}
I'm trying to a menu system for my sport site project where the sports are grouped together. For example the main category would be "ballsports" and under that (the child menu) people would select football, baseball or whatever else. I've got that all setup and functioning but I can't workout how to call the child menus into the templates.
Models:
class Sport(models.Model):
name = models.CharField(max_length=100, db_index=True)
sport_slug = models.SlugField(max_length=100, db_index=True)
category = models.ForeignKey('Sport_Category', on_delete=models.CASCADE,)
class Sport_Category(models.Model):
name = models.CharField(max_length=100, db_index=True)
category_slug = models.SlugField(max_length=100, db_index=True)
Views:
class IndexView(generic.ListView):
template_name="sports/index.html"
context_object_name='all_sport_category'
def get_queryset(self):
return Sport_Category.objects.all()
def list_of_sports_in_category(self):
sport_cat = self.category.name
return sport_cat
class SportListView(generic.ListView):
template_name="sports/sport-home.html"
context_object_name='sport_list'
def get_queryset(self):
return Sport.objects.all()
Template:
{% for sport_category in all_sport_category %}
<li>{{ sport_category.name }} </li> *(Working)*
{% for sports in list_of_sports_in_category %}
hi
{% endfor %}
{% endfor %}
list_of_sports_in_category method seems to return the category name, rather than the list of sports. try replacing the second for-loop in your template with {% for sport in sport_list %}.
I have two models, Author & Book in models.py
class Author(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=40)
email = models.EmailField()
age = models.IntegerField()
def __str__(self):
return '%s %s' %(self.first_name, self.last_name)
def __unicode__(self):
return '%s %s' %(self.first_name, self.last_name)
class Book(models.Model):
title = models.CharField(max_length=100) #name = title
pages = models.IntegerField()
price = models.DecimalField(max_digits=10, decimal_places=2)
rating = models.FloatField()
author = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
def __str__(self):
return self.title
def __unicode__(self):
return self.title
Now i'm listing all the books using ListView. And on click of a book i'm getting information the book using following method
class BookDetailView(generic.DetailView):
template_name = 'books/book_detail1.html'
model = Book
context_object_name = 'book_detail'
I'm able to access title, pages, price, rating, publisher & publication_date but not getting all the Authors(Author list). While i'm going to simply print it, it prints None in template. I even try to iterate using For Loop but not done in template
views.py
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<ul>
<li>Price:{{ book_detail.price }}</li>
<li>Pub Date:{{ book_detail.publication_date }}</li>
<li>Title: {{ book_detail.title }}</li>
<li>Pages: {{ book_detail.pages }}</li>
<li>Rating: {{ book_detail.rating }}</li>
<li>Publisher: {{ book_detail.publisher }}</li>
<li>Author: {{ book_detail.author }}</li>
</ul>
</body>
</html>
Can anyone help me to out from this?
You have defined a many-to-many relationship between Book and Author which means that a book can have any number of authors. In order to display them you need to loop through the set of authors:
Authors:
<ul>
{% for author in book_detail.author.all %}
<li>{{ author }}</li>
{% endfor %}
</ul>
You might want to change the name of that field to authors to be less confusing.
Alternatively if you want only one author for a book then you need to use a ForeignKey instead of a ManyToManyField. In that case your existing template logic would work.
Or if you use Function-Based Views, define this view:
#views.py
def book_detail_view(request, id):
book = get_object_or_404(Book, id=id)
authors_of_book = book.questions.all()
template = 'books/book_detail1.html'
context = {'authors_of_book': authors_of_book}
return render(request, template, context)
And also in your template:
#html.py
<ul>
{% for author in authors_of_book %}
<li>{{ author }}</li>
{% endfor %}
</ul>
For more detail read this document.
I am having some trouble getting the values from a snippet, that I have included into a streamfield using a Snippet Chooser Block.
BioSnippet:
#register_snippet
class BioSnippet(models.Model):
name = models.CharField(max_length=200, null=True)
job_title = models.CharField(max_length=200, null=True, blank=True)
bio = RichTextField(blank=True)
image = models.ForeignKey(
'wagtailimages.Image',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='+',
verbose_name='Bio Image'
)
contact_email = models.CharField(max_length=50, null=True, blank=True)
contact_phone = models.CharField(max_length=50, null=True, blank=True)
panels = [
FieldPanel('name'),
FieldPanel('job_title'),
FieldPanel('bio'),
ImageChooserPanel('image'),
FieldPanel('contact_email'),
FieldPanel('contact_phone'),
]
def __str__(self):
return self.name
class Meta:
ordering = ['name',]
Bio Streamfield Definitions:
class BioInline(StructBlock):
bio = SnippetChooserBlock(BioSnippet)
class BioBlock(StructBlock):
overall_title = CharBlock(required=False)
bios = ListBlock(BioInline())
This all works, but when I get to the template, I cannot seem to access the values of the snippet
{% for b in child.value.bios %}
{{ b }}
<hr>
{{ b.name }}
{% endfor %}
the {{ b }} tag outputs:
bio
Sales Team
However {{ b.name }} outputs nothing. Neither does {{ b.values.name }} or any other permutation I can guess at. I suspect the values are just not being pulled down.
bios here is defined as a list of BioInline values, and so b in your template would be a BioInline value - which has a single property, bio (giving you the actual BioSnippet object). To get the name, you'd therefore have to use: {{ b.bio.name }}.
I don't think the BioInline object is actually gaining you anything though - you could instead define BioBlock as:
class BioBlock(StructBlock):
overall_title = CharBlock(required=False)
bios = ListBlock(SnippetChooserBlock(BioSnippet))
which would make bios a list of BioSnippets - {{ b.name }} would then work as expected.
Alternatively, you can use self.bios
In blocks.py you have to import the Snippet model (should have this allready):
from thebioapp.models import BioSnippet
And then use this model in the template itself
{% for b in self.bios %}
{{ b }}
<hr>
{{ b.name }}
{% endfor %}
The post is old, but as Wagtail is growing in popularity, I hope this will benefit others!