Python

另类创建字典的方法

  • zip函数

    names = ['name','age','pay','job']
    values = ['sam smith',40,3000,'software']
    print(list(zip(names,values)))
  • 创建空字典

    names = ['name','age','pay','job']
    record = dict.fromkeys(names,"?")
    print(record)

路径

os.sys.path[0]获取当前 path 文件所在的文件夹
os.sys.argv[0]获取当前 path 文件的绝对路径

2018/12/12 posted in  Python

xpath 提取div标签所有文字信息

2018/12/11 posted in  Python

Scrapy 抓取网页数据

Scrapy 介绍

Scrapy,Python开发的一个快速、高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据。Scrapy用途广泛,可以用于数据挖掘、监测和自动化测试。
Scrapy吸引人的地方在于它是一个框架,任何人都可以根据需求方便的修改。它也提供了多种类型爬虫的基类,如BaseSpider、sitemap爬虫等,最新版本又提供了web2.0爬虫的支持。
Scrap,是碎片的意思,这个Python的爬虫框架叫Scrapy。

首先必须有python的环境,如果没有的话需要安装,目前python2.x已经不再更新,我使用的是python3的环境。

如果你已经有了python3的环境并且已经安装了pip3,那么安装scrapy只需要一行命令即可。

pip3 install scrapy

如果你还没有安装pip3的话,建议先安装pip3进行包管理。

pip3

pip 是 Python 包管理工具,该工具提供了对Python 包的查找、下载、安装、卸载的功能。
Python 2.7.9 + 或 Python 3.4+ 以上版本都自带 pip 工具。
你可以通过以下命令来判断是否已安装:

pip --version

如果你还未安装,则可以使用以下方法来安装:

$ curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py   # 下载安装脚本
$ sudo python get-pip.py    # 运行安装脚本

注意:用哪个版本的 Python 运行安装脚本,pip 就被关联到哪个版本,如果是 Python3 则执行以下命令:

$ sudo python3 get-pip.py    # 运行安装脚本。

一般情况 pip 对应的是 Python 2.7,pip3 对应的是 Python 3.x。

>>>pip3  -h#查看pip3的命令
Commands:
  install                     Install packages.
  download                    Download packages.
  uninstall                   Uninstall packages.
  freeze                      Output installed packages in requirements format.
  list                        List installed packages.
  show                        Show information about installed packages.
  check                       Verify installed packages have compatible dependencies.
  config                      Manage local and global configuration.
  search                      Search PyPI for packages.
  wheel                       Build wheels from your requirements.
  hash                        Compute hashes of package archives.
  completion                  A helper command used for command completion.
  help                        Show help for commands.

比较常用的就是install,list,一个是安装某个框架,另一个是列出所有安装的python框架。

demo 抓取豆瓣前250名的电影

新建scrapy项目

  1. scrapy startproject 项目名称
  2. cd 进入到项目名称
  3. cd 进入到 spiders
  4. scrapy genspider xxx_spider 域名 #生成爬虫类
    • 比如scrapy genspider douban_spider movie.douban.com

项目目录如下

  • douban
    • spiders
      • douban_spider.py #最重要的爬虫类
    • items.py #爬取的model类
    • middlewares.py #中间件 伪装useragent或者设置代理
    • pipelines.py #管道类 数据同步
    • settings.py #设置类 里面有一些项目的配置

运行项目

有两种方法

  1. 打开命令行工具 scrapy crawl xxx_spider
  2. 建议使用scrapy的cmdline工具

    • 在spiders文件夹下新建入口main.py

      from scrapy import cmdline
      cmdline.execute('scrapy crawl baidubaike_spider'.split())
      

      每次从这里面运行.py就行了,不需要每次都进到特定目录运行termianl终端程序。

主要爬虫类

douban_spider.py

# -*- coding: utf-8 -*-
import scrapy

class DoubanSpiderSpider(scrapy.Spider):
    name = 'douban_spider'#爬虫名
    allowed_domains = ['movie.douban.com']
    start_urls = ['https://movie.douban.com/top250']#入口url 扔到调度器里面
    #默认的解析方法
    def parse(self, response):
    #response就是网络请求之后的响应数据
    #主要的代码解析都在这个类中进行
       pass

HTML解析器

