Django教程(三)基础:后台、表单、配置、静态文件
一、后台
django的后台我们只要加少些代码,就可以实现强大的功能。与台相关文件:每个app中的 admin.py 文件与后台相关。
进入 blog应用,修改 admin.py 文件(如果没有新建一个),内容如下
from django.contrib import admin from .models import Article # 导入要管理的model admin.site.register(Article) # 注册要管理的model
只需要这三行代码,我们就可以拥有一个强大的后台!提示:urls.py中关于 admin的已经默认开启。
进入管理台页面:http://127.0.0.1:9001/admin 可以看到上面注册的数据库BLOG/Articles。
如果没有帐号,则创建:python manage.py createsuperuser --username jerry
1.添加数据:打开Articles,Add
2.添加__str__方法:
所有文章的标题都是一样的,Article object。要显示可识别的标题,需在Model中添加__str__方法
# blog/models.py class Article(models.Model): title = models.CharField(max_length=60) author = models.ForeignKey(Author) content = models.TextField() score = models.IntegerField() tags = models.ManyToManyField('Tag') def __str__(self): return self.title #这个实例,返回的是title标题字段
3.让model兼容pytho2和pyhton3,使用@python_2_unicode_compatible
from __future__ import unicode_literals @python_2_unicode_compatible class Article(models.Model): #省略其它代码...... def __str__(self): return self.title
python_2_unicode_compatible 会自动做一些处理去适应python不同的版本,本例中的 unicode_literals 可以让python2.x 也像 python3 那个处理 unicode 字符,以便有更好地兼容性。
4.在列表中显示与字段相关的其它内容: list_display = (...)
后台已经基本上做出来了,现在只显示了标题title,可是如果我们还需要显示一些其它的fields,如何做呢?添加一个ModelAdmin的类,并将它与Model都注册。
在admin.py中,添加ModelAdmin,如ArticleAdmin,使用list_display指出要显示的字段:
from django.contrib import admin from .models import Article class ArticleAdmin(admin.ModelAdmin): list_display = ('title','pub_date','update_time',) admin.site.register(Article,ArticleAdmin)
list_display 就是来配置要显示的字段的,当然也可以显示非字段内容,或者字段相关的内容。比如:
# models.py class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) def my_property(self): return self.first_name + ' ' + self.last_name my_property.short_description = "Full name of the person" full_name = property(my_property) #admin from django.contrib import admin from .models import Person class PersonAdmin(admin.ModelAdmin): list_display = ('full_name',) #这里的fullname并不是字段;显示的是其它内容 admin.site.register(Person, PersonAdmin)
注:list_display能显示的内容,要除了多对多关系的字段。
如果要添加新的字段,如文章的状态(草稿,已发布),需要在models.py 中Model添加或更改字段。
5.搜索功能:search_fields = (...)
#admin.py #其它代码省略 class ArticleAdmin(admin.ModelAdmin): list_display = ('title', 'author','score') search_fields = ['title', 'score'] #按照标题或分数搜索
6.筛选功能:list_filter = ('status',) 这样就可以根据文章的状态去筛选,比如找出是草稿的文章
7.新增或修改时的布局顺序:
#admin.py from django.contrib import admin class FlatPageAdmin(admin.ModelAdmin): fieldsets = ( (None, { 'fields': ('url', 'title', 'content', 'sites') }), ('Advanced options', { 'classes': ('collapse',), 'fields': ('registration_required', 'template_name'), }), )
二、admin的一些实例
实例1.定制加载的列表, 根据不同的人显示不同的内容列表,比如输入员只能看见自己输入的,审核员能看到所有的草稿,这时候就需要重写get_queryset方法
#admin.py class MyModelAdmin(admin.ModelAdmin): def get_queryset(self, request): qs = super(MyModelAdmin, self).get_queryset(request) if request.user.is_superuser: return qs else: return qs.filter(author=request.user)
该类实现的功能是如果是超级管理员就列出所有的,如果不是,就仅列出访问者自己相关的
实例2.定制搜索功能
class PersonAdmin(admin.ModelAdmin): list_display = ('name', 'age') search_fields = ('name', ) def get_search_results(self, request, queryset, search_term): queryset, use_distinct = super(PersonAdmin, self).get_search_results(request, queryset, search_term) try: search_term_as_int = int(search_term) queryset = self.model.objects.filter(age=search_term_as_int) except: pass return queryset, use_distinct
queryset 是默认的结果,search_term 是在后台搜索的关键词
实例3.修改保存时的一些操作,可以检查用户,保存的内容等,比如保存时加上添加人
from django.contrib import admin class ArticleAdmin(admin.ModelAdmin): def save_model(self, request, obj, form, change): obj.user = request.user obj.save()
其中obj是修改后的对象,form是返回的表单(修改后的),当新建一个对象时 change = False, 当修改一个对象时 change = True
如果需要获取修改前的对象的内容可以用
class ArticleAdmin(admin.ModelAdmin): def save_model(self, request, obj, form, change): obj_original = self.model.objects.get(pk=obj.pk) obj.user = request.user obj.save()
那么又有问题了,这里如果原来的obj不存在,也就是如果我们是新建的一个怎么办呢,这时候可以用try,except的方法尝试获取,当然更好的方法是判断一下这个对象是新建还是修改,是新建就没有 obj_original,是修改就有
class ArticleAdmin(admin.ModelAdmin): def save_model(self, request, obj, form, change): if change: # 更改的时候 obj_original = self.model.objects.get(pk=obj.pk) else: # 新增的时候 obj_original = None obj.user = request.user obj.save()
4, 删除时做一些处理,
class ArticleAdmin(admin.ModelAdmin): def delete_model(self, request, obj): """ Given a model instance delete it from the database. """ # handle something here obj.delete()
三、表单FORM
1.有时候我们需要在前台用 get 或 post 方法提交一些数据,用到表单。示例:写一个计算 a和 b 之和的简单应用,网页上这么写
<!DOCTYPE html> <html> <body> <p>请输入两个数字</p> <form action="/add/" method="get"> a: <input type="text" name="a"> <br> b: <input type="text" name="b"> <br> <input type="submit" value="提交"> </form> </body> </html>
把这些代码保存成一个index.html,放在 templates 文件夹中。
网页的值传到服务器是通过 <input> 或 <textarea>标签中的 name 属性来传递的,在服务器端这么接收:
from django.http import HttpResponse
from django.shortcuts import render
def index(request):
return render(request, 'index.html')
def add(request):
a = request.GET['a']
b = request.GET['b']
a = int(a)
b = int(b)
return HttpResponse(str(a+b))
request.GET 可以看成一个字典,用GET方法传递的值都会保存到其中,可以用 request.GET.get('key', None)来取值,没有时不报错。
前端+后端,这样就完成了基本的功能,基本上可以用了。
但是,比如用户输入的不是数字,而是字母,就出错了,还有就是提交后再回来已经输入的数据也会没了。
当然如果我们手动将输入之后的数据在 views 中都获取到再传递到网页,这样是可行的,但是很不方便,所以 Django 提供了更简单易用的 forms 来解决验证等这一系列的问题。
2.Django 的 表单 (forms)
示例:在应用程序目录,新建一个 forms.py 文件
from django import forms class AddForm(forms.Form): a = forms.IntegerField() b = forms.IntegerField()
在视图函数 views.py 中
# coding:utf-8 from django.shortcuts import render from django.http import HttpResponse # 引入我们创建的表单类 from .forms import AddForm def index(request): if request.method == 'POST':# 当提交表单时 form = AddForm(request.POST) # form 包含提交的数据 if form.is_valid():# 如果提交的数据合法 a = form.cleaned_data['a'] b = form.cleaned_data['b'] return HttpResponse(str(int(a) + int(b))) else:# 当正常访问时 form = AddForm() return render(request, 'index.html', {'form': form})
对应的模板文件 index.html
<form method='post'> {% csrf_token %} {{ form }} <input type="submit" value="提交"> </form>
再在 urls.py 中对应写上这个函数
from django.conf.urls import patterns, include, url from django.contrib import admin urlpatterns = patterns('', # 注意下面这一行 url(r'^$', 'tools.views.index', name='home'), url(r'^admin/', include(admin.site.urls)), )
可能觉得这样变得更麻烦了,有些情况是这样的,但是 Django 的 forms 提供了:
-
模板中表单的渲染
-
数据的验证工作,某一些输入不合法也不会丢失已经输入的数据。
-
还可以定制更复杂的验证工作,如果提供了10个输入框,必须必须要输入其中两个以上,在 forms.py 中都很容易实现
也有一些将 Django forms 渲染成 Bootstrap 的插件,更美观,也很好用,很方便。
四、配置settings
运行 django-admin.py startproject [project-name] 命令会生成一系列文件,在Django 1.6版本以后的 settings.py 文件中有以下语句:
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) import os BASE_DIR = os.path.dirname(os.path.dirname(__file__))
这里用到了python中一个神奇的变量 __file__ 这个变量可以获取到当前文件(包含这个代码的文件)的路径。os.path.dirname(__file__) 得到文件所在目录,再来一个os.path.dirname()就是目录的上一级,BASE_DIR 即为 项目 所在目录。我们在后面的与目录有关的变量都用它,这样使得移植性更强。
# SECURITY WARNING: don't run with debug turned on in production! DEBUG = True TEMPLATE_DEBUG = True
DEBUG=True 时,如果出现 bug 便于我们看见问题所在,但是部署时最好不要让用户看见bug的详情,可能一些不怀好心的人攻击网站,造成不必要的麻烦。
ALLOWED_HOSTS = ['*.besttome.com','www.ziqiangxuetang.com']
ALLOWED_HOSTS 允许你设置哪些域名可以访问,即使在 Apache 或 Nginx 等中绑定了,这里不允许的话,也是不能访问的。注意:不是允许哪些客户端能访问,而是允许客户端能访问主机的哪些URL
当 DEBUG=False 时,这个为必填项,如果不想输入,可以用 ALLOW_HOSTS = ['*'] 来允许所有的。
STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR,'static')
static 是静态文件所有目录,比如 jquery.js, bootstrap.min.css 等文件。
一般来说我们只要把静态文件放在 APP 中的 static 目录下,部署时用 python manage.py collectstatic 就可以把静态文件收集到(复制到) STATIC_ROOT 目录,但是有时我们有一些共用的静态文件,这时候可以设置 STATICFILES_DIRS 另外弄一个文件夹,如下:
STATICFILES_DIRS = ( os.path.join(BASE_DIR, "common_static"), '/var/www/static/', )
这样我们就可以把静态文件放在 common_static 和 /var/www/static/中了,Django也能找到它们。
MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR,'media')
media文件夹用来存放用户上传的文件,与权限有关,详情见 Django 静态文件 和 Django 部署
有时候有一些模板不是属于app的,比如 baidutongji.html, share.html等,
Django 1.5 - Django 1.7
TEMPLATE_DIRS = ( os.path.join(BASE_DIR, 'templates').replace('\\', '/'), os.path.join(BASE_DIR, 'templates2').replace('\\', '/'), # ... )
Django 1.8 及以上版本
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [ os.path.join(BASE_DIR,'templates').replace('\\', '/'), os.path.join(BASE_DIR,'templates2').replace('\\', '/'), ], 'APP_DIRS': True, ]
这样 就可以把模板文件放在 templates 和 templates2 文件夹中了。
五、静态文件
静态文件是指 网站中的 js, css, 图片,视频等文件
settings.py 静态文件相关示例代码及说明:
# Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.8/howto/static-files/ STATIC_URL = '/static/' # 当运行 python manage.py collectstatic 的时候 # STATIC_ROOT 文件夹 是用来将所有STATICFILES_DIRS中所有文件夹中的文件,以及各app中static中的文件都复制过来 # 把这些文件放到一起是为了用apache等部署的时候更方便 STATIC_ROOT = os.path.join(BASE_DIR, 'collected_static') # 其它 存放静态文件的文件夹,可以用来存放项目中公用的静态文件,里面不能包含 STATIC_ROOT # 如果不想用 STATICFILES_DIRS 可以不用,都放在 app 里的 static 中也可以 STATICFILES_DIRS = ( os.path.join(BASE_DIR, "common_static"), '/path/to/others/static/', # 用不到的时候可以不写这一行 ) # 这个是默认设置,Django 默认会在 STATICFILES_DIRS中的文件夹 和 各app下的static文件夹中找文件 # 注意有先后顺序,找到了就不再继续找了 STATICFILES_FINDERS = ( "django.contrib.staticfiles.finders.FileSystemFinder", "django.contrib.staticfiles.finders.AppDirectoriesFinder" )
静态文件放在对应的 app 下的 static 文件夹中 或者 STATICFILES_DIRS 中的文件夹中。
当 DEBUG = True 时,Django 就能自动找到放在里面的静态文件。(Django 通过 STATICFILES_FINDERS 中的“查找器”,找到符合的就停下来,寻找的过程 类似于 Python 中使用 import xxx 时,找 xxx 这个包的过程)。
示例项目 dj18static, 应用 app 下面有一个 static 里面有一个 zqxt.png 图片:
dj18static ├── blog │ ├── __init__.py │ ├── admin.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── static # 应用 blog 下的 static, 默认会找这个文件夹 │ │ └── 【zqxt.png】 │ ├── tests.py │ │ │ └── views.py ├── common_static # 已经添加到了 STATICFILES_DIRS 的文件夹 │ └── js │ └── 【jquery.js】 │ ├── dj18static │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py └── manage.py
当 settings.py 中的 DEBUG = True 时,打开开发服务器 python manage.py runserver 直接访问 /static/x.png 就可以找到这个静态文件。
也可以在 settings.py 中指定所有 app 共用的静态文件,比如 jquery.js 等
STATICFILES_DIRS = ( os.path.join(BASE_DIR, "common_static"), )
把 jquery.js 放在 common_static/js/ 下,这样就可以 在 /static/js/jquery.js 中访问到它!
其它参考办法(当你想为静态文件分配多个不同的网址时,可能会用上这个):
当然也可以自己指定静态文件夹, 在urls.py的最后边这样写
# static files import os from django.conf.urls.static import static from django.conf import settings if settings.DEBUG: media_root = os.path.join(settings.BASE_DIR, 'media2') urlpatterns += static('/media2/', document_root=media_root)
也可以这样
from django.conf.urls.static import static urlpatterns = ... urlpatterns += static('/media2/', document_root=media_root)
部署时
1. 收集静态文件
python manage.py collectstatic
这一句话就会把以前放在app下static中的静态文件全部拷贝到 settings.py 中设置的 STATIC_ROOT 文件夹中
2/用 apache2 或 nginx 示例代码,apache2配置文件
Alias /static/ /path/to/collected_static/
<Directory /path/to/collected_static>
Require all granted
</Directory>
nginx 示例代码:
location /media { alias /path/to/project/media; } location /static { alias /path/to/project/collected_static; }
Apache 完整的示例代码:
<VirtualHost *:80> ServerName www.baidu.comcom ServerAlias baidu.com ServerAdmin jerry@163.com Alias /media/ /path/to/media/ Alias /static/ /path/to/collected_static/ <Directory /path/to/media> Require all granted </Directory> <Directory /path/to/collected_static> Require all granted </Directory> WSGIScriptAlias / /path/to/prj/prj/wsgi.py <Directory /path/to/prj/prj> < Files wsgi.py> Require all granted </Files> </Directory> </VirtualHost>
如果你用的是apache 2.2 版本 用下面的代替 Require all granted 赋予权限
Order allow,deny Allow from all
posted on 2014-06-03 20:28 myworldworld 阅读(199) 评论(0) 收藏 举报
浙公网安备 33010602011771号