简明Python开发教程(6):用Django搭建网站

前面已经分享了Python的基础知识和典型应用,那么如何可视化呈现结果并进行交互?
一般用网页形式进行展示,网页展示结果、交互,服务器后台提供数据支持。开发网站又是一个复杂的工作。
幸好Python的Django框架可以让我们非常容易的搭建网站系统,只需要我们学习一点点HTML、CSS、JavaScript等前端知识,了解一下Django的工作原理就可以工作了。
前期我们梳理了工作岗位需要掌握的11大类、327小类技能点,并对27位同事的技能掌握进行摸底调查,分为:没听过、初级、中级、高级四部分;
同时统计近5年的外出培训记录。
目前需要开发一个网站,提供查询功能:
1)按人员查:对比显示该同事的技能掌握情况和培训记录;
2)按技能查询:显示不同基本人员分布情况

1 Django介绍

Django是用Python开发的免费开源web框架。
当初我使用自强学堂完成学习入门,推荐。
首先需要安装相应版本的Django,如1.11。
如果已经安装Anaconda,那么使用conda intsall django。即可完成安装。
一般情况,开发Django应用有以下几步:

1.1 创建一个工程

使用django-admin.py startproject project_name创建一个新工程,然后发现会自动新建一个文件夹,有着一定的模板。

image.png

可以看到目录结构基本如下:

hrinfo/
    manage.py
    hrifno/
        __init__.py
        settings.py
        urls.py
        wsgi.py

urls.py写一些url解析规则,setting.py包含一些全局配置信息,manage.py提供一些管理功能。
如进入工程目录,运行开发环境,测试Django是否工作正常。

image.png

一切正常,打开浏览器,输入127.0.0.1:8000,结果如下,说明Django工作正常。

image.png

1.2 新建一个应用App

进入工程目录后,输入python manage.py startapp hrskill,可以发现新建一个hrskill文件夹,包含若干文件:

image.png

这里最重要的是views.py文件,写网站后台处理逻辑。

1.3 修改配置setting.py文件

打开setting.py文件,增加App名称,如果希望关联数据库,如修改为Mysql
数据库,也可以配置,这里简化处理,这里不配数据库。

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'hrskill',  #新增配置
]

1.4 测试应用功能

通过修改urls.py 和 views.py来测试应用是否正常工作。比如我们想访问127.0.0.1:8000时,能够显示欢迎语句。
在views.py新增index函数:

from django.shortcuts import render
# Create your views here.
from django.http import HttpResponse
def index(request):
    return HttpResponse(u"欢迎光临!")

index()返回 HttpResponse 对象,可以显示在网页上,现在需要规定那个网址能使用这个函数,也就是需要在urls.py进行修改:

from django.conf.urls import url
from django.contrib import admin

from hrskill import views as hrskill_views #新增

urlpatterns = [
    url(r'^$', hrskill_views.index),  #新增url解析规则,什么网址对应什么函数
    url(r'^admin/', admin.site.urls),
]

其中网址写法符合正则表达式规则。
然后运行开发服务器 python manage.py runserver,打开浏览器,输入127.0.0.1:8000,结果如下:

image.png

1.5 使用模板(templates)进行交互

前面通过HttpResponse 来把内容显示到网页上,非常简单,能做的事也很少。
更多的我们是用模板templates的方法,就是事先写好html文件,然后直接返回这个html文件,这样就可以美化页面。
在hrskill文件夹下新建templates文件夹,然后新建一个index.html文件。
/templates/index.html内容如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>欢迎使用</title>
    </head>
    <body>
        欢迎跟着朱老师学Django.
    </body>
</html>

然后修改/hrskill/views.py如下:

from django.shortcuts import render
# Create your views here.
from django.http import HttpResponse  #可以注释掉
def index(request):
    return render(request, 'index.html')  #修改为这样即可
    #return HttpResponse(u"欢迎光临!")

然后可以刷新下网页(由于之前开发服务器一直运行,修改views.py会自动生效,无需重启,非常方便开发调式),结果已经更新。完美。


image.png

1.6 对模板进行渲染

上面功能还是很单一,只能返回写好的html文件。服务器更强大的应该是动态更新html文件,可以交互,比如不同用户访问,通过后台查询账号对应用户姓名,显示个性化欢迎语。
修改/templates/index.html内容如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>欢迎使用</title>
    </head>
    <body>
        {{name}},欢迎跟着朱老师学Django.
    </body>
</html>

修改/hrskill/views.py如下:

