John Rogerson
John Rogerson

Reputation: 1183

Django Sitemap -- 'str' object has no attribute 'get_absolute_url' Error

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

Answers (2)

CallMarl
CallMarl

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

Daniel Roseman
Daniel Roseman

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

Related Questions