Django与数据库中操作对应

在SQL中,很多关键词在删、改、查时都是可以用的,如order by、 like、in、join、union、and、or、not等等,我们以查询为例,说一下django如何映射SQL的这些关键字的(查、删、改中这些关键字的使用基本相同)。

No1 F类(无对应SQL关键字)

前面提到的filter/exclude中的查询参数值都是常量,如果我们想比较model的两个字段怎么办呢?Django也提供了方法,F类,F类实例化时,参数也可以用双下划线,也可以逻辑运算,如下

>>> from django.db.models import F
>>> Entry.objects.filter(n_comments__gt=F('n_pingbacks'))
>>> from datetime import timedelta
>>> Entry.objects.filter(mod_date__gt=F('pub_date') + timedelta(days=3))
>>> Entry.objects.filter(authors__name=F('blog__name'))

No2 Q类(对应and/or/not)

如果有or等逻辑关系呢,那就用Q类,filter中的条件可以是Q对象与非Q查询混和使用,但不建议这样做,因为混和查询时Q对象要放前面,这样就有难免忘记顺序而出错,所以最好如果使用Q对象,那就全部用Q对象。Q对象也很简单,就是把原来filter中的各个条件分别放在一个Q()即可,不过我们还可以使用或与非,分别对应符号为”|”和”&”和”~”,而且这些逻辑操作返回的还是一个Q对象,另外,逗号是各组条件的基本连接符,也是与的关系,其实可以用&代替(在python manage.py shell测试过,&代替逗号,执行的SQL是一样的),不过那样的话可读性会很差,这与我们直接写SQL时,各组条件and时用换行一样,逻辑清晰。

from django.db.models import Q
>>> Poll.objects.get( Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
question__startswith='Who') #正确,但不要这样混用
>>> Poll.objects.get( Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
Q(question__startswith='Who')) #推荐,全部是Q对象
>>> Poll.objects.get( (Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))&
Q(question__startswith='Who')) #与上面语句同意,&代替",",可读性差

Q类中时应该可以用F类,待测试。

No3 annotate(无对应SQL关键字)

函数原型annotate( *args , **kwargs )

返回QuerySet

往每个QuerySet的model instance中加入一个或多个字段,字段值只能是聚合函数,因为使用annotate时,会用group by,所以只能用聚合函数。聚合函数可以像filter那样关联表,即在聚合函数中,Django对OneToOne、OneToMany、ManyToMany关联查询及其反向关联提供了相同的方式,见下面例子。

>>> from django.contrib.auth.models import User
>>> from django.db.models import Count
#计算每个学员的usertask数量,字段命名为ut_num,返回的QuerySet中的每个object都有
#这个字段在UserTask中定义User为外键,在Task中定义与User是ManyToMany,中间表为
#notification_task_users
>>> a = User.objects.filter(is_active=True, usertask__is_active=True). annotate(n=Count('usertask')) #一对多反向连接。User与UserTask是onetomany关联
>>> b = User.objects.filter(is_active=True, task__is_active=True).annotate(n=Count('task__name')) #多对多反向连接,User与Task是manytomany关联
>>> len(a) #这里才会对a求值
>>> len(b)

a对应的SQL语句为(SQL中没有为表起别名,u、ut是我加的):

SELECT AUTH.USER.*,COUNT(UT.ID) AS UT_NUM
FROM AUTH_USER AS U
LEFT OUTER JOIN UT ON U.ID = UT.USER_ID
WHERE U.IS_ACTIVE=TRUE AND UT.IS_ACTIVE=TRUE
GROUP BY U.*

b对应的SQL语句为(SQL中没有为表起别名,u、t、r是我加的):

SELECT U.*,COUNT(T.NAME) AS N
FROM AUTH_USER AS U
LEFT OUTER JOIN NOTIFICATION.TASK_USERS AS R ON U.ID=R.USER_ID
LEFT OUTER JOIN NOTIFICATION_TASK AS T ON R.TASK_ID=T.ID
WHERE T.IS_ACTIVE=TRUE AND U.IS_ACTIVE=TRUE
GROUP BY U.*

No4 order_by–对应order by

函数原型 order_by(**kwargs)

返回QuerySet

正向的反向关联表跟filter的方式一样。如果直接用字段名,那就是升序asc排列;如果字段名前加-,就是降序desc

No5 distinct–对应distinct

原型 distinct()

一般与values()、values_list()连用,这时它返回ValuesQuerySet、ValuesListQuerySet

这个类跟列表很相似,它的每个元素是一个字典。它没有参数(其实是有参数的,不过,参数只在PostgreSQL上起作用)。使用方法为

>>> a=Author.objects.values_list(name).distinct()
>>> b=Author.objects.values_list(name,email).distinct()

对应的SQL分别为

SELECT DISTINCT NAME
FROM AUTHOR

SELECT DISTINCT NAME,EMAIL
FROM AUTHOR

No6 values()和values_list()–对应’select 某几个字段’

函数原型values(*field), values_list(*field)

返回ValuesQuerySet, ValuesListQuerySet

Author.objects.filter(**kwargs)对应的SQL只返回主表(即Author表)的所有字段值,即使在查询时关联了其它表,关联表的字段也不会返回,只有当我们通过Author instance用关联表时,Django才会再次查询数据库获取值。当我们不用Author instance的方法,且只想返回几个字段时,就要用values(),它返回的是一个ValuesQuerySet对象,它类似于一个列表,不过,它的每个元素是字典。而values_list()跟values()相似,它返回的是一个ValuesListQuerySet,也类型于一个列表,不过它的元素不是字典,而是元组。一般的,当我们不需要model instance的方法且返回多个字段时,用values(*field),而返回单个字段时用values_list(‘field’,flat=True),这里flat=True是要求每个元素不是元组,而是单个值,见下面例子。而且我们可以返回关联表的字段,用法跟filter中关联表的方式完全相同。

>>> a = User.objects.values('id','username','userex__account_name')
>>> type(a)
<class 'django.db.models.query.ValuesQuerySet'>
>>> a
[{'id':0,'username':u'test0',' userex__account_name': u'mlp-gikoo-test0@gk.cn'},{'id':1,'username':u'test1',
'userex__account_name': u'mlp-gikoo-test1@gk.cn'},{'id':2,'username':u'test2', ' userex__account_name': u'mlp-gikoo-test2@gk.cn'}]
>>> b= User.objects.values_list('username',flat=True)
>>> b
[u'gikoo', u'test1' ,u'test2']

No7 select_related()–对应返回关联表字段,嵌套。

这部分要比SQL语句强大

原型select_related(*filed)

返回QuerySet

它可以指定返回哪些关联表model instance,这里的field跟filter()中的键一样,可以用双下划线,但也有不同。可以参考 ForeignKey 或者 OneToOneField获取对应信息。QuerySet中的元素中的OneToOne关联及外键对应的是都是关联表的一条记录,如my_entry=Entry.objects.get(id=1),my_entry.blog就是关联表的一条记录的对象。select_related()不能用于OneToMany的反向连接,和ManyToMany,这些都是model的一条记录对应关联表中的多条记录。前面提到了对于a = Author.objects.filter(**kwargs)这类语句,对应的SQL只返回主表,即Author的所有字段,并不会返回关联表字段值,只有当我们使用关联表时才会再查数据库返回,但有些时候这样做并不好。看下面两段代码,这两段代码在1.1中提到过。在代码1中,在遍历a前,先执行a对应的SQL,拿到数据后,然后再遍历a,而遍历过程中,每次都还要查询数据库获取关联表。代码2中,当遍历开始前,先拿到Entry的QuerySet,并且也拿到这个QuerySet的每个object中的blog对象,这样遍历过程中,就不用再查询数据库了,这样就减少了数据库读次数。

代码1

a = Entry.objects.all()
for e in a:
    print (e.blog.name)

代码2

a = Entry.objects.select_related('blog')
for e in a:
    print (e.blog.name)

No8 prefetch_related (*field) –对应返回关联表字段

嵌套这部分要比SQL语句强大

函数原型 prefetch_related (*field)

返回的是QuerySet

