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!
Related
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.
My objective is to iterate through the model DeathDay posts that can be created through the admin (which contain several names and surnames) and display the last three persons that have been registered in such a model in the homepage that correspond to today. At the moment, I'm using a ListView function and it allows me to paste every name and surname that have been registered today. However, I tried to use the slice method but in such a case it finds that the first three elements of the list have no been created today and it does not show any result on my template.
Template:
{% for post in object_list %}
{% if date == post.daytoday %}
<b>{{ post.daynome }} {{ post.daycognome }}</b> </br>
{% endif %}
{% endfor %}
Models.py:
class DeathDay(models.Model):
daynome = models.CharField(max_length=120, blank=True)
daycognome = models.CharField(max_length=120, blank=True)
daynascita = models.DateField(max_length=120, blank=True)
daymorte = models.DateField(null=True, blank=True)
daytoday = models.DateField(auto_now_add=True)
dayluogo = models.CharField(max_length=120, null=True, blank=True)
object_list = List.objects.last()
gives you the last object created
i have two models "product" and "brand"
product has brand field ManyToMany to link the products with the concerned brand
## models.py
class Product(models.Model):
title = models.CharField(max_length=120)
slug = models.SlugField(blank=True, unique=True)
description = models.TextField()
brand = models.ManyToManyField(Brand)
class Brand(models.Model):
title = models.CharField(max_length=250, unique=True)
slug = models.SlugField(max_length=250, unique=True)
description = models.TextField(blank=True)
## url.py
re_path(r'^brands/(?P<slug>[\w-]+)/$', BrandDetail.as_view(), name = 'branddetail'),
## views.py
class BrandDetail(DetailView):
queryset = Brand.objects.all()
template_name = "brands/brand.html"
## brands/brand.html
{{ object.title }} <br/>
{{ object.description }} <br/>
Now when am rendring brand.html it shows the brand title and description fine
My question is
if i want to render in the same page the list of products linked to specific brand "considering the brand slug already passed in the URL", how i can do that?
the class is DetailsView and it has only Brand details in the query set as shown!!
i need any solution not ne
You do not need a ListView for that, you can iterate over the product_set of the brand, like:
{{ object.title }} <br/>
{{ object.description }} <br/>
products:
{% for product in object.product_set.all %}
{{ product.title }} <br/>
{% endfor %}
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 %}
..whatdoyoucallitanyway..
I have this model:
class Kaart(models.Model):
name = models.CharField(max_length=200, name="Kaardi peakiri", help_text="Sisesta kaardi pealkiri (maksimum tähemärkide arv on 38)", blank=False, null=False)
url = models.CharField(max_length=200, blank=False, null=False, name="Asukoha URL", help_text="Täisasukoht (http://www.domeen.ee/kaart/)")
kirjeldus = models.TextField(max_length=500, name="Kommentaar", help_text="Informatsioon / viide tegijale (mitte kohustuslik)")
Then i have this form:
class KaartForm(ModelForm):
class Meta:
model = Kaart
And i have this code in my template:
{% for field in form %}
<p>
<label>{{ field.label }}</label>
<em>{{ field.help_text }}</em>
{{ field }}
</p>
{% endfor %}
The problem is that both field.label and field.name display name, url, kirjeldus instead of the names i have set for them - "Kaardi pealkiri" etc. How do i get to use those instead?
You need to use verbose_name instead of name in your model.
name = models.CharField(max_length=200, verbose_name="Kaardi peakiri", help_text="Sisesta kaardi pealkiri (maksimum tähemärkide arv on 38)", blank=False, null=False)
See the docs. There is no option called name.
According to the documentation, the ModelForm's widget pulls its label value from the verbose_name attribute.