Django—视图
2019-04-18 09:00:20来源:博客园 阅读 ()
索引
一、URLconf
二、视图
三、HttpReqeust对象
3.1 QueryDict对象
3.2 GET和POST属性
四、HttpResponse对象
4.1 子类JsonResponse
4.2 子类HttpResponseRedirect
五、状态保持
5.1 Cookie
5.2 Session
视图的功能
视图负责接受Web请求HttpRequest,进行逻辑处理,返回Web响应HttpResponse给请求者。
一、URLconf
用户通过在浏览器的地址栏中输入网址请求网站,对于Django开发的网站,由哪一个视图进行处理请求,是由url匹配找到的。
配置
1)在项目的settings.py中通过ROOT_URLCONF指定url配置,默认已经有此配置。
2)打开项目的urls.py可以看到默认配置。
注意点
-
在项目的urls.py中进行包含配置,在各自应用中创建具体配置。
-
定义urlpatterns列表,存储url()对象,这个名称是固定的。
- urlpatterns中的每个正则表达式在第一次访问它们时被编译,这使得运行很快。
语法
url()对象,被定义在django.conf.urls包中,有两种语法结构:
语法一:包含,一般在自定义应用中创建一个urls.py来定义url。
这种语法用于test3/urls.py中,目的是将应用的urls配置到应用内部,数据更清晰并且易于维护。
url(正则,include('应用.urls'))
语法二:定义,指定URL和视图函数的对应关系。
在应用内部创建urls.py文件,指定请求地址与视图的对应关系。
url(正则,'视图函数名称')
获取值
请求的url被看做是一个普通的python字符串,进行匹配时不包括域名、get或post参数。 如请求地址如下:
http://127.0.0.1:8000/delete1/?a=10
1)去除掉域名和参数部分,并将最前面的/去除后,只剩下如下部分与正则匹配。
delete1/
2)打开booktest/urls.py文件,定义与这个地址匹配的url如下:
url(r'^delete\d+/$',views.show_arg),
3)在booktest/views.py中创建视图show_arg。
def show_arg(request): return HttpResponse('show_arg')
4)启动服务器,输入上面的网址,浏览器中效果如下图。
可以在匹配过程中从url中捕获参数,每个捕获的参数都作为一个普通的python字符串传递给视图。
获取值需要在正则表达式中使用小括号,分为两种方式:
-
位置参数
-
关键字参数
注意:两种参数的方式不要混合使用,在一个正则表达式中只能使用一种参数方式。
方式一:位置参数
直接使用小括号,通过位置参数传递给视图。
1)为了提取参数,修改上面的正则表达式如下:
url(r'^delete(\d+)/$',views.show_arg),
2)修改视图show_arg如下:
注意:参数的名字是任意的如a1、b2,尽量做到见名知意。
def show_arg(request,id): return HttpResponse('show arg %s'%id)
3)刷新浏览器页面,效果如下图:
4)在地址栏输入如下地址:
http://127.0.0.1:8000/2/?a=10
5)浏览器页面效果如下图
方式二:关键字参数
在正则表达式部分为组命名。
1)修改正则表达式如下:
其中?P部分表示为这个参数定义的名称为id,可以是其它名称,起名做到见名知意。
url(r'^delete(?P<id1>\d+)/$',views.show_arg),
2)修改视图show_arg如下:
注意:视图show_arg此时必须要有一个参数名为id1,否则报错。
def show_arg(request,id1): return HttpResponse('show %s'%id1)
3)刷新浏览器页面,效果如下图
上去
二、视图
视图就是python中的函数,视图一般被定义在"应用/views.py"文件中,此例中为"booktest/views.py"文件。视图必须返回一个HttpResponse对象或子对象作为响应。响应可以是一张网页的HTML内容,一个重定向,一个404错误等。
视图的第一个参数必须为HttpRequest实例,还可能包含下参数如:
- 通过正则表达式组获得的关键字参数。
- 通过正则表达式组获取的位置参数。
内置错误视图
Django内置处理HTTP错误的视图,主要错误及视图包括:
- 404错误:page not found视图
- 500错误:server error视图
如果想看到错误视图而不是调试信息,需要修改项目的setting.py文件的DEBUG项。
DEBUG = False ALLOWED_HOSTS = ['*', ]
404错误及视图
将请求地址进行url匹配后,没有找到匹配的正则表达式,则调用404视图,这个视图会调用404.html的模板进行渲染。视图传递变量request_path给模板,表示导致错误的URL。
1)在templates中创建404.html。
2)定义代码如下:
<html> <head> <title></title> </head> <body> 找不到了 <hr/> {{request_path}} </body> </html>
3)在浏览器中输入如下网址:
http://127.0.0.1:8000/test/
4)运行效果如下图:
500错误及视图
在视图中代码运行报错会发生500错误,调用内置错误视图,使用templates/500.html模板渲染。
上去
三、HttpReqeust对象
服务器接收到http协议的请求后,会根据报文创建HttpRequest对象,这个对象不需要我们创建,直接使用服务器构造好的对象就可以。视图的第一个参数必须是HttpRequest对象,在django.http模块中定义了HttpRequest对象的API。
属性
下面除非特别说明,属性都是只读的。
-
path:一个字符串,表示请求的页面的完整路径,不包含域名和参数部分。
-
method:一个字符串,表示请求使用的HTTP方法,常用值包括:'GET'、'POST'。
-
在浏览器中给出地址发出请求采用get方式,如超链接。
-
在浏览器中点击表单的提交按钮发起请求,如果表单的method设置为post则为post请求。
-
-
encoding:一个字符串,表示提交的数据的编码方式。
-
如果为None则表示使用浏览器的默认设置,一般为utf-8。
-
这个属性是可写的,可以通过修改它来修改访问表单数据使用的编码,接下来对属性的任何访问将使用新的encoding值。
-
-
GET:QueryDict类型对象,类似于字典,包含get请求方式的所有参数。
-
POST:QueryDict类型对象,类似于字典,包含post请求方式的所有参数。
-
FILES:一个类似于字典的对象,包含所有的上传文件。
-
COOKIES:一个标准的Python字典,包含所有的cookie,键和值都为字符串。
-
session:一个既可读又可写的类似于字典的对象,表示当前的会话,只有当Django 启用会话的支持时才可用,详细内容见"状态保持"。
示例
接下来演示属性path、method、encoding,对于GET、POST、FILES、COOKIES、session后面会有详细讲解。
path、encoding
1)打开booktest/views.py文件,代码如下:
def index(request): str='%s,%s'%(request.path,request.encoding) return render(request, 'booktest/index.html', {'str':str})
2)在templates/booktest/下创建index.html文件,代码如下:
<html> <head> <title></title> </head> <body> request对象的path,encoding属性:<br/> {{ str }} <br/> </body> </html>
2)打开浏览器请求,运行效果如下图:
method
1)打开booktest/views.py文件,编写视图method_show,代码如下:
def method_show(request): return HttpResponse(request.method)
2)打开booktest/urls.py文件,新增配置如下:
url(r'^method_show/$', views.method_show),
3)修改templates/booktest/下创建index.html文件,添加代码如下:
<html> <head> <title></title> </head> <body> ... ... request对象的method属性:<br/> <a href='/method_show/'>get方式</a><br/> <form method="post" action="/method_show/"> <input type="submit" value="post方式"> </form> <br/> </body> </html>
4)打开浏览器请求:
5)浏览效果如下图:
6)点击链接,转到method_show,浏览效果如下图:
7) 回到index页面,点击按钮,转到method_post,浏览效果如下图,报错了。
8)打开项目的settings.py文件,将MIDDLEWARE_CLASSES项的csrf注释。
9)回到浏览器中刷新,浏览效果如下图,点击“继续”按钮,最终浏览效果如下图:
上去
3.1 QueryDict对象
-
定义在django.http.QueryDict
-
HttpRequest对象的属性GET、POST都是QueryDict类型的对象
-
与python字典不同,QueryDict类型的对象用来处理同一个键带有多个值的情况
-
方法get():根据键获取值
-
如果一个键同时拥有多个值将获取最后一个值
-
如果键不存在则返回None值,可以设置默认值进行后续处理
dict.get('键',默认值) 可简写为 dict['键']
-
方法getlist():根据键获取值,值以列表返回,可以获取指定键的所有值
-
如果键不存在则返回空列表[],可以设置默认值进行后续处理
dict.getlist('键',默认值)
上去
3.2 GET和POST属性
GET属性
请求格式:在请求地址结尾使用?,之后以"键=值"的格式拼接,多个键值对之间以&连接。
例:网址如下
http://127.0.0.1:8000/list/?a=10&b=20&c=python
其中的请求参数为:
a=10&b=20&c=python
-
分析请求参数,键为'a'、'b'、'c',值为'10'、'20'、'python'。
-
在Django中可以使用HttpRequest对象的GET属性获得get方方式请求的参数。
-
GET属性是一个QueryDict类型的对象,键和值都是字符串类型。
-
键是开发人员在编写代码时确定下来的。
-
值是根据数据生成的。
POST属性
使用form表单请求时,method方式为post则会发起post方式的请求,需要使用HttpRequest对象的POST属性接收参数,POST属性是一个QueryDict类型的对象。
问:表单form如何提交参数呢?
答:表单控件name属性的值作为键,value属性的值为值,构成键值对提交。
- 如果表单控件没有name属性则不提交。
- 对于checkbox控件,name属性的值相同为一组,被选中的项会被提交,出现一键多值的情况。
- 键是表单控件name属性的值,是由开发人员编写的。
- 值是用户填写或选择的。
示例
1)打开booktest/views.py文件,创建视图show_reqarg。
def show_reqarg(request): if request.method == "GET": a = request.GET.get('a') # 获取请求参数a b = request.GET.get('b') # 获取请求参数b c = request.GET.get('c') # 获取请求参数c print(a,b,c) else: # POST请求 name = request.POST.get('name') # 获取name age = request.POST.get('age') # 获取name gender = request.POST.get('gender') # 获取gender print(name, age, gender) return HttpResponse("ok")
2)打开booktest/urls.py文件,配置url。
url(r'^show_reqarg/$', views.show_reqarg),
3)修改templates/booktest目录下的index.html,添加代码如下:
提交数据的两种方式: get方式:<br/> <a href="/book/show_reqarg/?a=1&b=2&c=python">get方式提交数据</a><br/> post方式:<br/> <form method="post" action="/book/show_reqarg/"> 姓名:<input type="text" name="name"><br/> 年龄:<input type="text" name="age"><br> 性别:男<input type="radio" name="gender" value="男"/> 女<input type="radio" name="gender" value="女"/><br/> <input type="submit" value="提交"> </form>
4)运行服务器。浏览效果如下图:
5)点击链接GET方式提交数据,看控制台的输出:
6)后退到index页面,输入数据如下,
点击提交,看控制台的输出:
上去
四、HttpResponse对象
视图在接收请求并处理后,必须返回HttpResponse对象或子对象。在django.http模块中定义了HttpResponse对象的API。HttpRequest对象由Django创建,HttpResponse对象由开发人员创建。
属性
- content:表示返回的内容。
- charset:表示response采用的编码字符集,默认为utf-8。
- status_code:返回的HTTP响应状态码。
- content-type:指定返回数据的的MIME类型,默认为'text/html'。
方法
-
_init_:创建HttpResponse对象后完成返回内容的初始化。
-
set_cookie:设置Cookie信息。
set_cookie(key, value='', max_age=None, expires=None)
-
cookie是网站以键值对格式存储在浏览器中的一段纯文本信息,用于实现用户跟踪。
- max_age是一个整数,表示在指定秒数后过期。
- expires是一个datetime或timedelta对象,会话将在这个指定的日期/时间过期。
- max_age与expires二选一。
- 如果不指定过期时间,在关闭浏览器时cookie会过期。
-
delete_cookie(key):删除指定的key的Cookie,如果key不存在则什么也不发生。
-
write:向响应体中写数据。
示例
直接返回数据
1)打开booktest/views.py文件,定义视图index2如下:
def index2(request): str='<h1>HTTPResponse</h1>' return HttpResponse(str)
2)打开booktest/urls.py文件,配置url。
url(r'^index2/$',views.index2),
3)运行服务器,运行效果如下图:
如果使用这种方式构造一个漂亮丰富的页面,对于开发人员真是会发疯,于是就有了下面的方式:
调用模板
可以将html、css、js定义到一个html文件中,然后由视图来调用。
1)打开booktest/views.py文件,定义视图index3如下:
def index3(request): return render(request, 'booktest/index3.html', {'h1': 'HTTPResponse'})
2)打开booktest/urls.py文件,配置url。
url(r'^index3/$',views.index3),
3)在templates/booktest/目录下创建index3.html,代码如下:
<html> <head> <title></title> </head> <body> <h1>{{h1}}</h1> </body> </html>
4)运行服务器,运行效果如下图:
上去
4.1 子类JsonResponse
在浏览器中使用javascript发起ajax请求时,返回json格式的数据,此处以jquery的get()方法为例。类JsonResponse继承自HttpResponse对象,被定义在django.http模块中,创建对象时接收字典作为参数。
JsonResponse对象的content-type为'application/json'。
示例
1)在booktest/views.py文件中定义视图json1、json2,代码如下:
from django.http import JsonResponse ... def json1(request): return render(request,'booktest/json1.html') def json2(request): return JsonResponse({'h1':'hello','h2':'world'})
2)在booktest/urls.py文件中配置url。
url(r'^json1/$', views.json1), url(r'^json2/$', views.json2),
3)创建目录static/js/,把jquery文件拷贝到这个目录下。
4)打开项目的settings.py文件,在文件最底部,配置静态文件查找路径,并且要求开启调试
DEBUG = True ... STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), ]
5)在templates/booktest/目录下创建json1.html,代码如下:
<input type="button" value="获取json数据" id="btn"> <ul> </ul> </body> <script> $("#btn").click(function () { $.ajax({ url:'/book/json2', type: 'post', dataType:'json', }) .done(function (data) { $("ul").append("<li>"+data.a1+"</li>"); $("ul").append("<li>"+data.a2+"</li>") }) })
6)运行服务器:
7)点击按钮"获取json数据"后浏览如下图。
ajax代码执行过程如下:
- 1.发起请求。
- 2.服务器端视图函数执行。
- 3.执行回调函数。
上去
4.2 子类HttpResponseRedirect
当一个逻辑处理完成后,不需要向客户端呈现数据,而是转回到其它页面,如添加成功、修改成功、删除成功后显示数据列表,而数据的列表视图已经开发完成,此时不需要重新编写列表的代码,而是转到这个视图就可以,此时就需要模拟一个用户请求的效果,从一个视图转到另外一个视图,就称为重定向。
Django中提供了HttpResponseRedirect对象实现重定向功能,这个类继承自HttpResponse,被定义在django.http模块中,返回的状态码为302。
示例
1)在booktest/views.py文件中定义视图red1,代码如下:
from django.http import HttpResponseRedirect ... # 定义重定义向视图,转向首页 def red1(request): return HttpResponseRedirect('/book/index')
2)在booktest/urls.py文件中配置url。
url(r'^red1/$', views.red1),
3)在地址栏中输入网址如下:
http://127.0.0.1:8000/book/red1/
4)回车后,浏览器地址栏如下图。
重定向简写函数redirect
在django.shortcuts模块中为重定向类提供了简写函数redirect。
1)修改booktest/views.py文件中red1视图,代码如下:
from django.shortcuts import redirect ... def red1(request): return redirect('/book/index')
上去
五、状态保持
浏览器请求服务器是无状态的。无状态指一次用户请求时,浏览器、服务器无法知道之前这个用户做过什么,每次请求都是一次新的请求。无状态的应用层面的原因是:浏览器和服务器之间的通信都遵守HTTP协议。根本原因是:浏览器与服务器是使用Socket套接字进行通信的,服务器将请求结果返回给浏览器之后,会关闭当前的Socket连接,而且服务器也会在处理页面完毕之后销毁页面对象。
有时需要保存下来用户浏览的状态,比如用户是否登录过,浏览过哪些商品等。 实现状态保持主要有两种方式:
- 在客户端存储信息使用Cookie。
- 在服务器端存储信息使用Session。
上去
Cookie,有时也用其复数形式Cookies,指某些网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据(通常经过加密)。Cookie最早是网景公司的前雇员Lou Montulli在1993年3月的发明。Cookie是由服务器端生成,发送给User-Agent(一般是浏览器),浏览器会将Cookie的key/value保存到某个目录下的文本文件内,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)。Cookie名称和值可以由服务器端开发自己定义,这样服务器可以知道该用户是否是合法用户以及是否需要重新登录等。服务器可以利用Cookies包含信息的任意性来筛选并经常性维护这些信息,以判断在HTTP传输中的状态。Cookies最典型记住用户名。
Cookie是存储在浏览器中的一段纯文本信息,建议不要存储敏感信息如密码,因为电脑上的浏览器可能被其它人使用。
- Cookie以键值对的格式进行信息的存储。
- Cookie基于域名安全,不同域名的Cookie是不能互相访问的,如访问itcast.cn时向浏览器中写了Cookie信息,使用同一浏览器访问baidu.com时,无法访问到itcast.cn写的Cookie信息。
- 当浏览器请求某网站时,会将浏览器存储的跟网站相关的所有Cookie信息提交给网站服务器。
典型应用:记住用户名,网站的广告推送。
1)打开booktest/views.py文件,创建视图set_cookie。
def set_cookie(request): response = HttpResponse("set_cookie") response.set_cookie("name", "baiyutang") return response
2)打开booktest/urls.py文件,配置url。
url(r'^set_cookie/$',views.set_cookie),
3)在浏览器访问网址。点检查,打开network,在响应头中查看到设置的Cookie信息。点cookie也可以看cookie列表
cookie设置期限
打开booktest/views.py文件,修改视图set_cookie。
def set_cookie(request): response = HttpResponse("set_cookie") response.set_cookie("name", "baiyutang", max_age=7*24*3600) # 设置7天期限 return response
访问查看:
Cookie信息被包含在请求头中,使用request对象的COOKIES属性访问。
1)打开booktest/views.py文件,创建视图get_cookie。
def get_cookie(request): response = HttpResponse("<h1>读取cookie数据:</h1><br/>") if "name" in request.COOKIES: response.write("<h2>"+request.COOKIES["name"]+"</h2>") return response
2)打开booktest/urls.py文件,配置url。
url(r'^get_cookie/$',views.get_cookie),
3)在浏览器输入网址访问:
Cookie信息被包含在请求头中,使用request对象的COOKIES属性访问。
1)打开booktest/views.py文件,创建视图del_cookie。
def del_cookie(request): response = HttpResponse("<h1>删除cookie</h1><br/>") if "name" in request.COOKIES: response.delete_cookie("name") return response
2)打开booktest/urls.py文件,配置url。
url(r'^del_cookie/$',views.del_cookie),
3)在浏览器输入网址访问,查看cookie已经不存在了。
上去
5.2 Session
对于敏感、重要的信息,建议要储在服务器端,不能存储在浏览器中,如用户名、余额、等级、验证码等信息。
在服务器端进行状态保持的方案就是Session。
启用Session
Django项目默认启用Session。
打开项目的settings.py文件,在项MIDDLEWARE_CLASSES中启用Session中间件。
禁用Session:将Session中间件删除。
存储方式
打开项目的settings.py文件,设置SESSION_ENGINE项指定Session数据存储的方式,可以存储在数据库、缓存、Redis等。
1)存储在数据库中,如下设置可以写,也可以不写,这是默认存储方式。
SESSION_ENGINE='django.contrib.sessions.backends.db'
2)存储在缓存中:存储在本机内存中,如果丢失则不能找回,比数据库的方式读写更快。
SESSION_ENGINE='django.contrib.sessions.backends.cache'
3)混合存储:优先从本机内存中存取,如果没有则从数据库中存取。
SESSION_ENGINE='django.contrib.sessions.backends.cached_db'
4)如果存储在数据库中,需要在项INSTALLED_APPS中安装Session应用。
5)迁移后会在数据库中创建出存储Session的表。
6)表结构如下图。
由表结构可知,操作Session包括三个数据:键,值,过期时间。
所有请求者的Session都会存储在服务器中,服务器如何区分请求者和Session数据的对应关系呢?
答:在使用Session后,会在Cookie中存储一个sessionid的数据,每次请求时浏览器都会将这个数据发给服务器,服务器在接收到sessionid后,会根据这个值找出这个请求者的Session。
结果:如果想使用Session,浏览器必须支持Cookie,否则就无法使用Session了。
存储Session时,键与Cookie中的sessionid相同,值是开发人员设置的键值对信息,进行了base64编码,过期时间由开发人员设置。
对象及方法
通过HttpRequest对象的session属性进行会话的读写操作。
1) 以键值对的格式写session。
request.session['键']=值
2)根据键读取值。
request.session.get('键',默认值)
3)清除所有session,在存储中删除值部分。
request.session.clear()
4)清除session数据,在存储中删除session的整条数据。
request.session.flush()
5)删除session中的指定键及值,在存储中只删除某个键及对应的值。
del request.session['键']
6)设置会话的超时时间,如果没有指定过期时间则两个星期后过期。
request.session.set_expiry(value)
-
如果value是一个整数,会话将在value秒没有活动后过期。
-
如果value为0,那么用户会话的Cookie将在用户的浏览器关闭时过期。
-
如果value为None,那么会话永不过期。
示例
写session
1)打开booktest/views.py文件,创建视图session_test,代码如下:
def session_test(request): request.session["name"] = "hahaha" return HttpResponse("设置session")
2)打开booktest/urls.py文件,配置url。
url(r'^session_test$', session_test),
3)运行服务器,打开浏览器请求网址。浏览效果如下图,看到响应头中创建了Cookie,里面有个键为sessionid。
4)打开MySQL数据库,查看Cookie中的sessionid值为"vv6nbmmpbt71fko6du1nahdn0twbk9g2",数据表中session的键为“vv6nbmmpbt71fko6du1nahdn0twbk9g2”,是一样的,这样,服务器就可以在众多的请求者中找到对应的Session数据。
在MySQL数据库复制值,在Base64解码中进行解码查看。
读session
1)打开booktest/views.py文件,修改session_test视图如下:
def session_test(request): session_id = request.session["name"] return HttpResponse(session_id)
2)刷新浏览器效果如下图。
删除
1)打开booktest/views.py文件,修改session_test视图如下:
def session_test(request): del request.session["name"] return HttpResponse("删除session")
2)刷新浏览器,在数据库命令行中查询,发现键和值都存在,在base64解码后如下图。
如果将所有的键及值都删除,逐个调用del太麻烦,可以使用clear()方法。
删除session
1)打开booktest/views.py文件,修改session_test视图如下:
def session_test(request): request.session.flush() return HttpResponse("删除session")
2)刷新浏览器,在数据库中查询发现没有了。
使用Redis存储Session
会话还支持文件、纯cookie、Memcached、Redis等方式存储,下面演示使用redis存储。
1)安装包。
pip install django_redis
2)修改项目的settings文件,增加如下项:
# django的缓存配置 CACHES = { 'default': { 'BACKEND': 'django_redis.cache.RedisCache', 'LOCATION': 'redis://127.0.0.1:6379/1', 'OPTIONS': { 'CLIENT_CLASS': 'django_redis.client.DefaultClient' } } } # 配置session存储 SESSION_ENGINE = 'django.contrib.sessions.backends.cache' SESSION_CACHE_ALIAS = 'default'
3)打开booktest/views.py文件,修改session_test视图如下:
def session_test(request): request.session["name"] = "hahahaha" return HttpResponse("redis设置session")
4)启动redis服务
5)刷新浏览器,
在redis客户端中查看数据如下。
原文链接:https://www.cnblogs.com/ForT/p/10717285.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇:python包管理工具pip
- Django项目中使用qq第三方登录。 2019-08-13
- Django和前端用ajax传输json等数据 2019-08-13
- Django基本知识 2019-08-13
- JavaScript获取Django模板中指定键值的数据,使用过滤器 2019-08-13
- django框架使用及创建项目 2019-07-24
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash