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 提供了:

  1. 模板中表单的渲染

  2. 数据的验证工作,某一些输入不合法也不会丢失已经输入的数据。

  3. 还可以定制更复杂的验证工作,如果提供了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)    收藏  举报

导航