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 %}
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.
Models.py
class Experience(models.Model):
user = models.ForeignKey(User, null=True, on_delete = models.CASCADE)
company_name = models.CharField(max_length=100)
company_address = models.CharField(max_length=200)
post_held = models.CharField(max_length=30)
year_from = models.CharField(max_length=20)
year_to = models.CharField(max_length=20)
info = models.TextField()
def get_absolute_url(self):
return reverse('resume')
def __str__ (self):
return self.company_name
Views.py
def Resume(request):
experience = Experience.objects.filter(user = request.user)
return render(request, 'resume.html', {'experience': experience})
Template
<ul>
{% for an_experience in experience %}
<li ><h5>{{ an_experience }},</h5> {{ an_experience.company_address }} - {{ an_experience.post_held }}</li>
<small>{{ an_experience.year_from }} - {{ an_experience.year_to }}</small>
<div>
{{ an_experience.info }}
</div>
{% endfor %}
</ul>
if I use .all(), it is working perfectly but while trying to filter it using request.user nothing is displaying in the template file.
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 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!
Maybe I cannot see the forest because of all the trees, but I have a very strange issue.
views.py:
from django.shortcuts import render
from models import Question, QuestionAnswerAlloc, Section
def home(request):
sections = Section.objects.all()
for s in sections:
questions = Question.objects.filter(section=s)
for q in questions:
answersalloc = QuestionAnswerAlloc.objects.filter(question=q)
q.answers.append(answersalloc)
s.questions.append(questions)
return render(request, "questionaire/index.html", {'sections': sections})
models.py:
from django.db import models
from portal.models import Customer
class Section(models.Model):
title = models.CharField(max_length=150)
weight = models.FloatField()
maxscore = models.FloatField()
questions = []
def __unicode__(self):
return "%s" % (self.title)
class Question(models.Model):
title = models.TextField()
section = models.ForeignKey(Section)
weight = models.FloatField()
answers = []
def __unicode__(self):
return self.title
class Answer(models.Model):
title = models.CharField(max_length=150)
points = models.IntegerField(default=0, help_text="This has to be a value between 0 and 5")
is_weighted = models.BooleanField(default=True, help_text="If this answer does not apply (N/a) it is not weighted!")
def __unicode__(self):
return self.title
class QuestionAnswerAlloc(models.Model):
question = models.ForeignKey(Question)
answer = models.ForeignKey(Answer)
def __unicode__(self):
return "Possible Answer"
class Report(models.Model):
STATUS_STARTED = "started"
STATUS_FIN = "finished"
STATUS_INPROG = "inprogress"
STATUS_ABORT = "aborted"
date = models.DateField(auto_now_add=True, blank=True)
title = models.CharField(max_length=150)
started_time = models.DateTimeField()
end_time = models.DateTimeField()
status = models.CharField(max_length=150, default=STATUS_STARTED)
guid = models.CharField(max_length=150, unique=True)
def __unicode__(self):
return self.title
class ReportAnswer(models.Model):
title = models.CharField(max_length=150)
orignal_answer = models.ForeignKey(Answer)
question = models.ForeignKey(Question)
section = models.ForeignKey(Section)
report = models.ForeignKey(Report)
points = models.FloatField()
weight = models.FloatField()
is_weighted = models.BooleanField(default=True)
customer = models.ForeignKey(Customer, blank=True, null=True)
def __unicode__(self):
return self.title
And my template:
{% for s in sections %}
<div class="row">
<div class="col-sm-12">
<div class="FormStepInfo">
<p class="QuestionaireSectionTitle">{{s.title}}</p>
<p class="QuestionaireSectionDesc"></p>
</div>
</div>
</div>
{% for q in s.questions %}
<div class="row">
<hr/>
<div class="col-sm-2 quest-num">{{forloop.counter }}</div>
<div class="col-sm-10 quest-title">
<label>
{{q.title}}
</label>
<br/>
<div class="CheckboxQuestion">
{% for a in q.answers %}
<label for=""><input type="radio" name="Q3" value="{{a.points}}" id="q3a1">{{a.title}}</label>
{% endfor %}
</div>
</div>
</div>
{% endfor %}
{% endfor %}
Unfortunately, the question title is not shown, neither the answers.
If I print out to sys.stderr i can see that there are questions assigned to the section. Am I missing something? I have restarted my "webserver", as I am using "python manage.py runserver" about 10 times and deleted my cache.
You have a fairly large misunderstanding of class definitions in Python. Usually when you define an attribute at class level it is shared by all members of the class. Django fields do some special magic to ensure that the values are per-instance rather than per-class, but your questions and answers lists do not do that. So even if you could get your code to work, all the answers would be associated with all the questions.
Luckily there's no need to do any of this. Django provides you with reverse accessors that provide exactly what you need. So the view can be simplified to just:
def home(request):
sections = Section.objects.all()
return render(request, "questionaire/index.html", {'sections': sections})
and the view becomes:
{% for s in sections %}
...
{% for q in s.question_set.all %}
...
{% for a in q.questionansweralloc_set.all %}
...etc