【四】路由层URLconf

若能避开猛烈的狂喜,自然也不会有悲伤的来袭。

  URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表;你就是以这种方式告诉Django,对于客户端发来的某个URL调用哪一段逻辑代码对应执行。

一、Django 1.X版的url


from django.conf.urls import url


1、简单的路由配置

(1)单一(基本)路由规则:
url(r'^login/$', views.index),
(2)基于正则表达式的路由

  格式:url('正则表达式','视图函数内存地址')

  • 单个正则表达式
    单个括号需要在视图函数detail中增加一个参数来接收正则中匹配的内容。
# 路由
url(r'^detail-(\d+).html/$', views.detail)
# 视图函数
def detail(request,nid):#增加nid形参,接受url传递的参数
    pass
  • 多个正则表达式(按顺序接收)
# 路由
url(r'^detail-(\d+)-(\d+).html/$', views.detail)
# 视图函数
# 接受参数时候,按顺序接受,比如url是http://127.0.0.1:8000/detail-2-3.html/,第一个参数为2,第二个参数为3
def detail(request,nid,sid):
    pass

🐷 Tips:
  若要从URL中捕获一个值,只需要用一对圆括号将它包住;
  不需要添加一个前导的反斜杠,因为每个URL都有。例如,应该是^login而不是^/login
  每个正则表达式前面的r是可选的但是建议加上,他告诉Python这个字符串是“原始的”——字符串中任何字符都不应该转义;
  路由匹配从上到下依次匹配,一旦匹配成功就不再匹配后面的路由,所以在写路由时要注意顺序。

2、无名分组和有名分组

  • 无名分组
    将括号内正则表达式匹配到的内容当作位置参数自动传递给对应视图函数。
# 路由
url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
# 视图函数
def article_detail(request,'2017','01','07'):
    pass
  • 有名分组
    在Python正则表达式中,命名正则表达式组的语法是
    (?P<name>pattern),其中name 是组的名称,pattern 是要匹配的模式。
    将括号内正则表达式匹配到的内容当作关键字参数自动传递给对应视图函数,函数中使用名字作为行参获取值。
# 路由
url(r'^detail-(?P<id1>\d+)-(?P<id2>\d+).html/$', views.detail),
# 视图函数
def detail(request,id1,id2):
    pass

🐷 Tips:
  位置参数必须要在关键字参数前面;
  无名分组和有名分组不支持混合使用,虽然不能混合使用,但可以重复使用相同类型的

  • 给路由添加额外参数
    除了正则路由可以给视图函数传递参数以外,还可以使用路由中直接添加参数
# 路由
url(r'^detail/', views.detail, {"nid": 12}),
# 视图函数,增加nid参数来接收传递的参数
def detail(request,nid):
    pass

3、反向解析

  在使用Django 项目时,一个常见的需求是获得URL 的最终形式,以用于嵌入到生成的内容中(视图中和显示给用户的URL等)或者用于处理服务器端的导航(重定向等)。人们强烈希望不要硬编码这些URL(费力、不可扩展且容易产生错误)或者设计一种与URLconf 毫不相关的专门的URL 生成机制,因为这样容易导致一定程度上产生过期的URL。
  意思就是根据名字动态获取该名字所对应的能够匹配上url的一个结果:url(r'^index666888/',views.index,name='index'),这就是无论前面的路径怎么变,都能根据index这个名字匹配到相应的视图
  在需要URL 的地方,对于不同层级,Django 提供不同的工具用于URL 反查:

  • 在前端模板中:使用url模板标签
  • 在Python 代码中:使用django.core.urlresolvers.reverse() 函数

🐷Tips:
  当命名你的URL 模式时,请确保使用的名称不会与其它应用中名称冲突。如果你的URL 模式叫做comment,而另外一个应用中也有一个同样的名称,当你在模板中使用这个名称的时候不能保证将插入哪个URL。在URL 名称中加上一个前缀,比如应用的名称,将减少冲突的可能。我们建议使用myapp-comment 而不是comment。

(1) 不传参(name只能匹配固定的url)

------- 路由 -------
 url(r'^index/$', views.index,name='my_index'),

------- 前端模板中 -------
<a href="{% url 'my_index' %}">Index</a>

------- 后端python中 -------
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
def redirect_to_year(request):
    # ...
    year = 2006
    # ...
    return HttpResponseRedirect(reverse('my_index'))  # 同redirect("/my_index/")

(2) 传参(无名分组的反向解析和有名分组的反向解析)

  • 无名分组的反向解析
