Django template 2.0 - 草稿

模板标签除了几个常用的,还真心没有仔细了解一下,看到2.0发布后,翻译学习一下。

本文尽量忠实原著,毕竟大神的东西不好亵渎。翻译中我尽量加入自己做项目时候经验,不至于翻译出来不是人类能读的。

一、模板介绍

作为鼎鼎大名的网络框架,Django不能很方便的动态生成HTML,它还好意思出门?最普通的方式就是依靠模板来动态生成。模板主要包括两个内容,一是包含了HTML输出的静态部分,二是怎么样插入动态内容的语法。在教程的第三部分中有一个例子就是用模板生成HTML网页的,有兴趣可以去参考一下。

一个Django 工程一般配置一个或者几个模板引擎,如果你不用模板,当然可以没有。Django自带自己独创的叫DTL的引擎,作为自己模板系统的后端。当然也支持流行的Jinja2引擎。如果你要用其他第三方的引擎,稍加配置后端也支持。

无论那种后端引擎,Django提供了一套标准的API来加载和渲染模板。所谓的加载包括两步,首先找到你指定的模板,然后预处理一下,一般就是编译一下放到内存里备用。所谓的渲染也包括两步,首先把环境变量的数据插入到模板中,然后返回一个结果字符串。

DTL是Django自己的模板系统,在1.8版本以前它仅仅是可选的。以后就默认内置了。Django的开发大神们相当的看好它,可以秒杀其他模板语言。大神这么推崇的模板,如果你没有特别理由,建议用DTL吧。特别是你想开发一个可以随时加入插件的应用并且要发布他的时候。Django自带的像django.contrib.admin的管理后台就是用的DTL 模板。

历史原因,模板引擎和模板语言都在django.template的模块中

警告!

模板系统对恶意模板没有反制措施。所以网站不要允许用户提供自己的模板,恶意的用户有可能会实施XSS攻击,获取模板中的隐私数据

二、对模板引擎的支持

2.1模板引擎的设置

模板引擎在TEMPLATES设置中配置。对每个引擎的配置就是一个字典。默认是空的。如果你用startproject命令来生成你的工程,在setting.py中会默认提供一点有用的配置。

TEMPLATES = [

    {

        'BACKEND': 'django.template.backends.django.DjangoTemplates',

        'DIRS': [],

        'APP_DIRS': True,

        'OPTIONS': {

            # ... some options here ...

        },

    },

]

后端这个键值是个python路径,它指向了一个模板引擎的类,这个类实现了模本后端的API。自带的后端引擎类是django.template.backend.django.DjangoTemplate和django.template.bakend.jinja2.Jinja2

一般来说,引擎是从文件中载入模板,所以顶级配置中为每个引擎提供了两个通用设置选项

DIRS定义了引擎搜索模板源文件的一系列文件夹。搜索的时候是按照你提供的文件夹的顺序来搜索的。

APP_DIRS是告诉引擎你要在安装的应用中搜索模板。每个后端为应用存储模板的下层文件夹提供了通用的名字。

OPTIONS。特殊情况下,你可以为相同的后端用不同的选项值来配置不同的后端实例。这种情况下,你要为每个引擎提供独特的名字。OPTIONS 就是设置后端特殊值的地方

2.2模板的使用

django.template.loader模块里有两个函数来加载模板

get_template(template_name, using=None)

这个函数用指定的模板名字来加载模本,返回一个模板对象

不同的后端加载模板后返回的模板对象是不同的,每个后端都有自己的模板类。

get_template()会按顺序尝试模板引擎,直到成功。注:引擎是自带的不会抛出异常。如果模板没有找到就抛出TemplateDoesNotExist的异常,如果找到模板,但是模板里面有语法错误,就抛出TemplateSyntaxError的异常。

怎么搜索模板以及怎么加载模板?每个引擎后端不同,方式也不同,相同的引擎后端因为配置不同,也会有差别。

如果你想限制在搜索某个引擎,你可以给引擎的NAME变量赋值


select_template(template_name_list, using=None)


select_template() 和get_template()类似,不同之处在于它的参数是一个模板名字的列表。这个方法蒋按顺序搜索每一个名字,搜索到一个符合就停止,返回模板对象。

如果加载模板失败,会抛出下面两个异常,这两个异常实在django.temolate定义好的。

exception TemplateDoesNotExist(msg, tried=None, backend=None, chain=None)

没有找到匹配的模板会抛出这个异常。在调试页面它会用下面这些参数来填充模板

参数 backend

产生这个异常的模板后端实例。实际就是那个引擎

参数tried

