Template not showing context variable - django

I created an app called marketing app which customizes messages to be written on top of home page. My problem is that these messages are not showing when everything configured and I don't know why is that might be the template because {{ marketing_message.message }} is only not showing
This is the model:
class MarketingMessage(models.Model):
message = models.CharField(max_length=120)
active = models.BooleanField(default=False)
featured = models.BooleanField(default=False)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
updated = models.DateTimeField(auto_now_add=False, auto_now=True)
start_date = models.DateTimeField(
auto_now_add=False, auto_now=False, null=True, blank=True)
end = models.DateTimeField(
auto_now_add=False, auto_now=False, null=True, blank=True)
def __str__(self):
return str(self.message[:12])
This is the view:
from marketing.models import MarketingMessage
class HomeView(ListView):
model = Item
paginate_by = 10
template_name = "home.html"
def get_context_data(self, **kwargs):
context = super(HomeView, self).get_context_data(**kwargs)
context['marketing_message'] = MarketingMessage.objects.all()
return context
This is the template:
{% if marketing_message %}
<div id="top-alert"class="alert alert-light" style="padding-top:85px; margin-bottom:-24px;">
×
<div class="container" style="text-align:center">
<strong> Marketing Message ! : </strong> {{ marketing_message.message}}
</div>
</div>
{% endif %}

marketing_message is a QuerySet, not a model instance.
You probably only want the most recent "active" message.
context['marketing_message'] = MarketingMessage.objects.filter(active=True).latest('timestamp')
Or the most recently updated:
context['marketing_message'] = MarketingMessage.objects.filter(active=True).latest('updated')
However latest() will fail if there is no object, which is likely not what you want, but you can do this:
try:
context['marketing_message'] = MarketingMessage.objects.filter(active=True).latest('updated')
except MarketingMessage.DoesNotExist:
context['marketing_message'] = None
Looking at your data, though, it seems incorrect. You have a start and end dates, but also active. You can imply if something is active if it falls within the start and end dates.
Also, since you have this, it seems like you could have multiple messages at once, in which case you should drop the .latest() and iterate over the ones within the start and end dates.

Related

when I try to render tags I get Wallpaper.Wallpaper.None

views.py
def download(request, wallpaper_name):
try:
wallpaper = Wallpaper.objects.get(name=wallpaper_name)
similar_wallpapers = wallpaper.tags.similar_objects()[:2]
except Exception as exc:
wallpaper = None
similar_wallpapers = None
messages.error = (request, 'Sorry! data does not exist')
context = {'wallpaper': wallpaper, 'similar_wallpapers': similar_wallpapers}
return render(request, 'Wallpaper/download.html', context)
models.py
class Tags(models.Model):
tag = models.CharField(max_length=100)
def __str__(self):
return self.tag
class Wallpaper(models.Model):
name = models.CharField(max_length=100, null=True)
size = models.CharField(max_length=50, null=True)
pub_date = models.DateField('date published', null=True)
resolution = models.CharField(max_length=100, null=True)
category = models.ManyToManyField(Category)
tags = TaggableManager()
Device_Choices = [
('PC', 'pc'),
('mobile', 'mobile')
]
Devices = models.CharField(max_length=20,choices=Device_Choices, default= 'PC')
image = models.ImageField(upload_to='Wallpaper/Images/', default="")
def __str__(self):
return self.name
download.html
<div class="tag">
<h3>Tags</h3>
<ul>
<li>{{wallpaper.tags}}</li>
</ul>
</div>
I want all the tags of that particular wallpaper to be rendered
and if possible please tell me if there is any other way to handle tags, because using taggit its very difficult i am getting manny errors
Tags are a many-to-many relation so you need to use .all in your template to get them. However, this will just show you the queryset, so you need to loop through them to render their names:
<ul>
{% for tag in wallpaper.tags.all %}
<li>{{ tag.name }}</li>
{% endfor %}
</ul>

Django: How to get total cart item in ecommerce