------- 路由 -------
url(r'^index/(\d+)/',views.index,name='list')  # index/1/ 或者 index/13213/ 或者 index/12/

------- 前端模板中 -------
<a href="{% url 'index' user_obj.pk %}">my_index</a>

------- 后端python中 -------
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect

def redirect_to_year(request):
    # ...
    user_obj.pk=1
    # ...
    return HttpResponseRedirect(reverse('index',args=(user_obj.pk,)))   # 同redirect("/index/1/")
  • 有名分组的反向解析
------- 路由 -------
url(r'^index/(?P<xxx>\d+)/',views.index,name='edit')

------- 前端模板中 -------
<a href="{% url 'edit' user_obj.pk %}">Edit</a>
或 <a href="{% url 'edit' xxx=user_obj.pk %}">Edit</a>

------- 后端python中 -------
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect

def redirect_to_year(request):
    # ...
    user_obj.pk=1
    # ...
    return HttpResponseRedirect(reverse('edit',args=(user_obj.pk,)))   # 同redirect("/edit/1/")
 或 return HttpResponseRedirect(reverse('edit',kwargs={'xxx':user_obj.pk}))   # 同redirect("/edit/1/")

(3) Model中使用获取URL——自定义get_absolute_url ()方法

class NewType(models.Model):
    caption = models.CharField(max_length=16)

    def get_absolute_url(self):
        """
        为每个对象生成一个URL
        应用:在对象列表中生成查看详细的URL,使用此方法即可!!!
        :return:
        """
        # return '/%s/%s' % (self._meta.db_table, self.id)
        # 或
        from django.urls import reverse
        return reverse('NewType.Detail', kwargs={'nid': self.id})

详解:在视图函数中反向获取url的方式是重载get_absolute_url方法。
   接下来以一个电子购物网站为例来理解:
模型表(models):

from django.db import models
from django.urls import reverse

class Category(models.Model):
    name = models.CharField(max_length=150, db_index=True)
    slug = models.SlugField(max_length=150, unique=True ,db_index=True)  # 🌈字段详解见下文
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ('name', )
        verbose_name = 'category'
        verbose_name_plural = 'categories'

    def __str__(self):
        return self.name

    def get_absolute_url(self):  # 🌸重点!!
        return reverse('shop:product_list_by_category', args=[self.slug])  # 这里的self.slug相当于当前对象category.slug

class Product(models.Model):
    category = models.ForeignKey(Category, related_name='products', on_delete=models.CASCADE)
    name = models.CharField(max_length=100, db_index=True)
    slug = models.SlugField(max_length=100, db_index=True) 
    description = models.TextField(blank=True)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    available = models.BooleanField(default=True)
    stock = models.PositiveIntegerField()  # 🌈字段详解见下文
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    image = models.ImageField(upload_to='products/%Y/%m/%d', blank=True)

    class Meta:
        ordering = ('name', )
        index_together = (('id', 'slug'),)

    def __str__(self):
        return self.name

    def get_absolute_url(self):  # 🌸重点!!
        return reverse('shop:product_detail', args=[self.id, self.slug])  # 这里的self.id相当于当前对象product.id,self.slug相当于当前对象product.slug

————————————————————————————
总结:
在category.get_obsolute_url里面用的是category.slug来连接到该product的list.html页面;
在product.get_obsolute_url里面用的是product.id和product.slug来连接到该product的detail.html页面;
至于这里为什么对象名都会变成小写,这就要进入源码中看,源码中是这么写的:
    get_absolute_url_override = settings.ABSOLUTE_URL_OVERRIDES.get(opts.label_lower)  # 🐷这里的label_lower就是将表名小写,进入label_lower,返回的是return '%s.%s' % (self.app_label, self.model_name)
    if get_absolute_url_override:
        setattr(cls, 'get_absolute_url', get_absolute_url_override)
————————————————————————————

视图(view):

from django.shortcuts import render, get_object_or_404 
from .models import Category, Product

def product_list(request, category_slug=None):
    category = None
    '''
    下面的categories是查询出的分类对象,
    print(categories.get_absolute_url())——>打印出/categories/-/
    '''
    categories = Category.objects.all()
    '''
    下面的products是查询出的产品对象,
    print(products.get_absolute_url())——>打印出/product/01-phone/
    '''
    products = Product.objects.filter(available=True)
    if category_slug:
        category = get_object_or_404(Category, slug=category_slug)  # 🐷详解见下文
        products = Product.objects.filter(category=category)

    context = {
        'category': category,
        'categories': categories,
        'products': products
    }
    return render(request, 'shop/product/list.html', context)

def product_detail(request, id, slug):
    product = get_object_or_404(Product, id=id, slug=slug, available=True)   # 🐷详解见下文
    context = {
        'product': product
    }
    return render(request, 'shop/product/detail.html', context)

————————————————————————————
总结:
在视图中查询出的对象如果调用get_absolute_url()方法,会得到相应表名的一个伪url,
后面就可以拼接到路径中,比如得到http://127.0.0.1:8000/shop/product/01-phone/
————————————————————————————

路由(url):

from django.conf.urls import url
from app import views

urlpatterns = [
        url("^$", views.product_list, name="product_list"),
        url(r"^(?P<category_slug>[\w-]+)/$", views.product_list,name="product_list_by_category"),
        url(r"^(?P<id>\d+)/(?P<slug>[\w-]+)/$", views.product_detail,name="product_detail"),
        ]

————————————————————————————
总结:
< >里面只是在传递关键字参数时用到,在路由中不会体现,只会得到后面的值或者名字,
比如第二个路由可能是http://127.0.0.1:8000/phone-name,第三个路由可能是http://127.0.0.1:8000/01/sony-phone
————————————————————————————

前端页面(list.html):

{% for product in products %}
       <div class="col-md-4">
         <div class="thumbnail">
             <a href="{{ product.get_absolute_url }}">  # 🐷重点!!!
                 <img src="{% if product.image %} {{ product.image.url }} {% else %} {% static 'img/default.jpg' %} {% endif %}" alt="..." style="height: 130px; width: auto">
             </a>
             <div class="caption">
                 <h3 class="text-center">
                     <a href="{{ product.get_absolute_url }}">{{ product.name }}</a>
                 </h3>
                 <p class="text-center">Kshs. {{ product.price }}</p>
             </div>
         </div>
        </div>
 {% endfor %}

————————————————————————————
总结:
这里的 product.get_absolute_url就会得到一个完整路由地址,完成跳转
————————————————————————————

🍃 补充知识点:

  • 模型表中的SlugField字段
slug = models.SlugField(max_length=150, unique=True ,db_index=True)

  SlugField 本质上相当于存放字符串,但是在意义上,主要用于把某些字段形成语义化的,可以访问的短网址(slug)字符串。
  举例而言,假设有一个关于文章的 models,有两个字段,分别是标题 title 和短网址 slug。

class Article(models.Model):
    title = models.CharField(max_length=100)
    slug = models.SlugField(max_length=40)

  这时候存入 models 的一条信息,title 是 The song of ice and fire。如果我们想用文章的标题作为 url 进行访问,完整的标题可能是:www.xxx.com/article/The song of ice and fire但是 url 是不能出现空格的,因此空格会被转变成 %20,最后网址得到www.xxx.com/article/The%20song%20of%20ice%20and%20fire,我们不希望出现这么多难看的 %20,而是希望用短横线 - 替代空格,得到www.xxx.com/article/the-song-of-ice-and-fire,而 Django 的 django.utils.text提供了一个方法叫 slugify,可以把刚才的文章标题 The song of ice and fire 做两个转变:全部转化成小写字母;空格部分替换成短横线 -,因为这种转变主要用于做 url 拼接,所以我们把这种结果都统一放在 SlugField 字段里面,用以构建语义化的 url 网址。

pre_save + slugify 构建 SlugField
(1)slug 是唯一的字段,不能出现重复 slug,所以 SlugField 的属性是 unique=True。
(2)使用 pre_save.connect(pre_save_post_receiver, sender=Post) 把 Post 这个 models 以及自定义的处理函数pre_save_post_receiver 连接起来,表示在 Post 存储之前,先用该函数进行数据预处理。
(3)预处理主要针对 slug,如果没有 slug,就把标题 title 用 slugify 转化成 slug。
(4)如果数据库中已经有了相同的 slug,就把之前的 slug 对应的数据的 id 拿过来,拼接在本次 slug 的后面。当然也可以用其他方法进行区分,避免重复。

在models.py中

from django.db import models
from django.db.models.signals import pre_save
from django.utils.text import slugify

class Post(models.Model):
    # ...
    title = models.CharField(max_length=150)
    slug = models.SlugField(unique=True)