在寻找模板的时候都寻找了那些目录。调试页面会以tuple的形式展示出来,这个tuple包含原始的文件目录和状态。 (origin, status),origin是一个原始样子的对象,status是一个字符串,内容找不到模板的原因

参数chain

加载模板时一系列中间TemplateDoesNotExist异常,一般发生在用多个引擎加载模板的时候,如在get_template方法中

exception TemplateSyntaxError(msg)


This exception is raised when a template was found but contains errors.

Template objects returned by get_template() and select_template() must provide a render() method with the following signature:

Template.render(context=None, request=None)¶

Renders this template with a given context.

If context is provided, it must be a dict. If it isn’t provided, the engine will render the template with an empty context.

If request is provided, it must be an HttpRequest. Then the engine must make it, as well as the CSRF token, available in the template. How this is achieved is up to each backend.

Here’s an example of the search algorithm. For this example the TEMPLATES setting is:

TEMPLATES = [

    {

        'BACKEND': 'django.template.backends.django.DjangoTemplates',

        'DIRS': [

            '/home/html/example.com',

            '/home/html/default',

        ],

    },

    {

        'BACKEND': 'django.template.backends.jinja2.Jinja2',

        'DIRS': [

            '/home/html/jinja2',

        ],

    },

]

If you call get_template('story_detail.html'), here are the files Django will look for, in order:

/home/html/example.com/story_detail.html ('django' engine)

/home/html/default/story_detail.html ('django' engine)

/home/html/jinja2/story_detail.html ('jinja2' engine)

If you call select_template(['story_253_detail.html', 'story_detail.html']), here’s what Django will look for:

/home/html/example.com/story_253_detail.html ('django' engine)

/home/html/default/story_253_detail.html ('django' engine)

/home/html/jinja2/story_253_detail.html ('jinja2' engine)

/home/html/example.com/story_detail.html ('django' engine)

/home/html/default/story_detail.html ('django' engine)

/home/html/jinja2/story_detail.html ('jinja2' engine)

When Django finds a template that exists, it stops looking.

Tip

You can use select_template() for flexible template loading. For example, if you’ve written a news story and want some stories to have custom templates, use something like select_template(['story_%s_detail.html' % story.id, 'story_detail.html']). That’ll allow you to use a custom template for an individual story, with a fallback template for stories that don’t have custom templates.

It’s possible – and preferable – to organize templates in subdirectories inside each directory containing templates. The convention is to make a subdirectory for each Django app, with subdirectories within those subdirectories as needed.

Do this for your own sanity. Storing all templates in the root level of a single directory gets messy.

To load a template that’s within a subdirectory, just use a slash, like so:

get_template('news/story_detail.html')

Using the same TEMPLATES option as above, this will attempt to load the following templates:

/home/html/example.com/news/story_detail.html ('django' engine)

/home/html/default/news/story_detail.html ('django' engine)

/home/html/jinja2/news/story_detail.html ('jinja2' engine)

In addition, to cut down on the repetitive nature of loading and rendering templates, Django provides a shortcut function which automates the process.

render_to_string(template_name, context=None, request=None, using=None)[source]¶

render_to_string() loads a template like get_template() and calls its render() method immediately. It takes the following arguments.

template_name

The name of the template to load and render. If it’s a list of template names, Django uses select_template() instead of get_template() to find the template.

context

A dict to be used as the template’s context for rendering.

request

An optional HttpRequest that will be available during the template’s rendering process.

using

An optional template engine NAME. The search for the template will be restricted to that engine.

Usage example:

from django.template.loader import render_to_string

rendered = render_to_string('my_template.html', {'foo': 'bar'})

See also the render() shortcut which calls render_to_string() and feeds the result into an HttpResponse suitable for returning from a view.

Finally, you can use configured engines directly:

engines¶

Template engines are available in django.template.engines:

from django.template import engines

django_engine = engines['django']

template = django_engine.from_string("Hello {{ name }}!")

The lookup key — 'django' in this example — is the engine’s NAME.

Built-in backends¶

class DjangoTemplates[source]¶

Set BACKEND to 'django.template.backends.django.DjangoTemplates' to configure a Django template engine.

When APP_DIRS is True, DjangoTemplates engines look for templates in the templates subdirectory of installed applications. This generic name was kept for backwards-compatibility.

DjangoTemplates engines accept the following OPTIONS:

'autoescape': a boolean that controls whether HTML autoescaping is enabled.

It defaults to True.

Warning

Only set it to False if you’re rendering non-HTML templates!

'context_processors': a list of dotted Python paths to callables that are used to populate the context when a template is rendered with a request. These callables take a request object as their argument and return a dict of items to be merged into the context.