from django.shortcuts import render
def index(request):
    name = '朱锋'  #模拟获取后台获取用户姓名,这里省略
    return render(request, 'index.html',{'name':name})  #注意传name参数给前端

刷新网页,效果如下:

image.png

1.7 前端传参数给后台

很多时候,用户需要在前端网页输入某些关键字,然后传递给后台,后台根据这些参数进行处理,并返回结果。
这里简单模拟下用户在前端网页输入数字后,后台获取数字后加10返回,显示。
首先修改/templates/index.html内容如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>欢迎使用</title>
        <script src="../static/js/jquery-3.2.0.min.js"></script>
    </head>
    <body>
        <p id="p1">欢迎跟着朱老师学Django.</p>
        <form action="/search/" method="get">
            <input id="name" type="text" >
            <button id='sum' type="button">Go!</button>
        </form>
        <script>
            $(document).ready(function() {
                $("#sum").click(function() {
                    var ne_str = $("#name").val();
                    $.ajaxSettings.async = false;
                    $.getJSON("/search/",{"name":ne_str}, function(ret) {
                        document.getElementById("p1").innerHTML = ret['data']
                    });
                });
            });
            </script>
    </body>
</html>

由于使用Jquery,需要导入,将相应js文件放入/hrskill/static/js目录下(自己新建)。
同时上面html文件中增加了一个表单form及对应的动作,包括一个输入框input,一个提交按钮,通过JavaScript的Ajax技术获取后台数据,获取数据后修改p1内容。
此时刷新网页,效果如下:

image.png

此时点击Go应该没有任何反应,因为后台没进行后台修改。
接下来我们要修改后台处理逻辑。
首先增加一个url网址对应的views函数。
修改/hringo/urls.py如下:

from django.conf.urls import url
from django.contrib import admin
from hrskill import views as hrskill_views #新增
urlpatterns = [
    url(r'^$', hrskill_views.index),  #新增url解析规则,什么网址对应什么函数
    url(r'^search/$', hrskill_views.search),  #新增search Url对应view中函数
    url(r'^admin/', admin.site.urls),
]

此时点击Go,Django后台会报错,因为没有修改views.py。
修改/hrskill/views.py如下:

from django.shortcuts import render
# Create your views here.
from django.http import HttpResponse
import json  #新增json处理  
def index(request):
    name = '朱锋'  #模拟获取后台获取用户姓名,这里省略
    return render(request, 'index.html',{'name':name})  #修改为这样即可
def search(request): #新增search函数
    name = request.GET['name']
    ret = {}
    ret['data'] = '你输入的字符串是——{}'.format(name)
    return HttpResponse(json.dumps(ret),content_type='application/json')

现在我们在输入框输入任何字符串,点击“Go”,提交后看看效果。(如果没响应,建议重启开发服务器再试试)。
输入“今天天气真好”,然后点击Go,效果如下:

点击前.png

点击后.png

偶尔可能犯迷糊,参数传递有问题,重新加载正常,需要前端大牛帮忙解决


以上,我们已经简单介绍了Django,包括网页的基本交互,接下来就是丰富处理逻辑,美化前端页面,都在上面的框架内完成。

2 前端优化——AdminLTE、Bootstrap、Echarts

为了使前端页面更美观,也使得交互更近优化,我们可以学习一些基本的前端技术的使用,如:
Bootstrap简洁、直观、强悍的前端开发框架,让web开发更迅速、简单。
AdminLTE,是基于Bootstrap3高度可定制的响应式管理模板,是网页更简单。
Echarts开源免费的可视化图表。
上述工具,自己查看教程学习,下载相应的js文件,放置合适路径。因为我也只是会用

3 最终实现

回到一开始的项目需求,按人员或技能查询并用合适图表对比显示分析。
首先看看后台Mysql两个数据库结构:
staff_skill表格式,提供人员技能掌握情况。

image.png

training_record表样例,提供人员培训记录。

image.png

3.1 HTML文件设计

总共设计3个html页面,分别是首页index.html、人员查询页面searchstaff.html和技能查询页面searchskill.html。
下载相应的js、css文件,放到/hrskill/static/下合适路径。
index.html如下(说实话,可能有些css、js文件是不必要,但是我不知道):

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>欢迎使用</title>
        <link rel="stylesheet" href="../static/css/bootstrap.min.css">
        <link rel="stylesheet" href="../static/css/bootstrap-table.min.css">
        <link rel="stylesheet" href="../static/css/AdminLTE.min.css">
        <link rel="stylesheet" href="../static/css/_all-skins.min.css">
        <link rel="stylesheet" href="../static/css/blue.css">
        <link rel="stylesheet" href="../static/css/morris.css">
        <link rel="stylesheet" href="../static/css/jquery-jvectormap-1.2.2.css">
        <link rel="stylesheet" href="../static/css/datepicker3.css">
        <link rel="stylesheet" href="../static/css/daterangepicker.css">
        <link rel="stylesheet" href="../static/css/bootstrap3-wysihtml5.min.css">
        <link rel="stylesheet" href="../static/css/dataTables.bootstrap.css">
        <script src="../static/js/jquery-3.2.0.min.js"></script>
        <script src="../static/js/bootstrap.min.js"></script>
        <script src="../static/js/bootstrap-table.min.js"></script>
        <script src="../static/js/bootstrap-table-zh-CN.min.js"></script>
        <script src="../static/js/jquery.dataTables.min.js"></script>
        <script src="../static/js/dataTables.bootstrap.min.js"></script>
        <script src="../static/js/jquery.slimscroll.min.js"></script>
        <script src="../static/js/fastclick.min.js"></script>
        <script src="../static/js/app.min.js"></script>
        <script src="../static/js/demo.js"></script>
    </head>
    <body class="hold-transition skin-blue sidebar-mini">
        <div class="wrapper">
            <header class="main-header">
                <a href="/" class="logo">
                    <span class="logo-lg">人员技能管理系统</span>
                </a>
                <nav class="navbar navbar-static-top"></nav>
            </header>
            <aside class="main-sidebar">
                <section class="sidebar">
                    <ul class="sidebar-menu">
                        <li class="active treeview">
                            <a href="#">
                                <i class="fa fa-th"></i> <span>快速查询</span>
                                <span class="pull-right-container">
                                    <i class="fa fa-angle-left pull-right"></i>
                                </span>
                            </a>
                            <ul class="treeview-menu">
                                <li class="active">
                                    <a href="/searchstaff"><i class="fa fa-circle-o"></i>人员查询</a>
                                </li>
                            </ul>
                            <ul class="treeview-menu">
                                <li class="active">
                                    <a href="/searchskill"><i class="fa fa-circle-o"></i>技能查询</a>
                                </li>
                            </ul>
                        </li>
                    </ul>
                </section>
            </aside>
            <div class="content-wrapper"></div>
        </div>
    </body>
</html>