爬取之后的数据如果为html就需要用到html解析器,业界一般有三种方式进行解析

  • Beautiifulsoup
  • 正则匹配式
  • lxml中的xpath

有人做过三个方法的比较,大致结果如下

lxml beautifulsoup re
语法难易度 简单 简单 复杂
查找速度 较快 最快

所以这里我使用的是lxml的方式进行html解析,也推荐新手从这个方式开始入门。

lxml

lxml是通过xpath来查找,使用前需使用调用ertee.HTML()方法('()'内填HTML代码)生成一个可查找的对象。

常用xpath语法如下
// 两个斜杠为向下查找孙子标签
    
/ 一个斜杠为查找直接儿子标签
    
[] 方括号内填标签属性,如查找class属性为name的a标签,格式为a[@class="name"]
    
/text() 取出标签的内容,如查找网页中的 <a class="name">KAINHUCK</a> 中的KAINHUCK,格式为//a[@class="name"]/text()
    
/@attr 取出标签的属性,如查找网页中的 <a class="name">KAINHUCK</a> 中的class属性值name,格式为//a[@class="name"]/@class 

xpath 如何提取出div下面所有标签的文本内容

有时候一个div标签下会有不同的标签,如果只是单纯的使用上面的方法,并不能提取到div下面的所有文本内容,所以xpath提供了string(.)方法。

title = html.xpath('//dd[@class="lemmaWgt-lemmaTitle-title"]/h1/text()')[0]

summary = html.xpath('//div[@class="lemma-summary"]')[0].xpath('string(.)').strip()

#strip方法返回移除字符串头尾指定的字符生成的新字符串。    

分析抓取网站的html标签

进入chrome打开开发者调试工具

另外要使用lxml的方式进行解析,可以安装插件进行查找,到chrome的商城下载xpath,这样就可以直接看到结果了,以防抓取到的标签出错。

//div[@class="article"]//ol[@class="grid_view"]/li

这段语法用于找到class为article的div标签下的class为grid_view的ol的子孙标签下的li标签。

查找出来的结果是个包含25个元素的list

代码编写

然后进入到我们的代码中,导入lxml工具,以及DoubanItem

# -*- coding: utf-8 -*-
import scrapy
from lxml import etree
from douban.items import DoubanItem


class DoubanSpiderSpider(scrapy.Spider):
    name = 'douban_spider'#爬虫名
    allowed_domains = ['movie.douban.com']
    start_urls = ['https://movie.douban.com/top250']#入口url 扔到调度器里面
    #默认的解析方法
    def parse(self, response):
        #循环电影的条目
        html = etree.HTML(response.text)
        movie_list = html.xpath('//div[@class="article"]//ol[@class="grid_view"]/li')
        for item in movie_list:
            #item文件导入
            douban_item = DoubanItem()
            #写详细的xpath 进行数据的解析
            douban_item['serial_number'] = item.xpath('.//div[@class="item"]//em/text()')[0]
            douban_item['movie_name'] = item.xpath('.//div[@class="info"]//a/span[1]/text()')[0]
            content_list = item.xpath('.//div[@class="info"]//div[@class="bd"]/p[1]/text()')
            for content in content_list:
                content_s = "".join(content.split())
                douban_item['introduce'] = content_s

            douban_item['star']= item.xpath('.//div[@class="star"]/span[@class="rating_num"]/text()')[0]
            douban_item['comment'] = item.xpath('.//div[@class="star"]/span[4]/text()')[0]
            douban_item['description'] = item.xpath('.//p[@class="quote"]/span[1]/text()')[0]
            print(douban_item)
            yield douban_item #yeild到piplines里面 进行数据清洗 数据存储
        
        #解析下一页规则 获取后一页的xpath
        next_link = html.xpath('//span[@class="next"]/link/@href')

        if next_link:
            next_link = next_link[0]
            #yeild到调度器当中 后面给了回调函数
            yield scrapy.Request('https://movie.douban.com/top250'+next_link,callback=self.parse)

其中重要的有yield方法,把我们生成的model类传输到piplines里面进行数据的存储。

还有就是因为这只是一页的数据,想要抓取的250条数据,那就要进行多次抓取,进过分析发现只需要每次把后页的a标签的href拿到就可以了,通过xpath进行解析就是

#解析下一页规则 获取后一页的xpath
        next_link = html.xpath('//span[@class="next"]/link/@href')