It defaults to an empty list.

See RequestContext for more information.

'debug': a boolean that turns on/off template debug mode. If it is True, the fancy error page will display a detailed report for any exception raised during template rendering. This report contains the relevant snippet of the template with the appropriate line highlighted.

It defaults to the value of the DEBUG setting.

'loaders': a list of dotted Python paths to template loader classes. Each Loader class knows how to import templates from a particular source. Optionally, a tuple can be used instead of a string. The first item in the tuple should be the Loader class name, and subsequent items are passed to the Loader during initialization.

The default depends on the values of DIRS and APP_DIRS.

See Loader types for details.

'string_if_invalid': the output, as a string, that the template system should use for invalid (e.g. misspelled) variables.

It defaults to an empty string.

See How invalid variables are handled for details.

'file_charset': the charset used to read template files on disk.

It defaults to the value of FILE_CHARSET.

'libraries': A dictionary of labels and dotted Python paths of template tag modules to register with the template engine. This can be used to add new libraries or provide alternate labels for existing ones. For example:

OPTIONS={

    'libraries': {

        'myapp_tags': 'path.to.myapp.tags',

        'admin.urls': 'django.contrib.admin.templatetags.admin_urls',

    },

}

Libraries can be loaded by passing the corresponding dictionary key to the {% load %} tag.

'builtins': A list of dotted Python paths of template tag modules to add to built-ins. For example:

OPTIONS={

    'builtins': ['myapp.builtins'],

}

Tags and filters from built-in libraries can be used without first calling the {% load %} tag.

class Jinja2[source]¶

Requires Jinja2 to be installed:

$ pip install Jinja2

Set BACKEND to 'django.template.backends.jinja2.Jinja2' to configure a Jinja2 engine.

When APP_DIRS is True, Jinja2 engines look for templates in the jinja2 subdirectory of installed applications.

The most important entry in OPTIONS is 'environment'. It’s a dotted Python path to a callable returning a Jinja2 environment. It defaults to 'jinja2.Environment'. Django invokes that callable and passes other options as keyword arguments. Furthermore, Django adds defaults that differ from Jinja2’s for a few options:

'autoescape': True

'loader': a loader configured for DIRS and APP_DIRS

'auto_reload': settings.DEBUG

'undefined': DebugUndefined if settings.DEBUG else Undefined

Jinja2 engines also accept the following OPTIONS:

'context_processors': a list of dotted Python paths to callables that are used to populate the context when a template is rendered with a request. These callables take a request object as their argument and return a dict of items to be merged into the context.

It defaults to an empty list.

Using context processors with Jinja2 templates is discouraged.

Context processors are useful with Django templates because Django templates don’t support calling functions with arguments. Since Jinja2 doesn’t have that limitation, it’s recommended to put the function that you would use as a context processor in the global variables available to the template using jinja2.Environment as described below. You can then call that function in the template:

{{ function(request) }}

Some Django templates context processors return a fixed value. For Jinja2 templates, this layer of indirection isn’t necessary since you can add constants directly in jinja2.Environment.

The original use case for adding context processors for Jinja2 involved:

Making an expensive computation that depends on the request.

Needing the result in every template.

Using the result multiple times in each template.

Unless all of these conditions are met, passing a function to the template is simpler and more in line with the design of Jinja2.

New in Django 1.11:

The 'context_processors' option was added.

The default configuration is purposefully kept to a minimum. If a template is rendered with a request (e.g. when using render()), the Jinja2 backend adds the globals request, csrf_input, and csrf_token to the context. Apart from that, this backend doesn’t create a Django-flavored environment. It doesn’t know about Django filters and tags. In order to use Django-specific APIs, you must configure them into the environment.

For example, you can create myproject/jinja2.py with this content:

from django.contrib.staticfiles.storage import staticfiles_storage

from django.urls import reverse

from jinja2 import Environment

def environment(**options):

    env = Environment(**options)

    env.globals.update({

        'static': staticfiles_storage.url,

        'url': reverse,

    })

    return env

and set the 'environment' option to 'myproject.jinja2.environment'.

Then you could use the following constructs in Jinja2 templates:

<img src="{{ static('path/to/company-logo.png') }}" alt="Company Logo">

<a href="{{ url('admin:index') }}">Administration</a>

The concepts of tags and filters exist both in the Django template language and in Jinja2 but they’re used differently. Since Jinja2 supports passing arguments to callables in templates, many features that require a template tag or filter in Django templates can be achieved simply by calling a function in Jinja2 templates, as shown in the example above. Jinja2’s global namespace removes the need for template context processors. The Django template language doesn’t have an equivalent of Jinja2 tests.