def create_slug(instance):
    slug = slugify(instance.title)
    qs = Post.objects.filter(slug=slug).order_by("-id")
    exists = qs.exists()
    if exists:
        new_slug = "{0}-{1}".format(slug, qs.first().id)
        return new_slug
    return slug

def pre_save_post_receiver(sender, instance, *args, **kwargs):
    if not instance.slug:
        instance.slug = create_slug(instance)

pre_save.connect(pre_save_post_receiver, sender=Post)
  • PositiveIntegerField()字段:主要存储正整数数据
---------------------- 一些常用的字段 ----------------------
----------------------------------------------------------
1、AutoField:自增Field域,自动增加的一个数据库字段类型,例如id字段就可以使用该数据类型
2、BigAutoField:和AutoField相同,只是比AutoField要大
3、BigIntegerField:大整型,只要用于存储整型的数据
4、BinaryField:主要是存储原始的二进制数据
5、BooleanField:主要是存储布尔类型的数据,0和1
6、CharField:主要存储字符串的数据类型
7、DateField:主要存储日期类型的数据类型
8、DateTimeField:主要存储时间相关的数据类型
9、DecimalField:主要存储固定精度的十进制数据
10、EmailField:存储电子邮件格式的数据
11、FileField:存储文件类型的数据
12、FilePathField:存储文件路径的数据
13、FloatField:存储浮点型数据
14、ImageField:存储图片型数据
15、IntegerField:存储整型数据
16、GenericIPAddressField:存储IP地址信息数据
17、NullBooleanField:可以存储布尔值数据,也可以存储空null数据
18、PositiveIntegerField:主要存储正整数数据
19、SmallIntegerField:小整型,主要用于存储整型的数据
20、TextField:存储文章内容信息数据,存储比较长的文本信息
21、TimeField:存储时间信息
22、URLField:存储URL网址信息
  • get_object_or_404
    用特定查询条件获取某个对象,成功则返回该对象,否则引发一个 Http404。
    get_object_or_404(klass, *args, **kwargs)
    参数:
    klass:接受一个 Model 类,Manager 或 QuerySet 实例,表示你要对该对象进行查询。
    **kwargs:查询条件,格式需要被 get() 和 filter() 接受。
    举个例子🌰:
from django.shortcuts import render
from django.shortcuts import get_object_or_404
from myApp.models import Book 

def my_view(request):
    context = {}
    # 查询主键为1的书,找不到返回http404
    books = get_object_or_404(Book, pk=1)
    context['books'] = books
    return render(request, 'my_view.html', context)

除了传递一个 Model,还可以传递一个 QuerySet 实例:

queryset = Book.objects.filter(title__startswith='红')
books = get_object_or_404(queryset, pk=1)

以上写法等价于:
get_object_or_404(Book, title__startswith='红', pk=1)

4、路由分发

  当项目中的app有多个时候,导入include路由分发,那么项目总路由不再做路由与视图函数的匹配工作,而是做一个中转。
🐷Tips:
  django里面每一个app都可以有自己的urls.py,static静态文件夹,templates模板文件夹;
  路由分发的时候千万不要加$

  • 配置工程中的总路由(urls.py)
#工程的urls.py配置

#导入include
from django.conf.urls import url,include

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^blog/',include('blog.urls'))  # 匹配到以blog开头的都转发到blog应用目录下的urls.py中
]
  • 在blog应用下新建urls.py,配置目的url
from django.conf.urls import url,include
from django.contrib import admin
#导入blog下的view函数
from . import views
urlpatterns = [
    url(r'^index/',views.index),
    url(r'^detail/',views.detail),
]

5、名称空间

  命名空间(英语:Namespace)是表示标识符的可见范围。一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的。这样,在一个新的命名空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其它命名空间中。
  由于name没有作用域,Django在反解URL时,会在项目全局顺序搜索,当查找到第一个name指定URL时,立即返回。我们在开发项目时,会经常使用name属性反解出URL,当不小心在不同的app的urls中定义相同的name时,可能会导致URL反解错误,为了避免这种事情发生,引入了命名空间
  使用namespacse参数给include命名,可以后续反向解析url。

  • 工程下的urls.py
from django.contrib import admin
from cmdb import views
from django.conf.urls import url,include
urlpatterns = [
    url(r'^app01/',include('app01.urls',namespace='myapp01')),
    url(r'^app02/',include('app01.urls',namespace='myapp02')),
]
  • app01下面的urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
    url(r'^index/',views.index,name='myindex'),
]
  • app02下面的urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
    url(r'^index/',views.index,name='myindex'),  # 这时候与app01中的name相同
]
  • 当反向解析时