最好需要yeild到调度器当中,因为是部分路径,所以要先进行路径的拼接,还要指定回调函数,就是请求之后进入的回调方法。

数据导出

在spiders文件夹下新建outputdata.py

#数据导出 也可以使用terminal 直接运行
from scrapy import cmdline
#数据导出到json
# cmdline.execute('scrapy crawl douban_spider -o output.json'.split())

#数据导出到csv格式
cmdline.execute('scrapy crawl douban_spider -o output.csv'.split())

2018/6/15 posted in  Python

python3 urllib 访问https网站

ssl._create_default_https_context=ssl._create_unverified_context
urllib urllib2 urllib3并不是进化关系
urllib和urllib2是相互独立的模版

列表

  • 列表添加新元素
    append()
  • 列表删除元素

    pop()方法总是删掉list的最后一个元素,并且它还返回这个元素

    pop()

    pop(2)删掉list中索引为2的元素

元组

元组和列表不同的是创建方式用()替代了[],而且元组一旦创建就不能改变。

同样可以根据索引取到元组的内容。

>>> t = (1)
>>> print t
1

创建单元组需要注意,因为创建元组的方式是()和运算优先级冲突了,所以上面的结果是1。

所以创建单元组要在第一个元素后自动添加一个',',就像下面的一样。

>>> t = (1,)
>>> print t
(1,)

还有需要注意的是元组也可以'可变‘,其实这种可变并不是真正的可变。比如下面的这个例子,元组中包括一个数组,数组就可以改变。

>>> t = ('a', 'b', ['A', 'B'])
>>> L = t[2]
>>> L[0] = 'X'
>>> L[1] = 'Y'
>>> print t
('a', 'b', ['X', 'Y'])

set

Python中什么是set
dict的作用是建立一组 key 和一组 value 的映射关系,dict的key是不能重复的。

有的时候,我们只想要 dict 的 key,不关心 key 对应的 value,目的就是保证这个集合的元素不会重复,这时,set就派上用场了。

set 持有一系列元素,这一点和 list 很像,但是set的元素没有重复,而且是无序的,这点和 dict 的 key很像。

创建 set 的方式是调用 set() 并传入一个 list,list的元素将作为set的元素:

>>> s = set(['A', 'B', 'C'])
>>> print s
set(['A', 'C', 'B'])

Python之 访问set

由于set存储的是无序集合,所以我们没法通过索引来访问。

访问 set中的某个元素实际上就是判断一个元素是否在set中。

例如,存储了班里同学名字的set:

>>> s = set(['Adam', 'Lisa', 'Bart', 'Paul'])

我们可以用 in 操作符判断:

Bart是该班的同学吗?

>>> 'Bart' in s
True

Python之 遍历set

由于 set 也是一个集合,所以,遍历 set 和遍历 list 类似,都可以通过 for 循环实现。

直接使用 for 循环可以遍历 set 的元素:

>>> s = set(['Adam', 'Lisa', 'Bart'])
>>> for name in s:
...     print name
... 
Lisa
Adam
Bart

Python之 更新set

add()添加
remove()删除

Python之 unicode编码

在字符串前面加上u 比如
>>>a = u"123"
>>>type(a)
>>>unicode

>>>b = "123"
>>>type(b)
>>>str
2018/5/10 posted in  Python

Django入门 — 建立简易博客以及ORM关系介绍

  • 开源的Python Web框架
  • MVC模式

使用Django 必须先安装Python,推荐安装3.0版本以上的Python3
然后再用pip安装工具安装Django
由于我安装的是python3 所以我的pip工具是pip3
安装命令pip3 install django==2.0
最后选择适合自己的IDE
我使用的是VSCode

优点

  • 开发效率高
  • 功能强大,丰富的第三方插件
  • 重视安全,避免安全漏洞

命令语句django-admin 检查django是否成功安装。

屏幕快照 2019-05-20 上午11.19.16

  • startproject # 创建一个django项目
  • startapp # 创建一个django应用
  • check # 检验项目完整性
  • runserver # 本地简易运行django项目
  • shell # 进入django项目的python shell环境
  • test # 执行django用例测试

数据库相关

  • makemigrations # 创建模型变更的迁移文件
  • migrate # 执行上一个命令创建的迁移文件
  • dumpdata # 把数据库数据导出到文件
  • loaddata # 把文件数据导入到数据库

Django 应用 VS Django项目

首先要明白Django项目和应用的区别

  • 1个Django项目就是一个基于Django的web应用
  • 1个Django应用就是一个可重用的python软件包
  • 1个Django应用可以自己管理模型视图模版路由和静态文件
  • 1个Django项目可以包含一组配置和若干个Django应用。

创建一个Django项目

  1. 创建一个项目

    django-admin startproject django_intrduction
    
  2. 用VSCode打开项目文件夹

    结构目录如下

    Django_instrduction

    • Django_instrduction

      • init.py//项目初始化
      • setting.py//🌟项目配置文件
      • urls.py//项目路由配置文件
      • wsgi.py//python服务器网关接口
    • manage.py//项目管理文件

  3. 运行项目 终端命令python3 manage.py runserver

Django项目重要文件介绍

setting.py
import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))#项目根目录


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '7bet#*gq%**^7*)5m%)avx&sg6yv_^&t5b!@8+$(&of&_^1wv)'#项目安全码

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True #不要在正式环境中打开 如果打开的话异常会抛到前端

ALLOWED_HOSTS = []
#ALLOWED_HOSTS = ['localhost'] 只允许host是数组中的内容的地址访问我们的网站 其他地址都屏蔽了


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blog.apps.BlogConfig',#自己创建的应用要写在这里面 才能被识别
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'django_intrduction.urls'

#django中的模板就是一个个的html文件
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]


创建一个Django应用

  1. 创建一个应用

    运行项目 终端命令python3 manage.py startapp 应用名

  2. 用VSCode打开项目文件夹

    结构目录如下

    Django_instrduction

    • 应用名

      • views.py//🌟执行响应的代码所在模块,大部分代码都在这里
      • models.py//定义应用模型、使用orm框架
      • apps.py //声明应用的地方
      • admin.py //定义admin模块管理的地方、后台管理配置
      • tests.py //自动化测试模块,编写测试用例的地方
      • urls.py //(自行创建)管理应用路由的地方
    • Django_instrduction

      • init.py//项目初始化
      • setting.py//项目配置文件
      • urls.py//项目路由配置文件
      • wsgi.py
    • manage.py//项目管理文件

Django HelloWorld

Django 视图

大部分代码都写在views.py当中,所以编辑views是非常重要的,

  • 每个响应对应一个函数,函数必须返回一个响应。
  • 函数必须存在一个参数,一般约定为request
  • 每个响应函数对应一个url
//views.py
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
def hello_world(request):
    return HttpResponse("hello world")

Django 路由

  • 每个URL都以url的形式写出来
  • url函数放在urlpatterns列表中
应用路由
from django.urls import path,include

import blog.views


urlpatterns = [
    path("hello_world",blog.views.hello_world)
]
项目路由
from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('blog/', include("blog.urls")),
]

概念介绍及实战

Django 模型

模型层简介
模型层是什么
  • 位于视图层和数据库之间
  • python对象和数据表之间转换
为什么需要模型层
  • 屏蔽不同的数据库之间的差异
  • 开发者更加专注于业务逻辑的开发
  • 提供很多便捷工具有助开发
创建博客文章模型
设计播客文章模型
  • 文章标题——文本类型
  • 文章摘要——文本类型
  • 文章内容——文本类型
  • 唯一id标记——int类型(自增、主键)
  • 发布日期——日期类型
模型层常用字段
  • 数字类型:
    • IntegerField()#整数 11个字节
    • BigIntegerField()#整数 20个字节
    • PositiveIntegerField()#正整数 10个字节
    • SmallIntegerField()#整数 6个字节
    • PositiveSmallIntegerField()#正整数 5个字节
  • 文本类型:
    • TextField()#longtext
    • CharField()#varchar
    • 布尔类型
    • BooleanField()#允许为空
    • NullBooleanField()#不允许为空
  • 浮点型
    • FloatField()
    • DecimalField()#指定整数和小数各多少位
  • 日期类型:
    • DateTimeField()#年月日时分秒
    • DateField()# 年月日
    • DurationField()#一段时间 int类型
  • 自增ID:
    • AutoField()
    • BigAutoField()//接受更大的值
  • 主键定义:primary_key属性
  • 二进制数据

    • BinaryField()
  • 其他类型

    • EmailField()#邮箱
    • ImageField()#图片
    • FileField()#文件
    • FilePathField()#文件路径
    • UrlField()
    • UUIDField()
    • GenericIPAddressField()#ip地址