Custom backends¶

Here’s how to implement a custom template backend in order to use another template system. A template backend is a class that inherits django.template.backends.base.BaseEngine. It must implement get_template() and optionally from_string(). Here’s an example for a fictional foobar template library:

from django.template import TemplateDoesNotExist, TemplateSyntaxError

from django.template.backends.base import BaseEngine

from django.template.backends.utils import csrf_input_lazy, csrf_token_lazy

import foobar

class FooBar(BaseEngine):

    # Name of the subdirectory containing the templates for this engine

    # inside an installed application.

    app_dirname = 'foobar'

    def __init__(self, params):

        params = params.copy()

        options = params.pop('OPTIONS').copy()

        super().__init__(params)

        self.engine = foobar.Engine(**options)

    def from_string(self, template_code):

        try:

          return Template(self.engine.from_string(template_code))

        except foobar.TemplateCompilationFailed as exc:

            raise TemplateSyntaxError(exc.args)

    def get_template(self, template_name):

        try:

            return Template(self.engine.get_template(template_name))

        except foobar.TemplateNotFound as exc:

            raise TemplateDoesNotExist(exc.args, backend=self)

        except foobar.TemplateCompilationFailed as exc:

            raise TemplateSyntaxError(exc.args)

class Template:

    def __init__(self, template):

        self.template = template

    def render(self, context=None, request=None):

        if context is None:

            context = {}

        if request is not None:

            context['request'] = request

            context['csrf_input'] = csrf_input_lazy(request)

            context['csrf_token'] = csrf_token_lazy(request)

        return self.template.render(context)

See DEP 182 for more information.

Debug integration for custom engines¶

The Django debug page has hooks to provide detailed information when a template error arises. Custom template engines can use these hooks to enhance the traceback information that appears to users. The following hooks are available:

Template postmortem¶

The postmortem appears when TemplateDoesNotExist is raised. It lists the template engines and loaders that were used when trying to find a given template. For example, if two Django engines are configured, the postmortem will appear like:

../../_images/postmortem.png

Custom engines can populate the postmortem by passing the backend and tried arguments when raising TemplateDoesNotExist. Backends that use the postmortem should specify an origin on the template object.

Contextual line information¶

If an error happens during template parsing or rendering, Django can display the line the error happened on. For example:

../../_images/template-lines.png

Custom engines can populate this information by setting a template_debug attribute on exceptions raised during parsing and rendering. This attribute is a dict with the following values:

'name': The name of the template in which the exception occurred.

'message': The exception message.

'source_lines': The lines before, after, and including the line the exception occurred on. This is for context, so it shouldn’t contain more than 20 lines or so.

'line': The line number on which the exception occurred.

'before': The content on the error line before the token that raised the error.

'during': The token that raised the error.

'after': The content on the error line after the token that raised the error.

'total': The number of lines in source_lines.

'top': The line number where source_lines starts.

'bottom': The line number where source_lines ends.

Given the above template error, template_debug would look like:

{

    'name': '/path/to/template.html',

    'message': "Invalid block tag: 'syntax'",

    'source_lines': [

        (1, 'some\n'),

        (2, 'lines\n'),

        (3, 'before\n'),

        (4, 'Hello {% syntax error %} {{ world }}\n'),

        (5, 'some\n'),

        (6, 'lines\n'),

        (7, 'after\n'),

        (8, ''),

    ],

    'line': 4,

    'before': 'Hello ',

    'during': '{% syntax error %}',

    'after': ' {{ world }}\n',

    'total': 9,

    'bottom': 9,

    'top': 1,

}

Origin API and 3rd-party integration¶

Django templates have an Origin object available through the template.origin attribute. This enables debug information to be displayed in the template postmortem, as well as in 3rd-party libraries, like the Django Debug Toolbar.

Custom engines can provide their own template.origin information by creating an object that specifies the following attributes:

'name': The full path to the template.

'template_name': The relative path to the template as passed into the the template loading methods.

'loader_name': An optional string identifying the function or class used to load the template, e.g. django.template.loaders.filesystem.Loader.

The Django template language¶

Syntax¶

About this section

This is an overview of the Django template language’s syntax. For details see the language syntax reference.

A Django template is simply a text document or a Python string marked-up using the Django template language. Some constructs are recognized and interpreted by the template engine. The main ones are variables and tags.

A template is rendered with a context. Rendering replaces variables with their values, which are looked up in the context, and executes tags. Everything else is output as is.

The syntax of the Django template language involves four constructs.

Variables¶

A variable outputs a value from the context, which is a dict-like object mapping keys to values.