# views.py中进行反向解析
def index(request):
    v=reverse('myapp01:myindex')
    print(v)      #输出/app01/index/
    print(request.resolver_match)
    return HttpResponse('ok')

# 在模版中解析改地址
{% url 'myapp01:myindex' %}

# 带参数的url反解析
v = reverse('myapp01:myindex', kwargs={'page':11})
{% url 'myapp01 :myindex' page=12 %}

6、伪静态网页(以html结尾)

  伪静态就是通过某些技术(rewrite)把动态网页的url地址伪装成静态url。此技术并未提升性能,甚至会使得性能下降。唯一的好处就是让搜索引擎收录网站内容,提升网页被搜索的概率。
  搜索引擎优化(seo):

# 在路由后面加了.html,假装它是一个静态的网页
url(r'^index.html',views.index)
url(r'^index/\d+.html',views.index)

二、Django2.0版的path

传送门(2.0的URL dispatcher):
https://docs.djangoproject.com/en/2.0/topics/http/urls/#example


from django.urls import path,re_path


1、在1.X中使用的是url方式,而2.0中推荐使用path模块,而且如果使用正则路由,则要引入re_path,并且一定要使用()把正则表达式包起来,然后用?P正式表达式这种形式来表式。
2、在2.0中使用namespace会报错,说什么app_name不存在什么的,这时需要在urls.py中加上app_name='test',加在urlpatterns=[…]上面即可。

  • 思考情况如下:
urlpatterns = [  
    re_path('articles/(?P<year>[0-9]{4})/', year_archive),  
    re_path('article/(?P<article_id>[a-zA-Z0-9]+)/detail/', detail_view),  
    re_path('articles/(?P<article_id>[a-zA-Z0-9]+)/edit/', edit_view),  
    re_path('articles/(?P<article_id>[a-zA-Z0-9]+)/delete/', delete_view),  
]

考虑下这样的两个问题:
  第一个问题,函数 year_archive 中year参数是字符串类型的,因此需要先转化为整数类型的变量值,当然year=int(year) 不会有诸如如TypeError或者ValueError的异常。那么有没有一种方法,在url中,使得这一转化步骤可以由Django自动完成?
  第二个问题,三个路由中article_id都是同样的正则表达式,但是你需要写三遍,当之后article_id规则改变后,需要同时修改三处代码,那么有没有一种方法,只需修改一处即可?
  在Django2.0中,可以使用 path 解决以上的两个问题。

  • Path converters(转换器)
    Django默认支持以下5个转化器:
      str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
      int,匹配正整数,包含0。
      slug,匹配字母、数字以及横杠、下划线组成的字符串。
      uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
      path,匹配任何非空字符串,包含了路径分隔符

  • 基本示例

from django.urls import path  
from . import views  
urlpatterns = [  
    path('articles/2003/', views.special_case_2003),  
    path('articles/<int:year>/', views.year_archive),  
    path('articles/<int:year>/<int:month>/', views.month_archive),  
    path('articles/<int:year>/<int:month>/<slug>/', views.article_detail),  
]  

基本规则:
  使用尖括号(<>)从url中捕获值。
  捕获值中可以包含一个转化器类型(converter type),比如使用 <int:name> 捕获一个整数变量。若果没有转化器,将匹配任何字符串,当然也包括了 / 字符。
  无需添加前导斜杠。


Django2.0视图调用形式
  • 注册自定义转换器
    对于一些复杂或者复用的需要,可以定义自己的转化器。转化器是一个类或接口,它的要求有三点:
      regex 类属性,字符串类型。
      to_python(self, value) 方法,value是由类属性 regex 所匹配到的字符串,返回具体的Python变量值,以供Django传递到对应的视图函数中。
      to_url(self, value) 方法,和 to_python 相反,value是一个具体的Python变量值,返回其字符串,通常用于url反向引用。
    例子🌰:
class FourDigitYearConverter:  
    regex = '[0-9]{4}'  
    def to_python(self, value):  
        return int(value)  
    def to_url(self, value):  
        return '%04d' % value  

使用register_converter 将其注册到URL配置中:

from django.urls import register_converter, path  
from . import converters, views  
register_converter(converters.FourDigitYearConverter, 'yyyy')  
urlpatterns = [  
    path('articles/2003/', views.special_case_2003),  
    path('articles/<yyyy:year>/', views.year_archive),  
    ...  
]  
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容