可以用双下划线。前面提到select_related不能用于OneToMany的反向连接,及ManyToMany的情况,这部分由prefetch_related()来实现。其实,prefetch_related()也能做select_related()的事情,但由于策略不同,可能相比select_related()要低效一些,所以建议还是各管各擅长的。select_related是用select ……join来返回关联的表字段,而prefetch_related是用多条SQL语句的形式查询,一般,后一条语句用IN来调用上一句话返回的结果。

class Restaurant(models.Model):
    pizzas = models.ManyToMany(Pizza, related_name='restaurants')
    best_pizza = models.ForeignKey(Pizza, related_name='championed_by')
>>> Restaurant.objects.prefetch_related('pizzas__toppings')
>>> Restaurant.objects.select_related('best_pizza').prefetch_related('best_pizza__toppings')

先用select_related查到best_pizza对象,再用prefetch_related 从best_pizza查出toppings

至此,我们总结了查询数据库时,返回的数据形式,主要有三种:返回QuerySet,每个object只包含主表字段;返回QuerySet,每个object除了包含主表所有字段,还包含某些关联表的object,这种情况要用select_related()和prefetch_related();返回ValuesQuerySet, ValuesListQuerySet,它们的每个元素包含若干主表和关联表的字段,不包含任何实体和关联实例,这种情况要用values()和values_list()。

No9 extra()–实现复杂的where子句

函数原型:extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)

基本上,查询时用django提供的方法就够用了,不过有时where子句中包含复杂的逻辑,这种情况下django提供的方法可能不容易做到,还好,django有extra(), extra()中直接写一些SQL语句。不过,不同的数据库用的SQL有些差异,所以尽可能不要用extra()。需要时再看使用方法吧。

No10 aggregate(*args, **kwargs)–对应聚合函数

参数为聚合函数,最好用**kwargs的形式,每个参数起一个名字。如

>>> from django.db.models import Count

>>> q = Blog.objects.aggregate(Count(‘entry’)) #这是用*args的形式,最好不要这样用

>>> q = Blog.objects.aggregate(number_of_entries=Count(‘entry’)) #这是用**kwargs的形式

{‘number_of_entries’: 16}

No11 exists()、count()、len()

如果只是想知道一个QuerySet是否为空,而不想获取QuerySet中的每个元素,那就用exists(),它要比len()、count()、和直接进行if判断效率高。如果只想知道一个QuerySet有多大,而不想获取QuerySet中的每个元素,那就用count();如果已经从数据库获取到了QuerySet,那就用len()

No12 contains/startswith/endswith–对应like

字段名加双下划线,除了它,还有icontains,即Case-insensitive contains,这个是大小写不敏感的

No13 in–对应in

字段名加双下划线

No14 gt/gte/lt/lte–对应于>,>=,<,<=

字段名加双下划线

No15 range–对应于between and

字段名加双下划线,range后面值是列表

No16 isnull–对应于is null

Entry.objects.filter(pub_date__isnull=True)对应的SQL为SELECT … WHERE pub_date IS NULL;

No17 QuerySet切片–对应于limit

QuerySet的索引只能是非负整数,不支持负整数,所以QuerySet[-1]错误

a=Entry.objects.all()[5:10]

b=len(a) #执行Entry.objects.all()[5:8],对于不同的数据库,SQL语句不同,Sqlite 的SQL语句为select * from tablename limit 3 offset 5; MySQL的SQL语句为select * from tablename limit 3,5

 

Django对数据库的封装——QuerySet

Django对数据库的操作分用到三个类:Manager、QuerySet、Model。Manager的主要功能定义表级方法(表级方法就是影响一条或多条记录的方法),我们可以以models.Manager为父类,定义自己的manager,增加表级方法;QuerySet是Manager的方法返回的,是一个可遍历结构,包含一个或多个元素,每个元素都是一个Model 实例,它里面的方法也是表级方法,前面说了,Django给我们提供了增加表级方法的途径,那就是自定义manager类,而不是自定义QuerySet类,一般的我们没有自定义QuerySet类的必要;Model是一条记录的类,它的功能很强大,里面包含外键实体等,它的方法都是记录级方法(都是实例方法,无类方法),不要在里面定义类方法,比如计算记录的总数,查看所有记录,这些应该放在自定义的manager类中。

1.QuerySet

1.1 简介

每个Model都有一个默认的manager类,名为objects,QuerySet有两种来源:通过manager的方法得到、通过QuerySet的方法得到。QuerySet的最初来源就是通过manager的方法。mananger的方法和QuerySet的方法大部分同名,同意思,如filter(),update()等,但也有些不同,如manager有create()、get_or_create(),而QuerySet有delete()等。一个QuerySet包含一个或多个model instance。QuerySet类似于Python中的list,list的一些方法QuerySet也有,比如切片,遍历。

>>> from gk_user.models import UserEx
>>> type(UserEx.objects)
<class 'django.db.models.manager.Manager'>
>>> a = UserEx.objects.all()
>>> type(a)
<class 'django.db.models.query.QuerySet'>

QuerySet是延迟获取的,只有当用到这个QuerySet时(有下面几种情况),才会求值,即查询数据库。另外,查询到的QuerySet又是缓存的,当再次使用同一个QuerySet时,并不会再查询数据库,而是直接从缓存获取(不过,有一些特殊情况)。一般而言,当对一个没有求值的QuerySet进行的运算返回的不是QuerySet、ValuesQuerySet、ValuesListQuerySet、Model实例时,一般的会立即查询数据库;反之,运算返回的是QuerySet、ValuesQuerySet、ValuesListQuerySet、Model实例时,一般不会查询数据库。下面介绍几种(并非全部)对QuerySet求值的场景。

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()
def __unicode__(self):
    return self.name
     
class Author(models.Model):
    name = models.CharField(max_length=50)
    email = models.EmailField()
def __unicode__(self):
    return self.name
    
class Entry(models.Model):
    blog = models.ForeignKey(Blog)
    headline = models.CharField(max_length=255)
    body_text = models.TextField()
    pub_date = models.DateField()
    mod_date = models.DateField()
    authors = models.ManyToManyField(Author)
    n_comments = models.IntegerField()
    n_pingbacks = models.IntegerField()
    rating = models.IntegerField()
def __unicode__(self):
    return self.headline

我们以上面的models为例。

I 遍历

a = Entry.objects.all()
for e in a:
    print (e.headline)

当遍历时,先从数据库执行查询select * from Entry得到a,然后再遍历a。注意:这里只是查询Entry表,返回的a的每条记录只包含Entry表的字段值。不管Entry的model中是否有onetoone、onetomany、manytomany字段,都不会关联查询。这遵循的是数据库最少读写原则。我们修改一下代码,如下,遍历一开始也是先执行查询得到a,但当执行print (e.blog.name)时,还需要再次查询数据库获取blog实体。

from django.db import connection

l = connection.queries #l是一个列表,记录SQL语句

a = Entry.objects.all()

for e in a:

print (e.blog.name)

len(l)

遍历时,每次都要查询数据库,l长度每次增1,Django提供了方法可以在查询时返回关联表实体,如果是onetoone或onetomany,那用select_related,不过对于onetomany,只能在主表(定义onetomany关系的那个表)的manager中使用select_related方法,即通过select_related获取的关联对象是model instance,而不能是QuerySet,如下,e.blog就是model instance。对于onetomany的反向和manytomany,要用prefetch_related,它返回的关联对象是QuerySet。

a = Entry.objects.select_related(‘blog’)

for e in a:

print (e.blog.name)

len(l)

可以看到从开始到结束,l的长度只增加1。另外,通过查询connection.queries[-1]可以看到Sql语句用了join。

II 切片

切片不会立即执行,除非显示指定了步长,如a= Entry.objects.all()[0:10:2],步长为2。

III 序列化,即Pickling

序列化QuerySet很少用

IV repr()

和str()功能相似,将对象转为字符串,很少用。

V len()

计算QuerySet元素的数量,并不推荐使用len(),除非QuerySet是求过值的(即evaluated),否则,用QuerySet.count()获取元素数量,这个效率要高。

VI list()

将QuerySet转为list

VII bool() ,判断是否为空

if Entry.objects.filter(headline="Test"):
    print("There is at least one Entry with the headline Test")

同样不建议这种方法判断是否为空,而应该使用QuerySet.exists(),查询效率高

1.2 QuerySet的方法

