问题
;TLDR - After some solutions discovered, my final question is how can I, if at all, access models related to models related to the main detailview model?
I'm trying to use a generic detailview to return an object and it's related object. In this example, a company like mcdonalds would have any sites (or locations). What I want the detailview to be able to show is the company detail, and the site detail related to the company. I'm stuck though. Dispite my efforts in not asking for help, I have not been able to pull the data from the model referencing the company sites. Where am I going wrong? I have sort of proven this to work in the django shell with SiteModel.objects.filter(company=5)
showing all of the company with an ID of 5's site names.
models.py
'''
The company model consists of the base company information
'''
class CompanyModel(models.Model):
name = models.CharField(_('Company Name'), max_length=255, blank=False)
website = models.URLField(_('Company Website'), blank=True)
since = models.DateField(auto_now_add=True)
rate = models.DecimalField(max_digits=5, decimal_places=2, blank=False)
def __str__(self):
return '%s' % (self.name)
class Meta:
ordering = ['name']
verbose_name = 'Company'
verbose_name_plural = 'Companies'
'''
The site model consists of sites of a company as
some companies have several sites that we will work from.
'''
class SiteModel(models.Model):
company = models.ForeignKey(CompanyModel, on_delete=models.PROTECT)
address = models.ForeignKey(AddressModel, on_delete=models.PROTECT)
phone = models.ForeignKey(PhoneModel, blank=True, null=True, on_delete=models.PROTECT)
distance = models.SmallIntegerField(blank=True)
def __str__(self):
return '%s - %s, %s' % (self.company, self.address.city, self.address.state)
class Meta:
ordering = ['company']
verbose_name = 'Company Site Information'
verbose_name_plural = 'Company Sites'
views.py
class CompanyDetailView(DetailView):
model = CompanyModel
template_name = 'customers/detail.html'
def get_context_data(self, **kwargs):
context = super(CompanyDetailView, self).get_context_data(**kwargs)
context['sites'] = SiteModel.objects.filter(id=self.kwargs['pk'])
return context
urls.py
url(r'^customer/(?P<pk>[0-9a-z-]+)/detail/$', CompanyDetailView.as_view(),
name='customer-detail'),
Update 1:
My template is showing the correct company, but only 1 site, and the site is not related to the company. Arg. It's showing both the company who's ID is 5, and the site who's ID is 5. How do I connect the dots correctly here?
template
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Customer Detail</title>
</head>
<body>
<div class="container">
{{ object.name }}
{% for site in sites %}
{{ site }}
{% endfor %}
</div>
</body>
</html>
Update 2:
I was able to sort this out by not supering get_context_data, and just itterating through the _set
suffix of the related model's name. Django Documentation Reference
template
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Customer Detail</title>
</head>
<body>
<div class="container">
{{ company.name }}
{% for site in company.sites.all %}
{{ site }}
{% endfor %}
</div>
</body>
</html>
The follow up to this, however, is how do I go more than one layer deep? Following up with the above models, I also have a "reports" model. But when I use the same method as above, it seems to break down after the first model. i.e. I can't just use company.sites.reports
.
models.py
class ServiceReportModel(models.Model):
report_number = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
site = models.ForeignKey(customers_models.SiteModel, on_delete=models.PROTECT, related_name='reports')
request_number = models.ForeignKey(ServiceRequestModel,
on_delete=models.PROTECT,
null=True,
blank=True,
related_name='s_report_number'
)
reported_by = models.ForeignKey(main_models.MyUser, related_name='reports')
reported_date = models.DateTimeField(auto_now_add=True)
updated_by = models.ForeignKey(main_models.MyUser, blank=True, null=True, related_name='+')
updated_date = models.DateTimeField(auto_now=True)
equipment = models.ForeignKey(customers_models.EquipmentModel, on_delete=models.PROTECT)
report_reason = models.CharField(max_length=255, null=True)
time_in = models.DateTimeField(blank=True, null=True)
time_out = models.DateTimeField(blank=True, null=True)
actions_taken = models.TextField(null=False, blank=False)
recommendations = models.TextField(null=True, blank=True)
def get_absolute_url(self):
return reverse('service-report', kwargs={'pk': self.pk})
def __str__(self):
return '%s - %s, %s' % (self.site.company, self.reported_date.strftime('%d %B %Y'), self.equipment.name)
class Meta:
ordering = ['reported_date']
verbose_name = 'Service Report'
verbose_name_plural = 'Service Reports'
回答1:
I was able to get a solution with some help. I went back to super'ing the get_context_data method, and following this documentation regarding spanning relationships using filters and double underscore notation.
class CompanyDetailView(DetailView):
model = CompanyModel
context_object_name = 'company'
template_name = 'customers/detail.html'
def get_context_data(self, **kwargs):
context = super(CompanyDetailView, self).get_context_data(**kwargs)
context['sites'] = SiteModel.objects.filter(company=self.get_object())
context['reports'] = ServiceReportModel.objects.filter(site__company=self.get_object())
return context
来源:https://stackoverflow.com/questions/47623088/detailview-object-relations