Django sitemap change base URL
Asked Answered
T

7

10

I'm using https://docs.djangoproject.com/en/dev/ref/contrib/sitemaps/?from=olddocs.

I have a sitemap generated from api.example.me for the domain: example.com.

Can I, with Django, specify a base URL?

Now with location() method return:

api.example.me/page/3123 instead of example.com/page/3123

Is this possible?

Tegular answered 30/4, 2012 at 22:0 Comment(4)
Do you have django.contrib.sites active? If you do, sitemaps will take active site from there.Canula
Yes ilvar, but I don't want that sitemaps take site from there. I would want to specify my personal base url. Now return: api.mydomain.me/page/3232 (api.mydomains.me it the active site), but, that i want, is: mydomain.com/page/3213 Understand?Tegular
Yes. You can monkey-patch sites to make it return some fake Site with domain which you need.Canula
ilvar: How? Any Hints? Examples?Tegular
T
17

Solved, I redefined my own get_urls. It works:

class MySitemap(Sitemap):
    changefreq = "never"
    priority = 0.5
    location = ""

    def get_urls(self, site=None, **kwargs):
        site = Site(domain='example.com', name='example.com')
        return super(MySitemap, self).get_urls(site=site, **kwargs)
 
    def items(self):
        return MyObj.objects.all().order_by('pk')[:1000]

    def lastmod(self, obj):
        return obj.timestamp
Tegular answered 6/5, 2012 at 16:24 Comment(2)
Works great. I don't know what version of Django you're using, but if you're using Django 1.5.1 this will works only if you add a "protocol" argument in the get_urls function. github.com/django/django/blob/1.5.1/django/contrib/sitemaps/…Lifelong
@deddamadre: I tried but facing issue "get_urls() got an unexpected keyword argument 'site'" Could you please help out for the same? Thanks in adv.Monochromatism
V
3

I didn't know how to use Site in my code by using previous answers so I used below code:

class Site:
    domain = 'example.com'

class MySitemap(Sitemap):
    def get_urls(self, site=None, **kwargs):
        site = Site()
        return super(MySitemap, self).get_urls(site=site, **kwargs)
Victuals answered 25/2, 2019 at 10:24 Comment(0)
L
1

And If you have multiples Sitemaps classes you can use a mixin approach.

An example for Django 1.5.1.

from django.contrib.sitemaps import Sitemap
from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse
from yourapp.models import MyObj

class SiteMapDomainMixin(Sitemap):

    def get_urls(self, page=1, site=None, protocol=None):
        # give a check in https://github.com/django/django/blob/1.5.1/django/contrib/sitemaps/__init__.py
        # There's also a "protocol" argument.
        fake_site = Site(domain='example.com', name='example.com')
        return super(SiteMapDomainMixin, self).get_urls(page, fake_site, protocol=None)

class MySitemap(SiteMapDomainMixin):
    changefreq = "never"
    priority = 0.5

    def items(self):
        return MyObj.objects.all().order_by('pk')[:1000]

    def location(self, item):
        return reverse('url_for_access_myobj', args=(item.slug,))

    def lastmod(self, obj):
        return obj.updated_at

class AnotherSitemap(Sitemap):
    changefreq = "never"
    priority = 0.5

    def items(self):
        return ['url_1', 'url_2', 'url_3',]

    def location(self, item):
        return reverse(item)

The urls.py would be something like...

from sitemaps import MySitemap
from sitemaps import AnotherSitemap
from yourapp.views import SomeDetailMyObjView
admin.autodiscover()

sitemaps = {
    'mysitemap': MySitemap,
    'anothersitemap': AnotherSitemap,
}

urlpatterns = patterns('',
    # other urls...
    url(r'^accessing-myobj/(?P<myobj_slug>[-\w]+)$', SomeDetailMyObjView, name='url_for_access_myobj'),
    (r'^sitemap\.xml$', 'django.contrib.sitemaps.views.sitemap', {'sitemaps': sitemaps}),
)
Lifelong answered 4/6, 2014 at 17:52 Comment(0)
C
0

You can try somethings like that:

from django.contrib.sites.models import Site, SiteManager

def get_fake_site(self):
    return Site(domain='example.com', name='example.com')

SiteManager.add_to_class('get_current', get_fake_site)

You should do it before constructing yous sitemap, and revert back to default after it.

Canula answered 3/5, 2012 at 4:59 Comment(2)
Little problem: type object 'SiteManager' has no attribute 'add_to_class'Tegular
Yeah, that's for models only. Anyway, your solution below is much more proper.Canula
B
0

Pretty much all answers require you to use the Site framework which requires migrations to work and it be added to INSTALLED_APPS.

In my instance I only needed to show the correct URL because I use Docker and the base URL based on my docker config is app.

With that all you need to do is define a custom Site() class like I have done below and you are good to go.


class UserGuideSitemap(sitemaps.Sitemap):
    priority = 1
    changefreq = 'daily'

    def get_urls(self, site=None, protocol=None, **kwargs):
        # we need the url to be example.com
        # SiteToShow() is just a custom class that gives the data needed
        return super().get_urls(site=SiteToShow(), protocol='https', **kwargs)

    def items(self):
        # must import here due to url circular import with urls.py
        from apps.user_guide.urls import urlpatterns as urls
        # get names of urls from base urls
        final_list = list()
        for pattern in urls:
            url_name = pattern.pattern.name
            # there are some urls we do not want
            if url_name not in ['']:
                final_list.append(url_name)

        return final_list

    def location(self, item):
        # return the URL for the sitemap
        return reverse(item)

And here is very simple the SiteToShow class:

class SiteToShow:

    domain = 'example.com'
    name = 'example.com'

    def __str__(self):
        return self.domain
Bladdernose answered 29/11, 2021 at 21:2 Comment(0)
S
0

The previous solutions are valid, but if you solely override the site, you might encounter an 'API already registered' issue. I tackled this by using the following code, where I specifically override the location.

#sitemap.py
from django.contrib.sitemaps import Sitemap
from .models import Post
from thedevstarter_backend.settings import FRONTEND_SITE_URL
class BlogSitemap(Sitemap):
    changefreq = 'weekly'
    priority = 0.9

    def items(self):
        return Post.objects.all()

    def lastmod(self, obj):
        return obj.updated_on

    def get_urls(self, site=None, **kwargs):
        domain = FRONTEND_SITE_URL  # Replace with your actual domain
        protocol = 'https'  # Replace with your actual protocol (http or https)

        # Construct URLs with the desired domain using reverse
        urls = super(BlogSitemap, self).get_urls(site=site, **kwargs)
        for url_info in urls:
            slug = url_info['item'].slug
            url_info['location'] = f'{protocol}://{domain}/blog/{slug}'

        return urls

    def location(self, obj):
        return f'/blog/{obj.slug}/'

Sediment answered 29/12, 2023 at 9:28 Comment(0)
S
-1

I use a patch by creating a custom template tag and use that function to replace the url: https://www.fraydit.com/blogs/wagtail-sitemap-in-docker/

Saturniid answered 25/7, 2021 at 20:27 Comment(1)
Please provide a detailed explanation to your answer, in order for the next user to understand your answer better. Also, provide a basic coverage of the content of your link, in case it stops working in the future.Brocatel

© 2022 - 2024 — McMap. All rights reserved.