I am trying to add the total item in the cart, but I keep getting
<property object at 0x000001CFFDED8228>:
could anybody help?
View.py
class checkout(ListView):
model = OrderItem
template_name = 'product/checkout.html'
def get_context_data(self, **kwargs):
context = super(checkout, self).get_context_data(**kwargs)
context['orderQty'] = Order.get_cart_items
return context
model.py
class Order(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.SET_NULL, blank=True, null=True)
date_ordered = models.DateTimeField(auto_now_add=True)
complete = models.BooleanField(default=False, null = True, blank=False)
transaction_id = models.CharField(max_length= 200, null=True)
def __str__(self):
return str(self.id)
#property
def get_cart_items(self):
orderitems = self.orderitem_set.all()
total = sum(item.quantity for item in orderitems)
return total
size_choices = (('small', 'S'),
('medium', 'M'),
('large', 'L'))
class OrderItem(models.Model):
product = models.ForeignKey(Product, on_delete=models.SET_NULL, blank=True, null=True)
order = models.ForeignKey(Order, on_delete=models.SET_NULL, blank=True, null=True)
date_added = models.DateTimeField(auto_now_add=True)
quantity = models.IntegerField(default=0, blank=True, null=True)
size = models.CharField(max_length= 200,choices= size_choices, default=0)
#property
def get_total(self):
total = self.product.price *self.quantity
return total
template.html:
<div class="row-1">
<div style="flex:2;"><strong>Total Items</strong>:<span style="float: right;">{{orderQty}}</span></div>
<hr>
<div style="flex:2;"><strong>SubTotal</strong>:<span style="float: right;">$387</span></div>
<hr>
<div style="flex:2; margin-top:10px"><strong>Shipping</strong><span style="float: right;">$54</span></div>
<hr>
</div>
<div>
<div style="flex:2; text-align:center"><h6>Total: $387</h6></div>
<input id="form-button" class="btn btn-success btn-block" type="submit" value="Pay">
</div
I believe these files contain the problem but from researching online I can't seem to pinpoint exactly what it is. The function based view of my website was working fine until I moved to class-based view my views.py file. Any assistance would be greatly appreciated.
I believe the problem is with this line of code:
def get_context_data(self, **kwargs):
context = super(checkout, self).get_context_data(**kwargs)
context['orderQty'] = Order.get_cart_items # <----
return context
You are just creating function object instead of calling it. Changing that line to this should solve the problem:
context['orderQty'] = Order.get_cart_items()
EDIT When you define #property, your function becomes no longer function object but property object. Since property is descriptor and is not callable, it will throw that error. For more information, check this documentation. So, I would suggest you to remove #property at function definition to resolve this issue.

Django display multiple uploaded files

I am trying to display multiple uploaded file URLs but I'm not sure how to do it. I am a form that the users can use to upload multiple files that are working perfectly but now I want to be able to display these files. For instance, a company can have more than one file.
class InternationalCompany(models.Model):
International_company_Name = models.CharField(max_length=50)
International_company_Id = models.CharField(max_length=50)
options = (
('Yes', 'Yes'),
('No', 'No'),
)
Does_it_have_a_Financial_Dealers_License = models.CharField(max_length=20, choices=options, null=True)
Register_Office = models.TextField(max_length=500, null=True)
Beneficial_owner = models.CharField(max_length=100, null=True)
Beneficial_owner_id = models.FileField(upload_to='passport/pdf/',null=True)
expire_date = models.DateField(null=True)
BO_Phone_number = models.IntegerField(null=True)
BO_Email_Address = models.EmailField(null=True)
BO_Residential_Address = models.TextField(max_length=200, null=True)
def __str__(self):
return self.International_company_Name
class SupportDocuments(models.Model):
Supporting_Documents = models.FileField(upload_to='support_doc/pdf/', null=True)
internationalcompany = models.ForeignKey(InternationalCompany, on_delete=models.CASCADE)
def __str__(self):
return self.Supporting_Documents.url
I try something like this but it only displayed one url of the file instead of the multiple urls for the files that are associate with that company.
{%for company in doc%}
<tr>
<td></td>
<td>{{company.internationalcompany.Beneficial_owner}}</td>
<td>{{company.Supporting_Documents.url}}</td>
</tr>
{%endfor%}
I have also try out this but it doesn't display anything.
{%for company in doc.Supporting_Documents.all%}
{{company.url}}
{%endfor%}
def supporting_doc(request, company_id):
doc = SupportDocuments.objects.filter(id=company_id)
return render(request, 'supporting_doc.html', locals())
First of all, it might be better to use context rather than locals() as discussed here
Second, the way you get the doc queryset is wrong. id=company_id The id of SupportingDocuments is different from company_id. What you really need to do is internationalcompany.id=company_id.
so views.py:
def supporting_doc(request, company_id):
documents = SupportDocuments.objects.filter(internationalcompany.id=company_id)
context = { "documents": documents}
return render(request, 'supporting_doc.html', context)
in template:
{% for doc in documents %}
{{ doc.internationalcompany.Beneficial_owner}}
{{ doc.Supporting_Documents }}
{% endfor %}
On a side note, it may be better to use all lowercases in fields. This way, it is easy to distinguish fields and models.

