Reputation: 1183
I'm getting the 'str' object has no attribute 'get_absolute_url'
error on my django project on my sitemap page. Any help is appreciated.
Here is my traceback:
Traceback:
File "C:\Users\crstu\AppData\Local\Programs\Python\Python36-32\lib\site-packages\django\core\handlers\exception.py" in inner
35. response = get_response(request)
File "C:\Users\crstu\AppData\Local\Programs\Python\Python36-32\lib\site-packages\django\core\handlers\base.py" in _get_response
128. response = self.process_exception_by_middleware(e, request)
File "C:\Users\crstu\AppData\Local\Programs\Python\Python36-32\lib\site-packages\django\core\handlers\base.py" in _get_response
126. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\crstu\AppData\Local\Programs\Python\Python36-32\lib\site-packages\django\contrib\sitemaps\views.py" in inner
16. response = func(request, *args, **kwargs)
File "C:\Users\crstu\AppData\Local\Programs\Python\Python36-32\lib\site-packages\django\contrib\sitemaps\views.py" in sitemap
71. protocol=req_protocol))
File "C:\Users\crstu\AppData\Local\Programs\Python\Python36-32\lib\site-packages\django\contrib\sitemaps\__init__.py" in get_urls
111. urls = self._urls(page, protocol, domain)
File "C:\Users\crstu\AppData\Local\Programs\Python\Python36-32\lib\site-packages\django\contrib\sitemaps\__init__.py" in _urls
120. loc = "%s://%s%s" % (protocol, domain, self.__get('location', item))
File "C:\Users\crstu\AppData\Local\Programs\Python\Python36-32\lib\site-packages\django\contrib\sitemaps\__init__.py" in __get
68. return attr(obj)
File "C:\Users\crstu\AppData\Local\Programs\Python\Python36-32\lib\site-packages\django\contrib\sitemaps\__init__.py" in location
75. return obj.get_absolute_url()
Exception Type: AttributeError at /sitemap.xml
Exception Value: 'str' object has no attribute 'get_absolute_url'
my sitemaps.py
file
from django.contrib import sitemaps
from django.contrib.sitemaps import Sitemap
from django.urls import reverse
from deals.models import Deal
from blog.models import Post
class StaticViewSitemap(sitemaps.Sitemap):
priority = 1.0
changefreq = 'daily'
def items(self):
return ['about', 'contact', 'disclosure', 'terms', 'privacy', 'deals:deals', 'blog:blog']
class BlogSitemap(Sitemap):
changfreq = "daily"
priority = 1.0
location ='/blog'
def items(self):
return Post.objects.filter(status='Published')
def lastmod(self, obj):
return obj.created
class DealSitemap(Sitemap):
changfreq = "daily"
priority = 1.0
def items(self):
return Deal.objects.all()
def lastmod(self, obj):
return obj.date_added
and my two relevant models (Deal and Post) where i created a get_absolute_url methods since it had been generating an error on the sitemap prior:
class Deal(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(max_length=140, unique=True)
description = RichTextUploadingField(default='')
retailer = models.ForeignKey(Retailer, on_delete=models.CASCADE)
image = VersatileImageField('deal image',
upload_to=deal_upload_path,
null=True,
blank=True)
link = models.URLField(max_length=2000, default='')
category = models.ForeignKey(Category, on_delete=models.CASCADE)
date_added = models.DateField(default=timezone.now)
date_expires = models.DateField(default=timezone.now)
price = models.CharField(max_length=140)
secondary_price = models.CharField(max_length=140, default='')
likes_total = models.IntegerField(default=1)
expired = models.BooleanField(default=False)
def __str__(self):
return "@{} ({})".format(self.title, self.retailer)
def _get_unique_slug(self):
slug = slugify(self.title)
unique_slug = slug
num = 1
while Deal.objects.filter(slug=unique_slug).exists():
unique_slug = '{}-{}'.format(slug, num)
num += 1
return unique_slug
def save(self, *args, **kwargs):
if not self.slug:
self.slug = self._get_unique_slug()
super().save()
def get_label(self):
if self.date_added > datetime.date.today() - datetime.timedelta(days=4):
return "<span class='"'notify-badge'"'>new</span>"
else:
return ''
def get_absolute_url(self):
return reverse('deals:deal_detail', kwargs={'slug': self.slug})
class Post(models.Model):
STATUS_CHOICES = (
('Published', 'Published'),
('Draft', 'Draft'),
)
title = models.CharField(max_length=100, unique=True)
body = RichTextUploadingField()
category = models.ForeignKey(BlogCategory, on_delete=models.CASCADE)
seo_title = models.CharField(max_length=60, blank=True, null=True)
seo_description = models.CharField(max_length=165, blank=True, null=True)
slug = models.SlugField(max_length=200, unique=True)
image = VersatileImageField('blog image',
upload_to='media/blog_images',
null=True,
blank=True)
created = models.DateTimeField(db_index=True, auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=10, default='Draft', choices=STATUS_CHOICES)
def get_absolute_url(self):
return reverse('blog:blog_post', kwargs={'slug': self.slug})
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super(Post, self).save(*args, **kwargs)
def __str__(self):
return self.title
and my urls.py file with relevant info
from django.contrib.sitemaps.views import sitemap
sitemaps = {
'static': StaticViewSitemap,
'blog': BlogSitemap,
'deals': DealSitemap
}
path('sitemap.xml', sitemap,
{'sitemaps': sitemaps},
name='django.contrib.sitemaps.views.sitemap'),
Upvotes: 1
Views: 1685
Reputation: 594
It's the location()
function who request for get_absolute_url()
method : here. If you are absolutly sur that your string is already an absolute path you can simply override it in your class by:
def location(self, item) :
return item
This will return your already setup absolut path.
Upvotes: 0
Reputation: 600059
You haven't followed the example properly for the StaticViewSitemap. As the docs say, the elements returned from items()
are passed to the location()
method; since the items would normally be model instances, the default implementation of this method is to call the get_absolute_url()
method of each instance. In your case you are passing URL names, so you need to redefine location()
appropriately - again as the example does.
def location(self, item):
return reverse(item)
Upvotes: 3