模型层关系型字段
  • 一对一(OneToOneField)
  • 多对一(ForeignKey)
  • 多对多(ManyToManyField)
生成数据表
  1. 命令行进入到manage.py同级目录
  2. 执行python3 manage.py makemigrations appname(可选)
  3. 执行python3 manage.py migrate
Demo
  1. 在应用的 models.py 定义模型
from django.db import models
# Create your models here.
class Aritcle(models.Model):
    
    aritcle_id = models.AutoField(primary_key=True)
    title = models.TextField()
    brief_content = models.TextField()
    content = models.TextField()
    publish_date = models.DateTimeField(auto_now=True)
    
    def __str__(self):
        return self.title

# 演示关系型model      
class A(models.Model):
    onetoone = models.OneToOneField(Aritcle)

class B(models.Model):
    foreign = models.ForeignKey(A)

class C(models.Model):
    manytomany = models.ManyToManyField(B)
       
  1. 然后迁移模型定义到数据库当中

    • python3 manage.py makemigrations appname
    Alexs-MacBook-Air:django_intrduction alexwee$ python3 manage.py makemigrations blog
    Migrations for 'blog':
    blog/migrations/0001_initial.py
    - Create model Aritcle
  2. 运行迁移文件 把迁移文件的内容同步到数据库中

    • python3 manage.py migrate appname
    Alexs-MacBook-Air:django_intrduction alexwee$ python3 manage.py migrate  blog
    Operations to perform:
    Apply all migrations: blog
    Running migrations:
    Applying blog.0001_initial... OK
Django shell

Python shell 用于交互式的python编程
Django shell 也类似继承django项目环境

为什么要使用django shell
  • 临时性操作使用django shell更加方便
  • 小范围的debug更简单,不需要运行整个项目来测试
  • 方便开发 方便调试 方便debug
demo