人员查询searchstaff.html文件如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>人员查询</title>
        <link rel="stylesheet" href="../static/css/bootstrap.min.css">
        <link rel="stylesheet" href="../static/css/bootstrap-table.min.css">
        <link rel="stylesheet" href="../static/css/AdminLTE.min.css">
        <link rel="stylesheet" href="../static/css/_all-skins.min.css">
        <link rel="stylesheet" href="../static/css/blue.css">
        <link rel="stylesheet" href="../static/css/morris.css">
        <link rel="stylesheet" href="../static/css/jquery-jvectormap-1.2.2.css">
        <link rel="stylesheet" href="../static/css/datepicker3.css">
        <link rel="stylesheet" href="../static/css/daterangepicker.css">
        <link rel="stylesheet" href="../static/css/bootstrap3-wysihtml5.min.css">
        <link rel="stylesheet" href="../static/css/dataTables.bootstrap.css">
        <script src="../static/js/jquery-3.2.0.min.js"></script>
        <script src="../static/js/bootstrap.min.js"></script>
        <script src="../static/js/bootstrap-table.min.js"></script>
        <script src="../static/js/bootstrap-table-zh-CN.min.js"></script>
        <script src="../static/js/jquery.dataTables.min.js"></script>
        <script src="../static/js/dataTables.bootstrap.min.js"></script>
        <script src="../static/js/jquery.slimscroll.min.js"></script>
        <script src="../static/js/fastclick.min.js"></script>
        <script src="../static/js/app.min.js"></script>
        <script src="../static/js/demo.js"></script>
    </head>
    <body class="hold-transition skin-blue sidebar-mini">
        <div class="wrapper">
            <header class="main-header">
                <a href="/" class="logo">
                    <span class="logo-lg">人员技能管理系统</span>
                </a>
                <nav class="navbar navbar-static-top"></nav>
            </header>
            <aside class="main-sidebar">
                <section class="sidebar">
                    <ul class="sidebar-menu">
                        <li class="active treeview">
                            <a href="#">
                                <i class="fa fa-th"></i> <span>快速查询</span>
                                <span class="pull-right-container">
                                    <i class="fa fa-angle-left pull-right"></i>
                                </span>
                            </a>
                            <ul class="treeview-menu">
                                <li class="active">
                                    <a href="/searchstaff"><i class="fa fa-circle-o"></i>人员查询</a>
                                </li>
                            </ul>
                            <ul class="treeview-menu">
                                <li class="active">
                                    <a href="/searchskill"><i class="fa fa-circle-o"></i>技能查询</a>
                                </li>
                            </ul>
                        </li>
                    </ul>
                </section>
            </aside>
            <div class="content-wrapper">
                <section class="content" >
                    <form action="/getstaff/" method="get">
                        <label>姓名:</label>
                        <input id="name" type="text" >
                        <button id='sum' class="btn btn-default" type="button">查询</button>
                    </form>
                    <p class="tab-p" id = "remark"></p>
                    <table id="table" data-checkbox-header="true" data-search="true"></table>
                    <table id="table_train" data-checkbox-header="true" data-search="true"></table>
                </section>
            </div>
        </div>

        <script>
        $(document).ready(function() {
            $("#sum").click(function() {
                var name_str = $("#name").val();
                //alert(name_str)
                $.ajaxSettings.async = false;
                $.getJSON("/getstaff/",{"username":name_str}, function(ret) {
                    document.getElementById("remark").innerHTML = ret['remark']
                    var cols = ret['cols']
                    var a_skills = ret['a_skills']
                    var cols_train = ret['cols_train']
                    var train_record = ret['train_record']
                    var $table = $('#table');
                    var $table_train = $('#table_train');
                    $table.bootstrapTable('destroy');
                    $table_train.bootstrapTable('destroy');
                    $(function() {
                        $table.bootstrapTable({
                            detailView: true,
                            data: a_skills,
                            dataType: "json",
                            search: true, //显示搜索框
                            columns: cols,
                            onExpandRow: function(index, row, $detail) {
                                InitSubTable(index, row, $detail);
                            }
                            });
                        InitSubTable = function(index, row, $detail) {
                            var b_skills = row.b_skills;
                            var cur_table = $detail.html('<table></table>').find('table');
                            $(cur_table).bootstrapTable({
                                data: b_skills,
                                columns: cols,
                            });
                        };
                    });
                    $(function(){
                            $table_train.bootstrapTable({
                            data: train_record,
                            dataType: "json",
                            search: true, //显示搜索框
                            columns: cols_train,
                        });
                    });
                });
            });
        });
        </script>
    </body>
</html>

通过输入被查询人员姓名,查询显示其技能和培训情况。
技能查询searchsskill.html文件如下:

未完待续,大家可以完成

通过输入被查询技能名称,查询显示人员掌握情况。

3.2 后台处理逻辑设置

修改urls.py如下:

from django.conf.urls import url
from django.contrib import admin
from hrskill import views as hrskill_views #新增
urlpatterns = [
    url(r'^$', hrskill_views.index),  #新增url解析规则,什么网址对应什么函数
    url(r'^searchstaff/$', hrskill_views.searchstaff),  #新增searchstaff函数
    url(r'^searchskill/$', hrskill_views.searchskill),  #新增searchskill函数
    url(r'^admin/', admin.site.urls),
]

修改views.py如下:

from django.shortcuts import render
from django.http import HttpResponse
import pandas as pd
import json  #新增json处理  
import pymysql #操作数据库
ip = '127.0.0.1'
user = 'root'
password = 'root'
db = 'hrinfo'
def index(request):
    name = '朱锋'  #模拟获取后台获取用户姓名,这里省略
    return render(request, 'index.html',{'name':name})  #修改为这样即可
def staffinfo(request):    
    return render(request, 'searchstaff.html')  
def skillinfo(request):
    return render(request, 'searchskill.html')  