数据库的常用操作就四种:增、删、改、查,QuerySet的方法涉及删、改、查。后面还会讲model对象的方法,model方法主要是增、删、改、还有调用model实例的字段。

(1) 删delete()

原型:delete()

返回:None

相当于delete-from-where, delete-from-join-where。先filter,然后对得到的QuerySet执行delete()方法就行了,它会同时删除关联它的那些记录,比如我删除记录表1中的A记录,表2中的B记录中有A的外键,那同时也会删除B记录,那ManyToMany关系呢?不清楚。实际中,delete用的很少,对于没有用的记录,一般是update为不可用。由于有些数据库,如Sqlite不支持delete与limit连用,所以在这些数据库对QuerySet的切片执行delete()会出错。如

>>> a = UserEx.objects.filter(is_active=False)
>>> b = a[:3]
>>> b.delete() #执行时会报错

解决:UserEx.objects.filter(pk__in=b).delete()

in后面可以是一个QuerySet,见 https://docs.djangoproject.com/en/1.6/ref/models/querysets/#in

(2) 改 update()

批量修改,返回修改的记录数。不过update()中的键值对的键只能是主表中的字段,不能是关联表字段,如下:

Entry.objects.update(blog__name='foo') #这是错误的,无法修改关联表字段,只能修改Entry
#表中的字段
Entry.objects.filter(blog__name='foo').update(comments_on=False) #正确,filter中的字段可以
#是关联表

最好的方法是先filter,查询出QuerySet,然后再执行QuerySet.update()。

由于有些数据库,不支持update与limit连用,所以在这些数据库对QuerySet的切片执行update()会出错。

(3)查询 filter(**kwargs)、exclude(**kwargs)、get(**kwargs)

相当于select-from-where,select-from-join-where,很多网站读数据库操作最多。可以看到,filter()的参数是变个数的键值对,而不会出现>,<,!=等符号,这些符号分别用__gt,__lt,~Q或exclude(),不过对于!=,建议使用Q查询,更不容易出错。可以使用双下划线对OneToOne、OneToMany、ManyToMany进行关联查询和反向关联查询,而且方法都是一样的,如:

>>> Entry.objects.filter(blog__name='Beatles Blog') 
#限定外键表的字段下面是反向连接,不过要注意,这里不是entry_set,
#entry_set是Blog 实例的一个属性,代表某个Blog对象的关联的所有entry,
#而QuerySet的方法中反向连接是直接用model的小写,不要把两者搞混。
#反过来也是一样,如果想根据现有对象找原对象,将原类型对象小写即可。
>>> Blog.objects.filter(entry__headline__contains='Lennon')
>>> Blog.objects.filter(entry__authors__name='Lennon') #ManyToMany关系,反向连接
>>> myblog = Blog.objects.get(id=1)
>>> Entry.objects.filter(blog=myblog) 
#正向连接。与下面一句等价,既可以用实体,也可以用实体的主键。
#其实即使用实体,也是只用实体的主键而已。这两种方式对OneToOne、
#OneToMany、ManyToMany的正向、反向连接都适用。
>>> Entry.objects.filter(blog=1)
>>> myentry = Entry.objects.get(id=1)
>>> Blog.objects.filter(entry=myentry) #ManyToMany反向连接。与下面一句等价
>>> Blog.objects.filter(entry=1)

OneToOne的关系也是这样关联查询,可以看到,Django对OneToOne、OneToMany、ManyToMany关联查询及其反向关联查询提供了相同的方式,真是牛逼啊。对于OneToOne、OneToMany的主表,也可以使用下面的方式

Entry.objects.filter(blog_id=1),因为blog_id是数据库表Entry的一个字段, 这条语句与Entry.objects.filter(blog=1)生成的SQL是完全相同的,都是只在Entry表查询,没用join,django为我们封装了对数据库的操作,所以建议只用model中的字段,而blog_id不是model定义的字段,不建议用。

与filter类似的还有exclude(**kwargs)方法,这个方法是剔除,相当于select-from-where not,select-from-join-where not。可以使用双下划线对OneToOne、OneToMany、ManyToMany进行关联查询和反向关联查询,方法与filter()中的使用方法相同。

>>> Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline=’Hello’)

转为SQL为

SELECT *
FROM Entry
WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')

python urllib2 详解

