django自定义类,实现简单的sitemap(网站地图)功能

2021-04-23 01:29

阅读:601

标签:+=   lis   简单的   字典   ima   页面   位置   als   统一   

功能描述

对于百度、360等搜索引擎,后台有提交网站地图(sitemap)的需求。以百度为例,规定网站地图的格式为xml或者txt,并且有比较严格的格式要求,django自带sitemap功能,但是使用起来比较麻烦,相关教程也非常少,还不够灵活,这里自定义一个类,实例化之后以比较灵活的方式来生成网站地图。

技术图片

sitemap模板

根节点为urlset,由url包裹其他标签这个后端渲染的变量有loc、lastmod、changefreq、priority这几种,以下的模板因为没有必要使用lastmod,所以既没有留位置渲染,也没有用if做空值判断,可以根据需求自己添加。


    {% for item in obj_sitemap %}
        {{ item.loc }}
            {% if item.changefreq %}
                {{ item.changefreq }}
            {% endif %}
            {% if item.priority %}
                {{ item.priority }}
            {% endif %}
        
    {% endfor %}

生成网站地图的类

这个sitemap类的主要思路是将字典渲染成xml格式,可以单独写出来导入,也可以直接写到views.py中。类实例化之后将参数通过函数转化成字典传递到列表中,到了所有需要的url都集中之后,统一渲染出来。

class Sitemap:
    ‘‘‘
        · loc:完整的url,带有协议名http/https、域名
        · lastmod:最近的更新时间,格式如 2020-11-11
        · changefreq:页面的更新频率,有这几种 always、hourly、daily、weekly、monthly、yearly、never
        · priority:优先级,从1-0越来越高,比如优先级最高的首页是1
    ‘‘‘
    
    # 注意,实例化的时候,网站的协议默认为http,正常情况下http会被重定向到https,但是https未经设置不能重定向到http,浏览器还会报ssl警告
    def __init__(self,request,template,protocol="http"):
        self.request = request
        # 网站前缀,如果对象实例化的时候,protocol是https的话,url的前缀就是https://domain
        self.site = protocol + "://" + request.META["HTTP_HOST"]
        self.template = template
        self.li_query = []
    
    # 传入参数自动构造成字典
    def construct_dict(self,loc=None,lastmod=None,changefreq=None,priority=None):
        if loc:
            self.li_query.append({
                "loc":loc,
                "lastmod":lastmod,
                "changefreq":changefreq,
                "priority":priority
            })
            
	# 执行渲染,需要注意的是,渲染出的结果是一个xml文件,因此要设置content_type="text/xml"
    def execute(self):
        return render(self.request,"sitemap.xml",{"obj_sitemap":self.li_query},content_type="text/xml")
    

views.py视图函数

以下代码的models指的是django的app的models.py,因为已经导入到views.py,这里就不过多赘述

# 因为生成网站地图是开销比较大的,特地开启缓存功能
from django.views.decorators.cache import cache_page

# 缓存页面刷新时间为12小时
@cache_page(60*60*12)
def sitemap(request):
    
    # 实例化sitemap对象
    obj_sitemap = Sitemap(request,"sitemap.xml",protocol="http")

    # 类似于首页的页面,直接使用对象添加参数的方法添加
    obj_sitemap.construct_dict(
        loc=obj_sitemap.site+reverse("index"),
        changefreq="daily",
        priority="1"
    )
    
    # 文章页,orm中的audit为审核状态(入库但不发布),因此用exclude先排除,其余都遍历一次
    for item in models.Airticle.objects.exclude(audit=False).order_by("-id"):
        obj_sitemap.construct_dict(
            # 本项目文章页的路由名称是detail,读取数据库条目的参数是id,构造出来的url结构就是 https://domain/detail/?id=index/
            loc=obj_sitemap.site+reverse("detail")+"?id="+str(item.id),
            changefreq="yearly",
            priority="0.4"
        )

    # 列表页,文章按照主题分类聚合成列表页。这里的Types是所有的文章类型,每一种类型按照id来区分,用page来切片实现分页
    # 遍历
    for item in models.Types.objects.all():
        whole_count = item.airtical_set.all().exclude(audit=False).count()
        # 每个列表页展现几篇文章,这里就写几,这里是9
        page_count = 9
        # 因为有分页,需要单独采用取模运算来计算数量,page表示这个列表页有几页,extra表示余数,如果余数不为0,那么page就应该+1,因为要单独加一页展现最后不到9的几篇文章
        page,extra = divmod(whole_count,page_count)
        if extra != 0:
            page += 1
        # 这个项目后端使用get取值,列表页的url结构是 https://domain/listpage/?id=index&page=index ,如果只有一页,就不存在page参数,所以第一页单独加一个判断,要用到字符串格式化
        for i in range(1,page+1):
            if i == 1:
                page_tail = ""
            else:
                page_tail = f"&page={i}"
            obj_sitemap.construct_dict(
                # url结构
                loc=obj_sitemap.site+reverse("news_list")+f"?id={item.id}{page_tail}",
                changefreq="weekly",
                priority="0.6"
            )

    # 最后一步,用render渲染
    return obj_sitemap.execute()

django自定义类,实现简单的sitemap(网站地图)功能

标签:+=   lis   简单的   字典   ima   页面   位置   als   统一   

原文地址:https://www.cnblogs.com/himan47/p/14685377.html


评论


亲,登录后才可以留言!