Variables are surrounded by {{ and }} like this:

My first name is {{ first_name }}. My last name is {{ last_name }}.

With a context of {'first_name': 'John', 'last_name': 'Doe'}, this template renders to:

My first name is John. My last name is Doe.

Dictionary lookup, attribute lookup and list-index lookups are implemented with a dot notation:

{{ my_dict.key }}

{{ my_object.attribute }}

{{ my_list.0 }}

If a variable resolves to a callable, the template system will call it with no arguments and use its result instead of the callable.

Tags¶

Tags provide arbitrary logic in the rendering process.

This definition is deliberately vague. For example, a tag can output content, serve as a control structure e.g. an “if” statement or a “for” loop, grab content from a database, or even enable access to other template tags.

Tags are surrounded by {% and %} like this:

{% csrf_token %}

Most tags accept arguments:

{% cycle 'odd' 'even' %}

Some tags require beginning and ending tags:

{% if user.is_authenticated %}Hello, {{ user.username }}.{% endif %}

A reference of built-in tags is available as well as instructions for writing custom tags.

Filters¶

Filters transform the values of variables and tag arguments.

They look like this:

{{ django|title }}

With a context of {'django': 'the web framework for perfectionists with deadlines'}, this template renders to:

The Web Framework For Perfectionists With Deadlines

Some filters take an argument:

{{ my_date|date:"Y-m-d" }}

A reference of built-in filters is available as well as instructions for writing custom filters.

Comments¶

Comments look like this:

{# this won't be rendered #}

A {% comment %} tag provides multi-line comments.

Components¶

About this section

This is an overview of the Django template language’s APIs. For details see the API reference.

Engine¶

django.template.Engine encapsulates an instance of the Django template system. The main reason for instantiating an Engine directly is to use the Django template language outside of a Django project.

django.template.backends.django.DjangoTemplates is a thin wrapper adapting django.template.Engine to Django’s template backend API.

Template¶

django.template.Template represents a compiled template. Templates are obtained with Engine.get_template() or Engine.from_string()

Likewise django.template.backends.django.Template is a thin wrapper adapting django.template.Template to the common template API.

Context¶

django.template.Context holds some metadata in addition to the context data. It is passed to Template.render() for rendering a template.

django.template.RequestContext is a subclass of Context that stores the current HttpRequest and runs template context processors.

The common API doesn’t have an equivalent concept. Context data is passed in a plain dict and the current HttpRequest is passed separately if needed.

Loaders¶

Template loaders are responsible for locating templates, loading them, and returning Template objects.

Django provides several built-in template loaders and supports custom template loaders.

Context processors¶

Context processors are functions that receive the current HttpRequest as an argument and return a dict of data to be added to the rendering context.

Their main use is to add common data shared by all templates to the context without repeating code in every view.

Django provides many built-in context processors. Implementing a custom context processor is as simple as defining a function.

Form Assets (the Media class)Class-based views

BACK TO TOP

Additional Information

Search:

Search 2.0 documentation

搜索

Support Django!

Support Django!

Chris Cogdon donated to the Django Software Foundation to support Django development. Donate today!

Contents

Templates

Support for template engines

Configuration

Usage

Built-in backends

Custom backends

Debug integration for custom engines

Template postmortem

Contextual line information

Origin API and 3rd-party integration

The Django template language

Syntax

Variables

Tags

Filters

Comments

Components

Engine

Template

Context

Loaders

Context processors

Browse

Prev: Form Assets (the Media class)

Next: Class-based views

Table of contents

General Index

Python Module Index

You are here:

Django 2.0 documentation

Using Django

Templates

Getting help

FAQ

Try the FAQ — it's got answers to many common questions.

Index, Module Index, or Table of Contents

Handy when looking for specific information.

django-users mailing list

Search for information in the archives of the django-users mailing list, or post a question.

#django IRC channel

Ask a question in the #django IRC channel, or search the IRC logs to see if it’s been asked before.

Ticket tracker

Report bugs with Django or Django documentation in our ticket tracker.

Download:

Offline (Django 2.0): HTML | PDF | ePub

Provided by Read the Docs.

Django Links

Learn More

About Django

Getting Started with Django

Team Organization

Django Software Foundation

Code of Conduct

Diversity Statement

Get Involved

Join a Group

Contribute to Django

Submit a Bug

Report a Security Issue

Follow Us

GitHub

Twitter

News RSS

Django Users Mailing List

Django

Hosting by

Rackspace

Design by

Threespot

&

© 2005-2018 Django Software Foundation and individual contributors. Django is a registered trademark of the Django Software Foundation.

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

推荐阅读更多精彩内容