urllib2是Python的一个获取URLs(Uniform Resource Locators)的组件。他以urlopen函数的形式提供了一个非常简单的接口,
这是具有利用不同协议获取URLs的能力,他同样提供了一个比较复杂的接口来处理一般情况,例如:基础验证,cookies,代理和其他。
它们通过handlers和openers的对象提供。
urllib2支持获取不同格式的URLs(在URL的”:”前定义的字串,例如:”ftp”是”ftp:python.ort/”的前缀),它们利用它们相关网络协议(例如FTP,HTTP)
进行获取。这篇教程关注最广泛的应用–HTTP。
对于简单的应用,urlopen是非常容易使用的。但当你在打开HTTP的URLs时遇到错误或异常,你将需要一些超文本传输协议(HTTP)的理解。
最权威的HTTP文档当然是RFC 2616(http://rfc.net/rfc2616.html)。这是一个技术文档,所以并不易于阅读。这篇HOWTO教程的目的是展现如何使用urllib2,
并提供足够的HTTP细节来帮助你理解。他并不是urllib2的文档说明,而是起一个辅助作用。
获取 URLs
最简单的使用urllib2将如下所示
[codesyntax lang=”python”]

import urllib2 
response = urllib2.urlopen('http://python.org/') 
html = response.read()

[/codesyntax]
urllib2的很多应用就是那么简单(记住,除了”http:”,URL同样可以使用”ftp:”,”file:”等等来替代)。但这篇文章是教授HTTP的更复杂的应用。
HTTP是基于请求和应答机制的–客户端提出请求,服务端提供应答。urllib2用一个Request对象来映射你提出的HTTP请求,在它最简单的使用形式中你将用你要请求的
地址创建一个Request对象,通过调用urlopen并传入Request对象,将返回一个相关请求response对象,这个应答对象如同一个文件对象,所以你可以在Response中调用.read()。
[python]
import urllib2
req = urllib2.Request(‘http://www.voidspace.org.uk’)
response = urllib2.urlopen(req)
the_page = response.read()

[/codesyntax]
记得urllib2使用相同的接口处理所有的URL头。例如你可以像下面那样创建一个ftp请求。
req = urllib2.Request(‘ftp://example.com/’)
在HTTP请求时,允许你做额外的两件事。首先是你能够发送data表单数据,其次你能够传送额外的关于数据或发送本身的信息(“metadata”)到服务器,此数据作为HTTP的”headers”来发送。
接下来让我们看看这些如何发送的吧。
Data数据
有时候你希望发送一些数据到URL(通常URL与CGI[通用网关接口]脚本,或其他WEB应用程序挂接)。在HTTP中,这个经常使用熟知的POST请求发送。这个通常在你提交一个HTML表单时由你的浏览器来做。
并不是所有的POSTs都来源于表单,你能够使用POST提交任意的数据到你自己的程序。一般的HTML表单,data需要编码成标准形式。然后做为data参数传到Request对象。编码工作使用urllib的函数而非
urllib2。
[codesyntax lang=”python”]

import urllib 
import urllib2 
url = 'http://www.someserver.com/cgi-bin/register.cgi' 
values = {'name' : 'Michael Foord', 
          'location' : 'Northampton', 
          'language' : 'Python' } 
data = urllib.urlencode(values) 
req = urllib2.Request(url, data) 
response = urllib2.urlopen(req) 
the_page = response.read()

[/codesyntax]
记住有时需要别的编码(例如从HTML上传文件–看http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13 HTML Specification, Form Submission的详细说明)。
如ugoni没有传送data参数,urllib2使用GET方式的请求。GET和POST请求的不同之处是POST请求通常有”副作用”,它们会由于某种途径改变系统状态(例如提交成堆垃圾到你的门口)。
尽管HTTP标准说的很清楚POSTs通常会产生副作用,GET请求不会产生副作用,但没有什么可以阻止GET请求产生副作用,同样POST请求也可能不产生副作用。Data同样可以通过在Get请求
的URL本身上面编码来传送。
可看如下例子
[python:nogutter]
>>> import urllib2
>>> import urllib
>>> data = {}
>>> data[‘name’] = ‘Somebody Here’
>>> data[‘location’] = ‘Northampton’
>>> data[‘language’] = ‘Python’
>>> url_values = urllib.urlencode(data)
>>> print url_values
name=Somebody+Here&language=Python&location=Northampton
>>> url = ‘http://www.example.com/example.cgi’
>>> full_url = url + ‘?’ + url_values
>>> data = urllib2.open(full_url)

[/codesyntax]
Headers
我们将在这里讨论特定的HTTP头,来说明怎样添加headers到你的HTTP请求。
有一些站点不喜欢被程序(非人为访问)访问,或者发送不同版本的内容到不同的浏览器。默认的urllib2把自己作为“Python-urllib/x.y”(x和y是Python主版本和次版本号,例如Python-urllib/2.5),
这个身份可能会让站点迷惑,或者干脆不工作。浏览器确认自己身份是通过User-Agent头,当你创建了一个请求对象,你可以给他一个包含头数据的字典。下面的例子发送跟上面一样的内容,但把自身
模拟成Internet Explorer。
[codesyntax lang=”python”]

import urllib 
import urllib2 
url = 'http://www.someserver.com/cgi-bin/register.cgi' 
user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)' 
values = {'name' : 'Michael Foord', 
          'location' : 'Northampton', 
          'language' : 'Python' } 
headers = { 'User-Agent' : user_agent } 
data = urllib.urlencode(values) 
req = urllib2.Request(url, data, headers) 
response = urllib2.urlopen(req) 
the_page = response.read()

[/codesyntax]
response应答对象同样有两个很有用的方法。看下面的节info and geturl,我们将看到当发生错误时会发生什么。
Handle Exceptions处理异常
当urlopen不能够处理一个response时,产生urlError(不过通常的Python APIs异常如ValueError,TypeError等也会同时产生)。
HTTPError是urlError的子类,通常在特定HTTP URLs中产生。
URLError
通常,URLError在没有网络连接(没有路由到特定服务器),或者服务器不存在的情况下产生。这种情况下,异常同样会带有”reason”属性,它是一个tuple,包含了一个错误号和一个错误信息。
例如
[codesyntax lang=”python”]

>>> req = urllib2.Request('http://www.pretend_server.org') 
>>> try: urllib2.urlopen(req) 
>>> except URLError, e: 
>>>    print e.reason 
>>> 
(4, 'getaddrinfo failed')

[/codesyntax]
HTTPError
服务器上每一个HTTP 应答对象response包含一个数字”状态码”。有时状态码指出服务器无法完成请求。默认的处理器会为你处理一部分这种应答(例如:假如response是一个”重定向”,需要客户端从别的地址获取文档
,urllib2将为你处理)。其他不能处理的,urlopen会产生一个HTTPError。典型的错误包含”404″(页面无法找到),”403″(请求禁止),和”401″(带验证请求)。
请看RFC 2616 第十节有所有的HTTP错误码
HTTPError实例产生后会有一个整型’code’属性,是服务器发送的相关错误号。
Error Codes错误码
因为默认的处理器处理了重定向(300以外号码),并且100-299范围的号码指示成功,所以你只能看到400-599的错误号码。
BaseHTTPServer.BaseHTTPRequestHandler.response是一个很有用的应答号码字典,显示了RFC 2616使用的所有的应答号。这里为了方便重新展示该字典。(译者略)
当一个错误号产生后,服务器返回一个HTTP错误号,和一个错误页面。你可以使用HTTPError实例作为页面返回的应答对象response。这表示和错误属性一样,它同样包含了read,geturl,和info方法。
[codesyntax lang=”python”]

>>> req = urllib2.Request('http://www.python.org/fish.html') 
>>> try: 
>>>     urllib2.urlopen(req) 
>>> except URLError, e: 
>>>     print e.code 
>>>     print e.read() 
>>> 
404 

Error 404: File Not Found 
...... etc...

[/codesyntax]
Wrapping it Up包装
所以如果你想为HTTPError或URLError做准备,将有两个基本的办法。我则比较喜欢第二种。
第一个:
[codesyntax lang=”python”]

from urllib2 import Request, urlopen, URLError, HTTPError 
req = Request(someurl) 
try: 
    response = urlopen(req) 
except HTTPError, e: 
    print 'The server couldn/'t fulfill the request.' 
    print 'Error code: ', e.code 
except URLError, e: 
    print 'We failed to reach a server.' 
    print 'Reason: ', e.reason 
else: 
    # everything is fine

[/codesyntax]
注意:except HTTPError 必须在第一个,否则except URLError将同样接受到HTTPError。
第二个:
[codesyntax lang=”python”]

from urllib2 import Request, urlopen, URLError 
req = Request(someurl) 
try: 
    response = urlopen(req) 
except URLError, e: 
    if hasattr(e, 'reason'): 
        print 'We failed to reach a server.' 
        print 'Reason: ', e.reason 
    elif hasattr(e, 'code'): 
        print 'The server couldn/'t fulfill the request.' 
        print 'Error code: ', e.code 
else: 
    # everything is fine

[/codesyntax]
info and geturl
urlopen返回的应答对象response(或者HTTPError实例)有两个很有用的方法info()和geturl()
geturl — 这个返回获取的真实的URL,这个很有用,因为urlopen(或者opener对象使用的)或许
会有重定向。获取的URL或许跟请求URL不同。
info — 这个返回对象的字典对象,该字典描述了获取的页面情况。通常是服务器发送的特定头headers。目前是httplib.HTTPMessage 实例。
经典的headers包含”Content-length”,”Content-type”,和其他。查看Quick Reference to HTTP Headers(http://www.cs.tut.fi/~jkorpela/http.html)
获取有用的HTTP头列表,以及它们的解释意义。
Openers和Handlers
当你获取一个URL你使用一个opener(一个urllib2.OpenerDirector的实例,urllib2.OpenerDirector可能名字可能有点让人混淆。)正常情况下,我们
使用默认opener — 通过urlopen,但你能够创建个性的openers,Openers使用处理器handlers,所有的“繁重”工作由handlers处理。每个handlers知道
如何通过特定协议打开URLs,或者如何处理URL打开时的各个方面,例如HTTP重定向或者HTTP cookies。
如果你希望用特定处理器获取URLs你会想创建一个openers,例如获取一个能处理cookie的opener,或者获取一个不重定向的opener。
要创建一个 opener,实例化一个OpenerDirector,然后调用不断调用.add_handler(some_handler_instance).
同样,可以使用build_opener,这是一个更加方便的函数,用来创建opener对象,他只需要一次函数调用。
build_opener默认添加几个处理器,但提供快捷的方法来添加或更新默认处理器。
其他的处理器handlers你或许会希望处理代理,验证,和其他常用但有点特殊的情况。
install_opener 用来创建(全局)默认opener。这个表示调用urlopen将使用你安装的opener。
Opener对象有一个open方法,该方法可以像urlopen函数那样直接用来获取urls:通常不必调用install_opener,除了为了方便。
Basic Authentication 基本验证
为了展示创建和安装一个handler,我们将使用HTTPBasicAuthHandler,为了更加细节的描述本主题–包含一个基础验证的工作原理。
请看Basic Authentication Tutorial(http://www.voidspace.org.uk/python/articles/authentication.shtml)
当需要基础验证时,服务器发送一个header(401错误码) 请求验证。这个指定了scheme 和一个‘realm’,看起来像这样:Www-authenticate: SCHEME realm=”REALM”.
例如
Www-authenticate: Basic realm=”cPanel Users”
客户端必须使用新的请求,并在请求头里包含正确的姓名和密码。这是“基础验证”,为了简化这个过程,我们可以创建一个HTTPBasicAuthHandler的实例,并让opener使用这个
handler。
HTTPBasicAuthHandler使用一个密码管理的对象来处理URLs和realms来映射用户名和密码。如果你知道realm(从服务器发送来的头里)是什么,你就能使用HTTPPasswordMgr。
通常人们不关心realm是什么。那样的话,就能用方便的HTTPPasswordMgrWithDefaultRealm。这个将在你为URL指定一个默认的用户名和密码。这将在你为特定realm提供一个其他组合时
得到提供。我们通过给realm参数指定None提供给add_password来指示这种情况。
最高层次的URL是第一个要求验证的URL。你传给.add_password()更深层次的URLs将同样合适。
[codesyntax lang=”python”]

# 创建一个密码管理者 
password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm() 
# 添加用户名和密码 
# 如果知道 realm, 我们可以使用他代替 ``None``. 
top_level_url = "http://example.com/foo/" 
password_mgr.add_password(None, top_level_url, username, password) 
handler = urllib2.HTTPBasicAuthHandler(password_mgr) 
# 创建 "opener" (OpenerDirector 实例) 
opener = urllib2.build_opener(handler) 
# 使用 opener 获取一个URL 
opener.open(a_url) 
# 安装 opener. 
# 现在所有调用 urllib2.urlopen 将用我们的 opener.

[/codesyntax]
urllib2.install_opener(opener)
注意:以上的例子我们仅仅提供我们的HHTPBasicAuthHandler给build_opener。默认的openers有正常状况的handlers–ProxyHandler,UnknownHandler,HTTPHandler,HTTPDefaultErrorHandler, HTTPRedirectHandler, FTPHandler, FileHandler, HTTPErrorProcessor。
top_level_url 实际上可以是完整URL(包含”http:”,以及主机名及可选的端口号)例如:http://example.com/,也可以是一个“authority”(即主机名和可选的
包含端口号)例如:“example.com” or “example.com:8080”(后者包含了端口号)。权限验证,如果递交的话不能包含”用户信息”部分,例如:
“joe@password:example.com”是错误的。
Proxies代理urllib 将自动监测你的代理设置并使用他们。这个通过ProxyHandler这个在正常处理器链中的对象来处理。通常,那工作的很好。但有时不起作用
。其中一个方法便是安装我们自己的代理处理器ProxyHandler,并不定义代理。这个跟使用Basic Authentication 处理器很相似。
[codesyntax lang=”python”]

>>> proxy_support = urllib.request.ProxyHandler({}) 
>>> opener = urllib.request.build_opener(proxy_support) 
>>> urllib.request.install_opener(opener)

[/codesyntax]
注意:
此时urllib.request不支持通过代理获取https地址。但,这个可以通过扩展urllib.request达到目的。
Sockets and Layers
Python支持获取网络资源是分层结构。urllib 使用http.client库,再调用socket库实现。
在Python2.3你可以指定socket的等待回应超时时间。这个在需要获取网页的应用程序里很有用。默认的socket模型没有超时和挂起。现在,socket超时没有暴露 www.2cto.com
给http.client或者urllib.request层。但你可以给所有的sockets设置全局的超时。

Python字典详解

创建

方法一:
[codesyntax lang=”python”]

>>> dict1 = {}
>>> dict2 = {'name': 'earth', 'port': 80}
>>> dict1, dict2
({}, {'port': 80, 'name': 'earth'})

[/codesyntax]
方法二:从Python 2.2 版本起,可以使用一个工厂方法,传入一个元素是列表的元组作为参数
[codesyntax lang=”python”]

>>> fdict = dict((['x', 1], ['y', 2]))
>>> fdict
{'y': 2, 'x': 1}

[/codesyntax]
方法三:

从Python 2.3 版本起, 可以用一个很方便的内建方法fromkeys() 来创建一个”默认”字典, 字典中元素具有相同的值 (如果没有给出, 默认为None,这个有点像我框架的oneObject方法):
[codesyntax lang=”python”]

>>> ddict = {}.fromkeys(('x', 'y'), -1) 
>>> ddict
{'y': -1, 'x': -1}
>>>
>>> edict = {}.fromkeys(('foo', 'bar'))
>>> edict
{'foo': None, 'bar': None}

[/codesyntax]

访问字典中的值

想遍历一个字典(一般用键), 你只需要循环查看它的键, 像这样:
[codesyntax lang=”python”]

>>> dict2 = {'name': 'earth', 'port': 80}
>>>
>>>> for key in dict2.keys():
... print 'key=%s, value=%s' % (key, dict2[key])
...
key=name, value=earth
key=port, value=80

[/codesyntax]
从Python 2.2 开始,可以直接在 for 循环里遍历字典。
[codesyntax lang=”python”]

>>> dict2 = {'name': 'earth', 'port': 80}
>>>
>>>> for key in dict2:
... print 'key=%s, value=%s' % (key, dict2[key])
...
key=name, value=earth
key=port, value=80

[/codesyntax]
想判定其是否存在某个键值对,可以使用has_key()或 in 、 not in 操作符
[codesyntax lang=”python”]

>>> 'server' in dict2 # 或 dict2.has_key('server')
False
>>> 'name' in dict # 或 dict2.has_key('name')
True
>>> dict2['name']
'earth'

[/codesyntax]
一个字典中混用数字和字符串的例子:
[codesyntax lang=”python”]

>>> dict3 = {}
>>> dict3[1] = 'abc'
>>> dict3['1'] = 3.14159
>>> dict3[3.2] = 'xyz'
>>> dict3
{3.2: 'xyz', 1: 'abc', '1': 3.14159}

[/codesyntax]

更新字典

采取覆盖更新

上例中 dict2[‘name’]=’earth’;

更新 dict2[‘name’]=’abc’;

删除字典元素和字典

del dict2[‘name’] # 删除键为“name”的条目

dict2.clear() # 删除dict2 中所有的条目

del dict2 # 删除整个dict2 字典

dict2.pop(‘name’) # 删除并返回键为“name”的条目
[codesyntax lang=”python”]

dict2 = {'name': 'earth', 'port': 80}
>>> dict2.keys()
['port', 'name']
>>>
>>> dict2.values()
[80, 'earth']
>>>
>>> dict2.items()
[('port', 80), ('name', 'earth')]
>>>
>>> for eachKey in dict2.keys():
... print 'dict2 key', eachKey, 'has value', dict2[eachKey]
...
dict2 key port has value 80
dict2 key name has value earth

[/codesyntax]
update()方法可以用来将一个字典的内容添加到另外一个字典中
[codesyntax lang=”python”]

dict3 = {'server': 'http', 'port': 80, 'host': 'venus'}
>>> dict3.clear()
>>> dict3
{}

[/codesyntax]
映射类型相关的函数
[codesyntax lang=”python”]

>>> dict(x=1, y=2)
{'y': 2, 'x': 1}
>>> dict8 = dict(x=1, y=2)
>>> dict8
{'y': 2, 'x': 1}
>>> dict9 = dict(**dict8)
>>> dict9
{'y': 2, 'x': 1}

dict9 = dict8.copy()

[/codesyntax]

字典内建方法

方法名字 操作
dict.clear() 删除字典中所有元素
dict.copy() 返回字典(浅复制)的一个副本
dict.fromkeysc(seq,val=None) 创建并返回一个新字典,以seq 中的元素做该字典的键,val 做该字典中所有键对应的初始值(如果不提供此值,则默认为None)
dict.get(key,default=None) 对字典dict 中的键key,返回它对应的值value,如果字典中不存在此键,则返回default 的值(注意,参数default 的默认值为None)
dict.has_key(key) 如果键(key)在字典中存在,返回True,否则返回False. 在Python2.2版本引入in 和not in 后,此方法几乎已废弃不用了,但仍提供一个 可工作的接口。
dict.items() 返回一个包含字典中(键, 值)对元组的列表
dict.keys() 返回一个包含字典中键的列表
dict.values() 返回一个包含字典中所有值的列表
dict.iter() 方法iteritems(), iterkeys(), itervalues()与它们对应的非迭代方法一样,不同的是它们返回一个迭代子,而不是一个列表。
dict.pop(key[, default]) 和方法get()相似,如果字典中key 键存在,删除并返回dict[key],如果key 键不存在,且没有给出default 的值,引发KeyError 异常。
dict.setdefault(key,default=None) 和方法set()相似,如果字典中不存在key 键,由dict[key]=default 为它赋值。
dict.setdefault(key,default=None) 和方法set()相似,如果字典中不存在key 键,由dict[key]=default 为它赋值。

Python IDLE快捷键使用

最近由于需要进行Python脚本 如果将至运行在cmd下时 总显示乱码  没办法只能想起他办法来进行解决了

想着安装Windows版本的Python的时候 默认的安装了IDLE文本编辑器  且其支持各类Windows编码  所以就优先使用这玩意了

毕竟 如果每次都用Eclipse老打开脚本 速度会很慢~~

 

但是 这样做 也有一个弊端 就是快捷键没有Eclipse那么好用了

好了  为提升速度 赶紧上网找一下IDLE的快捷键 以供与大家分享……

Ctrl + Space

完成类、方法、变量名称的自动输入,这个快捷键是我最经常使用的快捷键了,它可以完成类、方法、变量名称的自动录入,很方便.(不过在我的电脑上和输入法冲突)

Ctrl + N

快速跳转到执行的类。

Ctrl + Shift + N

跳转到指定的文件

Ctrl+Shift+Alt+N

可以快速打开符号

Ctrl + B (ctrl+点击)

跳转到定义处

Ctrl + Alt + B

跳转到方法实现处

Ctrl + Alt + T

用*来围绕选中的代码行( * 包括if、while、try catch等)这个功能也很方便,

Ctrl + W

按一个word来进行选择操作在IDEA里的这个快捷键功能是先选择光标所在字符处的单词,然后是选择源

代码的扩展区域。举例来说,对下边这个语句java.text.SimpleDateFormat formatter = new java.text.SimpleDateFormat(“yyyy-MM-dd HH:mm”);当光标的位置在双引号内的字符串中时,会先选中这个字符串,然后是等号右边的表达式,再是整个句子。我一般都是在对代码进行重新修改的时候使用

它来选择出那些长长的复合表达式,很方便:)

Ctrl + Q

在editor window中显示java docs这个功能很方便–因为有时仅仅是忘记了自己编写的方法中的某个参数的含义,此时又不想再起一个浏览器来查看java doc,此时这个功能的好处就体现出来了

Alt+Q

可以不需要移动代码就能查看当前方法地声明。连续按两次会显示当前所编辑的类名

Ctrl+P

可以显示参数信息

Ctrl + /

注释/反注释指定的语句,它可以注释和反注释你所选择的语句(使用单行注释符号”//”)

Ctrl + Shift + /

用来进行多行语句的注释(即使用多行注释符号”/* … */”)

F2/Shift + F2

跳转到下/上一个错误语句、警告处IDEA提供了一个在错误语句之间方便的跳转的功能,你使用这个快捷键可以快捷在出错的语句之间进行跳转。

Shift + F6

提供对方法、变量,类,文件的重命名

Ctrl + Alt + L

根据模板格式化选择的代码,根据模板中设定的格式来format你的java代码,不过可惜的是只对java文件有效

Ctrl + Alt + I

将选中的代码进行自动缩进编排这个功能在编辑jsp文件的时候也可以工作,提供了一个对上边格式化代码功能的补充。

Ctrl + Alt + O

优化import自动去除无用的import语句。

Ctrl + ]/[

跳转到代码块结束/开始处

Ctrl+E

可以显示最近编辑的文件列表

Shift+Click

可以关闭文件。但是得点击标签栏

Ctrl+Shift+Backspace

可以跳转到上次编辑的地方

Ctrl+F12

可以显示当前文件的结构,大纲

Ctrl+F7

可以查询当前元素在当前文件中的引用,然后按F3可以选择

Alt+Insert

可以生成构造器/Getter/Setter等代码

Ctrl+Alt+V

可以引入变量。例如把括号内的SQL赋成一个变量,我非常喜欢这个功能

Alt+Up and Alt+Down

可在方法间快速移动

Alt+Enter

可以得到一些Intention Action,例如将”==”改为”equals()”

Ctrl+Shift+Space

在很多时候都能够给出Smart提示

Ctrl+Alt+Space

是类名自动完成

Alt+F3 (Ctrl+F)

可以快速寻找

Ctrl+O

可以选择父类的方法进行重写

Ctrl-I

可以选择父接口的方法进行实现

Ctrl+J

Live Templates!

Ctrl-H

要看一个所选择的类的继承层次,按Ctrl-H(Browse Type Hierarchy)即可。也可以激活编辑器中的继承关系视图查看当前编辑类的继承关系。

Ctrl+Shift+F7

可以高亮当前元素在当前文件中的使用

Alt+F7

查找当前元素在工程中的引用

Alt+F8

debug的时候计算变量值

Ctrl+Alt+Up /Ctrl+Alt+Down

可以快速跳转搜索结果

Ctrl+Shift+J

可以整合两行

Ctrl+D

复制上一行或复制选定

Ctrl+Alt+L

格式化代码

Alt+Shift+Insert

列编辑

Ctrl-Shift-V

将最近使用的剪贴板内容选择插入到文本。使用时系统会弹出一个含有剪贴内容的对话框,从中你可以选择你要粘贴的部分。

技巧篇

使用Refactor|Copy Class…可以创建一个所选择的类的“副本”。这一点很有用,比如,在你想要创建一个大部分内容都和已存在类相同的类时。

在任何工具窗口里使用Escape键都可以把焦点移到编辑器上。

Shift-Escape不仅可以把焦点移到编辑器上而且还可以隐藏当前(或最后活动的)工具窗口。

F12键把焦点从编辑器移到最近使用的工具窗口。

使用Ctrl-Shift-F7(Search | Highlight Usages in File)可以快速高亮显示当前文件中某一变量的使用地方。按Escape清除高亮显示。

Ctrl-Shift-J快捷键把两行合成一行并把不必要的空格去掉以匹配你的代码格式。

要在任何视图(Project View工程视图,Structure View结构视图或者其它视图)里快速选择当前编辑地部分(类,文件,方法或者字段),按Alt-F1(View | Select in…)。

所有视图里都提供了速查功能:在树里只需键入字符就可以快速定位到一个条目。

Python读取Jason

今天在观察python脚本的时候,看到了python解析jason数据这么一段。
经过相关查找,终于弄清楚了python是怎么解析jason结构,取得数据的。
我们通过以下命令:

[codesyntax lang=”python”]

target = urlopen(url, 'utf8')
try:
    target = json.loads(target)
except:
    print 'load json error!!'

[/codesyntax]

取得了这么一段jason数据:

[codesyntax lang=”jason”]

{
    "title": "报表",
    "tables": {
        "example1": {
            "id": "first",
            "values": [
                {
                    "key": "one",
                    "value": "1234"
                },
                {
                    "key": "two",
                    "value": "12345"
                },
                {
                    "key": "three",
                    "value": "123456"
                },
            ]
        },
        "example2": {
            "id": "second",
            "values": [
                {
                    "key": "four",
                    "value": "321"
                },
                {
                    "key": "five",
                    "value": "4321"
                },
        },
    }
}

[/codesyntax]

我们应该如何拿到里面的数据呢?比如说拿到key为“three”,value为“123456”的值,那么我们可以这样获取数据: [codesyntax lang=”python”]

get_value = target['tables']['example1']['values'][2]['value']

[/codesyntax]

首先,需要理解jason的结构:

写道

JSON建构于两种结构:
“名称/值”对的集合(A collection of name/value pairs)。不同的语言中,它被理解为对象(object),纪录(record),结构(struct),字典(dictionary),哈希表(hash table),有键列表(keyed list),或者关联数组 (associative array)。
值的有序列表(An ordered list of values)。在大部分语言中,它被理解为数组(array)。

写道

JSON具有以下这些形式:
对象是一个无序的“‘名称/值’对”集合。一个对象以“{”(左括号)开始,“}”(右括号)结束。每个“名称”后跟一个“:”(冒号);“‘名称/值’ 对”之间使用“,”(逗号)分隔。

数组是值(value)的有序集合。一个数组以“[”(左中括号)开始,“]”(右中括号)结束。值之间使用“,”(逗号)分隔。

值(value)可以是双引号括起来的字符串(string)、数值(number)、true、false、 null、对象(object)或者数组(array)。这些结构可以嵌套。

而python会把对应的jason结构翻译过来,对应的关系如下:

所以我们使用 get_value = target[‘tables’][‘example1’][‘values’][2][‘value’] 就可以得到“123456”这个值。同理,使用 get_value = target[‘tables’][‘example2’][‘values’][0][‘key’]就可以得到“four”这个值了。

JSON Python
object dict
array list
string unicode
number (int) int, long
number (real) float
true True
false False
null None  

Python字符串查找

python 字符串查找有4个方法,1 find,2 index方法,3 rfind方法,4 rindex方法。

1 find()方法:查找子字符串,若找到返回从0开始的下标值,若找不到返回-1[codesyntax lang=”python”]

info = 'abca'
print info.find('a')##从下标0开始,查找在字符串里第一个出现的子串,返回结果:0

info = 'abca'
print info.find('a',1)##从下标1开始,查找在字符串里第一个出现的子串:返回结果3

info = 'abca'
print info.find('333')##返回-1,查找不到返回-1
[/codesyntax ]

2 index()方法:

python 的index方法是在字符串里查找子串第一次出现的位置,类似字符串的find方法,不过比find方法更好的是,如果查找不到子串,会抛出异常,而不是返回-1[codesyntax lang="python"]

info = 'abca'
print info.index('a')
print info.index('33')
[/codesyntax ]

rfind和rindex方法用法和上面一样,只是从字符串的末尾开始查找。

Python和Django安装使用

很多初学者都问Python和Django怎么安装,这里我们就简单地介绍一下这两个软件在Windows 2003下的安装步骤。

一、下载并安装Python

Python 官方下载地址:http://www.python.org/ftp/python/

我们这里选择的是 Python 2.7.2 。虽然目前最新版是Python 3.2.2, 但是Django目前还不支持 Python 3.2.2。

安装步骤很简单,双击安装包开始安装,这里我们安装到 D:\Python,如图1,


图1

单击“Next”按钮,进入Python安装组件选择界面。这里我们安装全部组件,选择默认的设置就可以了。如图2。


图2

安装完成后,需要设置操作系统环境变量Path,添加Python安装路径  “;D:\Python”  如图3


图3

设置完成之后,我们打开CMD命令提示符窗口,输入“python”,然后回车,应该可以看到类似的画面,如图4。


图4

Ok,这个时候,我们的python就安装完成了,你可以输入指令 print “Hello world” 打印字符串,按回车键看一下程序的执行效果是否一样。

二、下载并安装Django

下载Django目前最新版本 Django-1.3.1.tar.gz。我们下载的这个Django-1.3.1.tar.gz文件是一个标准的Unix压缩格式的文件,我们在Windows下也可以使用WinRAR之类的软件进行解压,解压之后我们得到一个Django-1.3.1的目录,假设我们解压到D:\Django目录。我们打开DOS命令提示窗口,进入这个目录,然后执行python setup.py install 这个命令来开始Django的安装。如图5。


图5

安装完成之后,我们发现 Django 被安装到了 D:\Python\Lib\site-packages\django 这个目录。在这个目录中有一个bin子目录,存放的是Django的常用命令, 为了方便以后操作,我们需要将这个bin路径添加到操作系统环境变量Path。添加Django命令路径  “;D:\Python\Lib\site-packages\django\bin”。如图6。


图6

目前为止我们已经完成 Django 安装的操作,下边我们需要来验证一下我们是否可以开始工作了。首先我们打开一个CMD命令窗口,看看Django的常规指令是否能用,然后我们再看看Django是否已经和python语言环境集成到了一起。如图7。


图7

从图中看到,我们首先在操作系统提示符下执行 “django-admin.py –version”,系统打印出Django的版本号“1.3.1”。接着我们输入“Python”进入到python运行环境,在“>>>”提示符下,我们输入一个python的模块导入语句 “import django”,这个语句表示我们在目前 python 运行环境中引入”django”这个功能模块;然后我们使用这个功能模块的“VERSION”方法来查看这个模块的版本号,同样我们也看到了相同的版本号。如果你的电脑上也完整的看到这些信息的话,那么OK,这证明你的电脑已经可以开始执行基于Django系统的python程序了。

三、创建一个Django项目

学习Django,我们的目的当然是为了用来开发基于Web的应用系统,我们来看看Django如何显示一个Web页面。打开一个CMD命令窗口,依次输入指令。如图8


图8

这里解释一下上图中的命令,首先进入D盘,输入命令django-admin.py startproject mysite 用来创建一个网站项目,网站目录名字为mysite,路径为D:\mysite。接着进入mysite 这个目录,输入manage.py runserver 开启网站。可以指定端口,默认为8000,如果想使用90端口,就写成 manage.py runserver 90。

最后我们打开浏览器在地址栏里输入地址 http://localhost:8000 ,看到 “It worked”了吗?如图9


图9

接下来我们建一个Hello world页面:

使用Django,页面的内容是靠视图函数来产生,我们在D:\mysite目录下创建一个视图文件views.py 输入如下内容:

from django.http import HttpResponse
import datetime

def hello(request):
    now = datetime.datetime.now()
    html = "<html><body><h3>Hello World!</h3>It is now %s </body></html>" % now
    return HttpResponse(html)

接着,修改mysite目录下的urls.py 文件,内容如下:

from django.conf.urls.defaults import patterns, include, url

urlpatterns = patterns('',

    ('^hello/$','mysite.views.hello'),
)

最后我们打开浏览器在地址栏里输入地址 http://localhost:8000/hello/,结果显示 如图10


图10

四、建立一个Mysql数据库应用

1、首先安装MySQL数据库,我们这里安装到D:\MySQL。具体参考开文档:MySQL安装图解

2、安装python-mysql驱动。

官方下载地址:http://sourceforge.net/projects/mysql-python/files/
windows版本下载地址:http://www.codegood.com/downloads

我们这里使用windows版本 MySQL-python-1.2.3.win32-py2.7.exe

2、修改settings.py配置文件的数据库项

在D:\mysite目录下有一个setttings.py文件,打开它,找到DATABASES这一项,更改数据库连接参数。结果如下:

DATABASES = {
    'default': {
        'ENGINE': 'mysql',
        'NAME': '你的数据库名称',
        'USER': '你的MYSQL账号',
        'PASSWORD': '你的MYSQL密码',
        'HOST': '127.0.0.1',
        'PORT': '3306',
    }
}

打开CMD窗口,在D:\mysite目录下输入下面指令,测试数据连接是否成功。如图11


图11

如果没有任何提示信息,代表数据库连接成功。

3、新建一个App应用 books

打开CMD窗口,在D:\mysite目录下输入指令:如图12


图12

4、自定义model文件

在D:\mysite\books目录下,修改models.py 文件内容如下。

from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.CharField(max_length=100)
    publisher = models.CharField(max_length=100)
    publication_date = models.DateField()

    def __unicode__(self):
        return u'%s %s' % (self.title,self.authors)

创建一个书籍的数据表的模型

4、修改setttings.py文件,激活books应用

再到settings.py文件,修改INSTALLED_APPS这一项。

INSTALLED_APPS = (
    'mysite.books',
)

5、建表

打开CMD窗口,在d:\mysite目录下输入下面命令,同步你的模型到数据库。如图13


图13

6、向数据表插入一些记录

打开CMD窗口,在d:\mysite目录下,输入一些指令。如图14


图14

7、修改D:\mysite\books\views.py文件的内容

from django.shortcuts import render_to_response
from books.models import Book

def booklist(request):
    list = Book.objects.all()
    return render_to_response('booklist.html',{'books':list})

8、修改d:\mysite\url.py的内容,结果为:

urlpatterns = patterns('',
    ('^hello/$','mysite.views.hello'),
    ('^books/$','mysite.books.views.booklist'),
)

9、在D:\mysite目录下新建一个子目录templates 作为存放模板的目录

新建一个模板文件booklist.html 内容以下

<ul>
{% for book in books %}

  <li> {{book.title}} </li>

{% endfor %}
</ul>

10、修改d:\mysite\settings.py 文件

找到 TEMPLATE_DIRS项,修改内容如下:

TEMPLATE_DIRS = (
      'd:/mysite/templates'
)

最后进入mysite 这个目录,输入manage.py runserver 开启网站。 打开浏览器访问地址http://localhost:8000/books 结果如图15


图15

Python字符串常用函数

去空格及特殊符号

[codesyntax lang=”python”]

 s.strip().lstrip().rstrip(',')

[/codesyntax]

复制字符串

[codesyntax lang=”python”]

#strcpy(sStr1,sStr2)
sStr1 = 'strcpy'
sStr2 = sStr1
sStr1 = 'strcpy2'
print sStr2

[/codesyntax]

连接字符串

[codesyntax lang=”python”]

#strcat(sStr1,sStr2)
sStr1 = 'strcat'
sStr2 = 'append'
sStr1 += sStr2
print sStr1

[/codesyntax]

查找字符

[codesyntax lang=”python”]

#strchr(sStr1,sStr2)
# < 0 为未找到
sStr1 = 'strchr'
sStr2 = 's'
nPos = sStr1.index(sStr2)
print nPos

[/codesyntax]

比较字符串

[codesyntax lang=”python”]

#strcmp(sStr1,sStr2)
sStr1 = 'strchr'
sStr2 = 'strch'
print cmp(sStr1,sStr2)

[/codesyntax]

扫描字符串是否包含指定的字符

[codesyntax lang=”python”]

#strspn(sStr1,sStr2)
sStr1 = '12345678'
sStr2 = '456'
#sStr1 and chars both in sStr1 and sStr2
print len(sStr1 and sStr2)

[/codesyntax]

字符串长度

[codesyntax lang=”python”]

#strlen(sStr1)
sStr1 = 'strlen'
print len(sStr1)

[/codesyntax]

将字符串中的大小写转换

[codesyntax lang=”python”]

#strlwr(sStr1)
sStr1 = 'JCstrlwr'
sStr1 = sStr1.upper()
#sStr1 = sStr1.lower()
print sStr1

[/codesyntax]

追加指定长度的字符串

[codesyntax lang=”python”]

#strncat(sStr1,sStr2,n)
sStr1 = '12345'
sStr2 = 'abcdef'
n = 3
sStr1 += sStr2[0:n]
print sStr1

[/codesyntax]

字符串指定长度比较

[codesyntax lang=”python”]

#strncmp(sStr1,sStr2,n)
sStr1 = '12345'
sStr2 = '123bc'
n = 3
print cmp(sStr1[0:n],sStr2[0:n])

[/codesyntax]

复制指定长度的字符

[codesyntax lang=”python”]

#strncpy(sStr1,sStr2,n)
sStr1 = ''
sStr2 = '12345'
n = 3
sStr1 = sStr2[0:n]
print sStr1

[/codesyntax]

将字符串前n个字符替换为指定的字符

[codesyntax lang=”python”]

#strnset(sStr1,ch,n)
sStr1 = '12345'
ch = 'r'
n = 3
sStr1 = n * ch + sStr1[3:]
print sStr1

[/codesyntax]

扫描字符串

[codesyntax lang=”python”]

#strpbrk(sStr1,sStr2)
sStr1 = 'cekjgdklab'
sStr2 = 'gka'
nPos = -1
for c in sStr1:
    if c in sStr2:
       nPos = sStr1.index(c)
       break
    print nPos

[/codesyntax]

翻转字符串

[codesyntax lang=”python”]

#strrev(sStr1)
sStr1 = 'abcdefg'
sStr1 = sStr1[::-1]
print sStr1

[/codesyntax]

查找字符串

[codesyntax lang=”python”]

#strstr(sStr1,sStr2)
sStr1 = 'abcdefg'
sStr2 = 'cde'
print sStr1.find(sStr2)

[/codesyntax]

分割字符串

[codesyntax lang=”python”]

#strtok(sStr1,sStr2)
sStr1 = 'ab,cde,fgh,ijk'
sStr2 = ','
sStr1 = sStr1[sStr1.find(sStr2) + 1:]
print sStr1
#或者
s = 'ab,cde,fgh,ijk'
print(s.split(','))

连接字符串

[codesyntax lang=”python”]

delimiter = ','
mylist = ['Brazil', 'Russia', 'India', 'China']
print delimiter.join(mylist)

[/codesyntax]

addslashes 的实现

[codesyntax lang=”python”]

def addslashes(s):
    d = {'"':'\\"', "'":"\\'", "\0":"\\\0", "\\":"\\\\"}
    return ''.join(d.get(c, c) for c in s)

s = "John 'Johny' Doe (a.k.a. \"Super Joe\")\\\0"
print s
print addslashes(s)

[/codesyntax]

只显示字母与数字

[codesyntax lang=”python”]

def OnlyCharNum(s,oth=''):
    s2 = s.lower();
fomart = 'abcdefghijklmnopqrstuvwxyz0123456789'
for c in s2:
    if not c in fomart:
        s = s.replace(c,'');
        return s;
print(OnlyStr("a000 aa-b"))

[/codesyntax]

截取字符串

[codesyntax lang=”python”]

str = ’0123456789′
print str[0:3] #截取第一位到第三位的字符
print str[:] #截取字符串的全部字符
print str[6:] #截取第七个字符到结尾
print str[:-3] #截取从头开始到倒数第三个字符之前
print str[2] #截取第三个字符
print str[-1] #截取倒数第一个字符
print str[::-1] #创造一个与原字符串顺序相反的字符串
print str[-3:-1] #截取倒数第三位与倒数第一位之前的字符
print str[-3:] #截取倒数第三位到结尾
print str[:-5:-3] #逆序截取

[/codesyntax]

Windows安装Pycrypto

最近想着利用pysftp将本地的图片全部上传到站点服务器上去

结果却是发现他每次都提示找不到Crypto模块

没办法,只好上网找了   但是苦逼的是安装pyCrypto的时候  要么就报找不到.h头文件,要么就直接编译的时候给报错

报找不到.h文件的解决方法:

1. 直接从VS库里面将对应的.h文件放到python的include文件夹里面

2. 更改python脚本,让其在cl.exe后面添加新目录 –I <.h文件所在目录>

 

编译时错误:

[codesyntax lang=”text”]
D:\Apps\Python\module\pycrypto-2.6.1>setup.py install
running install
running build
running build_py
running build_ext
warning: GMP or MPIR library not found; Not building Crypto.PublicKey._fastmath.

building ‘Crypto.Random.OSRNG.winrandom’ extension
W:\PROGRA~2\Microsoft Visual Studio 9.0\VC\bin\cl.exe /c /nologo /Ox /MD /W3 /GS – /DNDEBUG -Isrc/ -Isrc/inc-msvc/ -ID:\Apps\Python\include -ID:\Apps\Python\PC /Tcsrc/winrand.c /Fobuild\temp.win-amd64-2.7\Release\src/winrand.obj
winrand.c
D:\Apps\Python\include\winnt.h(3019) : error C2061: 语法错误 : 标识符“PCONTEXT”
D:\Apps\Python\include\winnt.h(3020) : error C2059: 语法错误 : “}”
D:\Apps\Python\include\winbase.h(1481) : error C2061: 语法错误 : 标识符“LPCONTEXT”
D:\Apps\Python\include\winbase.h(1481) : error C2059: 语法错误 : “;”
D:\Apps\Python\include\winbase.h(2222) : error C2146: 语法错误 : 缺少“)”(在标识符“lpContext”的前面)
D:\Apps\Python\include\winbase.h(2222) : error C2081: “LPCONTEXT”: 形参表中的名称非法
D:\Apps\Python\include\winbase.h(2222) : error C2061: 语法错误 : 标识符“lpContext”
D:\Apps\Python\include\winbase.h(2222) : error C2059: 语法错误 : “;”
D:\Apps\Python\include\winbase.h(2223) : error C2059: 语法错误 : “)”
D:\Apps\Python\include\winbase.h(2230) : error C2143: 语法错误 : 缺少“)”(在“*”的前面)
D:\Apps\Python\include\winbase.h(2230) : error C2143: 语法错误 : 缺少“{”(在“*”的前面)
D:\Apps\Python\include\winbase.h(2231) : error C2059: 语法错误 : “)”
error: command ‘W:\\PROGRA~2\\Microsoft Visual Studio 9.0\\VC\\bin\\cl.exe’ failed with exit status 2
[/codesyntax]

 

找了很久 都没有找到解决办法

后来一想,算了虽然是开源的 但至少网络上已经人家已经编译好的程序 就直接进行复制得了
也省得自己耗费大量的精力去处理这些错误

功夫不负有心人,总算让我找到Windows下使用VS2008或者VS2010编译的PyCrypto应用了

 

PyCrypto 2.6:

 

PyCrypto 2.3:

 

PyCrypto 2.1:

 

好了 总算是大功告成了  暂时就先这样处理吧

同时 也欢迎诸位大神,如果能解决那个编译时错误的话 也敬请和我联系

 

本文参考至:  The Voidspace Python Module