#查询人员信息
def getstaff(request): 
    name = request.GET["username"]
    conn = pymysql.connect(host=ip, port=3306, user=user, passwd=password, db=db,charset='utf8')
    sql_skill = "SELECT * FROM staff_skill"
    skills = pd.read_sql(sql_skill,conn)
    skills = skills[skills['name']==name]
    ret = {}
    cols = []
    col = ['name','skill_name','date','no','primary','middle','senior']
    col_title = ['姓名','技能名称','认证日期','没听过','初级','中级','高级']
    for i in range(len(col)):
        col_f = {}       
        col_f['field'] = col[i]
        col_f['title'] = col_title[i]
        cols.append(col_f)
    ret['cols'] = cols
    a_skills = []
    for a_skill,group in skills.groupby(['a_skill']):
        row = {}
        date = max(group['skill_date'])
        num = len(group)
        no = len(group[group['skill_level']=='没听过'])
        primary = len(group[group['skill_level']=='初级'])
        middle = len(group[group['skill_level']=='中级'])
        senior = len(group[group['skill_level']=='高级'])
        row['name'] = name
        row['skill_name'] = a_skill
        row['date'] = date
        row['no'] = '{}/{}'.format(no,num)
        row['primary'] = '{}/{}'.format(primary,num)
        row['middle'] = '{}/{}'.format(middle,num)
        row['senior'] = '{}/{}'.format(senior,num)
        b_skills = []
        for b_skill ,b_group in group.groupby(['b_skill']):
            b_row = {}
            b_row['name'] = name
            b_row['skill_name'] = b_skill
            b_row['date'] = date
            num = len(b_group)
            no = len(b_group[b_group['skill_level']=='没听过'])
            primary = len(b_group[b_group['skill_level']=='初级'])
            middle = len(b_group[b_group['skill_level']=='中级'])
            senior = len(b_group[b_group['skill_level']=='高级'])
            b_row['no'] = '{}/{}'.format(no,num)
            b_row['primary'] = '{}/{}'.format(primary,num)
            b_row['middle'] = '{}/{}'.format(middle,num)
            b_row['senior'] = '{}/{}'.format(senior,num)
            b_skills.append(b_row)
        row['b_skills'] = b_skills
        a_skills.append(row)    
    ret['a_skills'] = a_skills
    
    sql_train = "SELECT * FROM training_record"
    trains = pd.read_sql(sql_train,conn)
    cj_trains = trains[trains['name']==name]
    zj_trains = pd.DataFrame()
    for i in trains.index:
        speaker = trains.loc[i]['speaker']
        if name in speaker:
            zj_trains = zj_trains.append(trains.loc[i],ignore_index=True)
    re_train = []
    if not zj_trains.empty:
        for topic in set(zj_trains['train_topic']):    
            topic_train = zj_trains[zj_trains['train_topic'] == topic][['train_date','days','train_class','train_loc']]
            topic_train = topic_train.drop_duplicates()
            row = dict(topic_train.iloc[0])
            row['name'] = name
            row['topic'] = topic
            row['isspeaker'] = '是'
            re_train.append(row)
    if not cj_trains.empty:
        for i in cj_trains.index:
            topic = cj_trains.loc[i]['train_topic']
            if zj_trains.empty or (topic not in set(zj_trains['train_topic'])):
                row = dict(cj_trains.loc[i][['train_date','days','train_class','train_loc']])
                row['name'] = name
                row['topic'] = topic
                row['isspeaker'] = '否'
                re_train.append(row)
    ret['train_record'] = re_train
    cols_train = []
    col_train = ['name','topic','train_date','days','train_class','train_loc','isspeaker']
    col_title_train = ['姓名','培训名称','培训日期','培训天数','培训类型','培训地点','是否为讲师']
    for i in range(len(col_train)):
        col_f = {}       
        col_f['field'] = col_train[i]
        col_f['title'] = col_title_train[i]
        cols_train.append(col_f)
    ret['cols_train'] = cols_train
    
    #写评语
    num = len(skills)
    senior = len(skills[skills['skill_level']=='高级'])
    middle = len((skills[skills['skill_level']=='中级']))
    primary = len((skills[skills['skill_level']=='初级']))
    no = len((skills[skills['skill_level']=='没听过']))
    num_zj = len(zj_trains)
    num_cj = len(zj_trains) + len(cj_trains)
    remark = "<br>{}同学,在全部的{}个知识点中,掌握情况大概如下:高级{}/{},中级{}/{},初级{}/{},没听过{}/{}。\
    近期主讲{}次培训,参加{}次培训。<br>".format(name,num,senior,num,middle,num,primary,num,no,num,num_zj,num_cj)
    ret['remark'] = remark
    return HttpResponse(json.dumps(ret),content_type='application/json')
 

由于时间关系,后台处理逻辑实现比较乱,建议单独一个模块,写各种函数,实现数据处理功能。
现在我们可以看看网页的效果
点击左侧“人员查询”:

image.png

输入姓名“XX”,点击查询:

image.png

由于时间关系,技能查询功能未实现,同时显示方式、评价都有很多优化的地方,使得交互更加友好。
期待你们的完善。
全部教程到此结束,砖已抛出,期待你们的玉。
Python真是零基础编程的神器!

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

推荐阅读更多精彩内容