Detailview Object Relations

;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'
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

How can I increase page load speed?

I need to have multilingual site. For this purpose I wrote django module, which collects lots of info about countries, cities and their translations to almost all languages.
Below is the short version of models of this module:
class LanguagesGroups(models.Model):
class Meta:
verbose_name = 'Language Group'
class Languages(models.Model):
iso_code = models.CharField("ISO Code", max_length=14, db_index=True)
group = models.ForeignKey(LanguagesGroups, on_delete=models.CASCADE, verbose_name='Group of ISO',
related_name='group', db_index=True)
class Cities(models.Model):
population = models.IntegerField(null=True)
territory_km2 = models.IntegerField(null=True)
class CitiesTranslations(models.Model):
common_name = models.CharField(max_length=188, db_index=True)
city = models.ForeignKey(Cities, on_delete=models.CASCADE, verbose_name='Details of City')
lang_group = models.ForeignKey(LanguagesGroups, on_delete=models.CASCADE, verbose_name='Language of city',
null=True)
class Meta:
index_together = (['common_name', 'city'],
['city', 'lang_group'])
I want to show to users some data about places which user requested with translated versions of cities (depending on user settings):
class Profile(models.Model):
title = models.CharField(_('title'), max_length=120)
info = models.TextField(_('information'), max_length=1500, blank=True)
city = models.ForeignKey(Cities, verbose_name=_('city'), null=True, blank=True)
def get_city(self):
user_lang = get_language() # en
lang_group = Languages.objects.get(iso_code=user_lang).group # 1823
return CitiesTranslations.objects.get(city=self.city, lang_group=lang_group).common_name
template.html
{% for item in object_list %}
{{ item.title }}
{{ item.get_city }}
{{ item.info }}
{% endfor %}
When I add {{ item.get_city }}, in case of pagination and just 25 items per page, the page load speed goes down up to 18 times and amount of queries (according to django-debug-tool) goes up from 2 to 102. django-debug-tool tells me about 25 duplications.
How can I fix this slowness?
EDIT:
My view
class ProfileListView(ListView):
model = Profile
template_name = 'profiles/profiles_list.html'
context_object_name = 'places_list'
paginate_by = 25
First of all, if you want speed - you should try caching.
You can also optimize your query.
def get_city(self):
user_lang = get_language() # en
return CitiesTranslations.objects.get(
city=self.city_id, lang_group__group__iso_code=user_lang
).common_name
What you probably also want is to get all your stuff in batches, not with individual method calls. Assuming we have your object_list:
city_ids = [x.city_id for x in object_list]
city_translations = CitiesTranslations.objects.filter(
city__in=city_ids, lang_group__group__iso_code=user_lang
).values_list('city_id', 'common_name')
city_translations = dict(city_translations)
for obj in object_list:
obj.city_name = city_translations[obj.city_id]
You can put this code somewhere in your view. You will also have to change {{ item.get_city }} to {{ item.city_name }} in the templates.