使用django shell 新建文章

  1. python3 manage.py shell进入shell 环境

    Python 3.7.1 (v3.7.1:260ec2c36a, Oct 20 2018, 03:13:28) 
    [Clang 6.0 (clang-600.0.57)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    (InteractiveConsole)
    >>>
  2. 在shell环境新建文章并保存到数据库

    from blog.models import Aritcle
    >>> a = Aritcle()
    >>> a.title = "test django shell"
    >>> a.brief_content = "test django shell by maweefeng"
    >>> a.content = "test django shell new ariticle main content"
    >>>
    >>>
    >>>
    >>> print(a)
    Aritcle object (None)
    >>> a.save()//保存到数据库
    >>>
  3. 验证文章是否保存到数据库

    >>> ariticle = Aritcle.objects.all()//取出所有文章
    >>> aricle = ariticle[0]//取到第一篇文章
    >>> print(aricle.title)
    <class 'django.db.models.fields.TextField'>
    >>>
    >>> print(aricle)
    Aritcle object (1)
    >>> print(aricle.content)
    <class 'django.db.models.fields.TextField'>
    >>>
django admin模块
django admin模块是什么
  • 是一个后台管理工具,不需要用户开发后台管理工具
  • 可以读取定义的模型元数据,提供强大的管理使用页面
为什么要使用django admin模块
  • django shell 新建文章太复杂了
  • 管理页面是基础设施中重要的部分
  • 认证用户,显示管理模型,校验输入等功能类似
使用方法
  • 创建管理员用户 python3 manage.py createsuperuser
* Alexs-MacBook-Air:django_intrduction alexwee$ python3 manage.py createsuperuser
Username (leave blank to use 'alexwee'): maweefeng
address: 
Password: 
Password (again): 
Superuser created successfully.
Alexs-MacBook-Air:django_intrduction alexwee$ 

但是没有看到刚才新建的文章模型,是因为我们还没有把模型注册到admin中,进入IDE中的应用目录下的admin.py

from django.contrib import admin

# Register your models here.

from .models import Aritcle

admin.site.register(Aritcle)  

回到浏览器刷新 就有了新的分组

屏幕快照 2019-05-21 上午11.20.06

实现播客数据返回页面

类似于之前返回的helloworld项目

  1. 应用视图 views.py

    from django.shortcuts import render
    from django.http import HttpResponse
    from blog.models import Summary
    # Create your views here.
    def hello_world(request):
    return HttpResponse("hello world")
    def ariticle_content(request):
    summary = Summary.objects.all()[0]
    title = summary.summary_title
    content = summary.summary_content
    summary_id = summary.summary_id
    pubdate = summary.publish_date
    return_str = 'title:%s summary_content:%s summary_id:%s publicdate:%s'%(title,content,summary_id,pubdate)
    return HttpResponse(return_str)
  2. 应用路由 urls.py

    from django.urls import path,include
    import blog.views
    urlpatterns = [
    path("hello_world",blog.views.hello_world),
    path("content",blog.views.ariticle_content)
    ]
  3. 项目路由 urls.py

    from django.contrib import admin
    from django.urls import path,include
    urlpatterns = [
    path('admin/', admin.site.urls),
    path('blog/', include("blog.urls")),
    ]

Django视图与模板

使用Bootstrap实现静态博客页面

页面布局设计

  • 博客首页
  • 文章详情页

Bootstrap 以及 Bootstrap的栅格系统

Bootstrap是来自美国twitter的前端框架,提供非常多的控件以及源码,栅格系统就是把web页面分成几等份排列的方式。

创建模板文件夹并实现静态页面

在应用文件夹内部新建文件夹templates,然后在里面新建html文件,这是很关键的一步

⚠️注意事项

还有需要注意的是最好在templates文件夹中再新建应用名所属的文件夹,然后在应用名所属的文件夹中新建html文件,这是因为Django查找templates是按照INSTALLED_APPS中的添加顺序查找templats,所以不同应用下的templates的html同名会造成冲突。

认识Django的模版系统

python的视图文件不适合编码html,因为页面设计改变需要修改python代码,比较复杂。另外网页的逻辑和视图应该分开设计。

模版系统的表现形式是文本,分离文档的表现形式和表现内容,模版系统定义了特有的标签占位符。

学习模版系统的基本语法

  1. 变量标签:{{变量}}
  2. for循环标签:{% for x in list %},{% endfor %}

      <ul>
        {% for item in list%}
    <li>{{item}}</li>
    {% endfor%}
    </ul>
  3. if-else标签:{% if %},{% else %},{%endif%}

     {% if true %}
            <p>it is true part</p>
    {%else%}
    <p>it is false part</p>
    {% endif %}

使用模版系统渲染博客页面

render渲染函数

  • render() 函数中支持一个dict类型的参数
  • 该字典是后台传递到模板的参数,键为参数名
  • 在模板中使用{{参数名}}来直接使用

    def render(request, template_name, context=None, content_type=None, status=None, using=None)
    Return a HttpResponse whose content is filled with the result of calling django.template.loader.render_to_string() with the passed arguments.
    

编写django应用的views.py

from django.shortcuts import render
from django.http import HttpResponse
from blog.models import Summary,Article
    
def get_index_page(request):
    all_ariticle = Summary.objects.all()
    return render(request,'blog/index.html',{'aritcle_list':all_ariticle})

实现文章详情页面跳转

Django中的超链接

1⃣️ 直接拼接

直接在a标签的href中拼接需要点击跳转的路径 在html的表现形式为

<a href="/blog/detail/{{item.summary_id}}"></a>
2⃣️ 参数以及命名空间
  • href后面是目标地址
  • templates中可以用"{% url 'app_name:url_name' param%}"
  • 其中app_name 和 url_name都在url中配置。
url函数的名称参数
  • 项目urls.py 写在include()的第二个参数位置,namespace='blog',还要在第一个参数中传入一个包含appname的元组 见下面demo
  • 应用下则写在url()的第三个参数位置,写上name=‘方法名’
  • 主要取决于是否使用include引用了另一个url配置文件
Demo
  • django项目的urls.py

      from django.contrib import admin
    from django.urls import path,include
    urlpatterns = [
    path('admin/', admin.site.urls),
    path('blog/', include(("blog.urls",'blog'),namespace='blog')),
    ]
  • django应用的urls.py

    from django.urls import path,include
    import blog.views
    urlpatterns = [
    path("hello_world",blog.views.hello_world),
    path("index",blog.views.get_index_summary_page),
    path("detail/<int:article_id>",blog.views.get_index_page,name='get_index_page')
    ]
  • django应用的views.py

    def get_detail_page(request,summary_id):
        all_ariticle = Summary.objects.all()
    cur_article = None
    for aritcle in all_ariticle:
    if aritcle.summary_id == summary_id:
    cur_article = aritcle
    break
    sectionList = cur_article.summary_content.split('\n')
    return render(request,'blog/detail.html',{'curr_aritcle':cur_article,'section_list':sectionList})
  • html超链接部分代码写法

     <a href="{% url 'blog:get_detail_page' item.summary_id %}"></a>
    

实现分页功能

参数request包含了一些get以及post的信息。

  • django应用的views.py

    def get_index_page(request):
        # 适用与/index?page=1之类的网络请求
    page = request.GET.get('page')
    if page:
    page = int(page)
    else:
    page = 1
    all_ariticle = Summary.objects.all()
    return render(request,'blog/index.html',{'aritcle_list':all_ariticle})

django分页组件Paginator

  • 在views.py中引入分页组件

    from django.core.paginator import Paginator
    def get_index_page(request):
    # 适用与/index?page=1之类的网络请求
    page = request.GET.get('page')
    if page:
    page = int(page)
    else:
    page = 1
    all_ariticle = Summary.objects.all()
    paginator = paginator(all_ariticle,3)
    page_aritcle_list = paginator.page(page)
    page_num = paginator.num_pages
    if page_aritcle_list.has_next():
    next_page = page + 1
    else:
    next_page = page
    if page_aritcle_list.has_previous():
    previous_page = page - 1
    else:
    previous_page = page
    return render(request,'blog/index.html',{
    'aritcle_list':page_aritcle_list,
    'page_num':range(1,page_num+1),
    "curr_page":page,
    'next_page':next_page,
    'previous_page':previous_page
    }
    )

补充部分 ORM

ORM

  • 对象关系映射(object relation mapping)
  • 实现了对象和数据库之间的映射
  • 隐藏了数据访问的细节,不需要编写sql语句

如何删除一个模型类

  1. 首先删除models.py中模型类的代码
  2. 删除模型类在migrations文件夹中对应的文件
  3. 删除django_migrations中对应的生成记录
  4. 再删除模型对应的数据表

切记不要直接把数据库整个删掉再生成,尤其是当数据库中有数据的时候。

如何导入数据

  1. django shell

    from blog.models import Aritcle
    >>> a = Aritcle()
    >>> a.title = "test django shell"
    >>> a.brief_content = "test django shell by maweefeng"
    >>> a.content = "test django shell new ariticle main content"
    >>> a.save()//保存到数据库
  2. 脚本批量导入

    import os
    import sys
    import random
    import django
    from datetime import date
    # 在当前项目中运行该python脚本
    project_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    sys.path.append(project_path)
    os.environ['DJANGO_SETTINGS_MODULE'] = 'Django_ORM.settings'
    django.setup()
    from orm.models import Aritcle
    #上面这行必须在django.setup()之后
    def import_data():
    for i in [1,2,3,4,5,6,7,8,9,10]:
    Aritcle.objects.create(title = '这个是标题%s'%(i),brief_content='这个是简介',content='这个是内容我们都有一个家名字叫中国')
    return True
    if __name__ == "__main__":
    if import_data():
    print('插入数据成功')
  3. fixtures
    使用django serialization 生成 model

    • 终端命令导出数据python3 manage.py dumpdata > orm.json生成了一个json文件

    • 然后从数据库中删除部分数据

    • 执行命令从json中导入数据 python3 manage.py loaddata orm.json

    • 数据库中重新出现了刚才删除的数据(因为从json中重新导入了数据)

  4. 数据库层面的导入数据

如何导出数据

  1. 导出fixtures能识别的json文件

    • 终端命令导出数据python3 manage.py dumpdata > orm.json生成了一个json文件
  2. 导出其他格式的文件
    pcharm自带的数据库工具,单选某个表右键dump data to file
    nivacate datum等数据库工具导出数据

  3. 数据库层面的导出数据

ModelsAPI

查询集介绍

  1. 查询 过滤 检索

    Aritcle.objects.all()#返回所有结果
    Aritcle.objects.get(title='这是一个标题')#返回一个结果 多条则会报错
    Aritcle.objects.filter(star__gte = 500)#queryset可以是多条结果 fans >=500的结果
  2. 字段数据匹配 大小写敏感

    teacher = Aritcle.objects.filter(star__in=[555,1231])
    teacher = Aritcle.objects.filter(title__contains='a')
    
  3. 结果切片 排序 链式查询

    Aritcle.objects.all()[:1]
    Aritcle.objects.all().order_by('star')#升序排序
    Aritcle.objects.all().order_by('-star')#降序排序
    Aritcle.objects.filter(star__gte = 500).order_by('-star')#链式查询
  4. 查看执行的原生SQL xxx.query

    print(str(Aritcle.objects.filter(star__gte = 500).order_by('-star').query))
    

返回新的QuerySet的API

  1. all() filter() order_by() exclude()去掉某个model reverse()反转 distinct()去重

    Aritcle.objects.all().exclude(title = 'title')
    Aritcle.objects.all().exclude(title = 'title').reverse()
    
  2. extra() defer() only() 实现字段别名 排除一些字段 选择一些字段

    Aritcle.objects.all().extra(select={'article_title'='title'})
    Aritcle.objects.all().only('title','star').query()
    
  3. dates() datetimes() 根据时间日期获取查询集

    Aritcle.objects.dates('publish_date','month',order ='DESC')
    
  4. union() intersection() difference() 并集 交集 差集

    a_500 = Aritcle.objects.filter(star__gte = 500)
    a_200 = Aritcle.objects.filter(star__lte = 200)
    print(a_500.union(a_200))
    print(a_500.intersection(a_200))
    print(a_500.difference(a_200))
  5. select_related() 一对一 多对一查询优化 prefetch_related() 一对多 多对多查询优化 反向查询

    Aritcle.objects.all().select_related('author')
    Audiences.objects.filter(star__gte = 500).prefetch_related('article')
    
  6. annotate() 使用聚合计数 求和 平均数 raw()执行原声sql

    # 对每个文章关联的作者的评🌟进行统计
    Aritcle.objects.values('author').annotate(vol=Sum('star'))
    # vol star 总和
    Aritcle.objects.values('author').annotate(ave=Avg('star'))
    # ave star 求平均值
  7. values() values_list() 获取字典或者元祖形式的queryset

    Aritcle.objects.values('title','star')
    Aritcle.objects.values_list('title','star')
    

不返回QuerySet的API

  1. 获取对象 get()获取单个对象 get_or_create()获取或者创建 first() last() latest() earliest() in_bulk()

  2. 创建对象 create() bulk_create() create_or_update() 创建 批量创建 创建或更新

  3. 更新对象 update() update_or_create()更新 更新或创建

    Aritcle.objects.filter(star__gte = 500).update(star=20)
    
  4. 删除对象delete() 使用filter过滤

    Aritcle.objects.filter(star__gte = 500).delete()
    
  5. 其他操作exists() count() aggregate()判断是否存在 统计个数 聚合

    Aritcle.objects.filter(star = 500).exists()
    Aritcle.objects.count()
    Aritcle.objects.aggregate(Max('star',Min('star'),Avg('star')))

自定义聚合查询 实现group_concat

在models.py 中自定义继承自models.Aggregate 的类GroupConcat

class GroupConcat(models.Aggregate):
    function = 'Group_Concat'
    template = '%(fuction)s(%(distinct)s%(expressions)s%(ordering)s%(separator)s)'

    def __init__(self,expression,distinct=False,ordering=None,separator=',',**extra):
        super(GroupConcat,self).__init__(expression,
        distinct='DISTINCT' if distinct else '',
        ordering = 'ORDER BY %s' % ordering if ordering is not None else '',
        separator = 'SEPARATOR "%s"'%separator,
        output_field=models.CharField(),**extra)


views.py

Aritcle.objects.values('author').annotate(title=GroupConcat('title',distinct=True,ordering='title ASC',separator='-'))
2018/4/20 posted in  Python

python开发 端口占用问题

当你该端口被其他进程占用时,那就需要你修改为一个未使用的端口号重新运行。
是运行程序没有通过 C正常结束而是直接关闭Terminal或者其他非正常途径退出的时候。
解决方法:
1.终端输入:lsof -i:(port),查看占用该端口号的进程,一般就是刚未正常退出的进程。

例如 lsof -i:8000

2.然后kill掉该PID的进程,重新运行。
sudo kill 8000

2018/4/10 posted in  Python