DJANGO回顾

注: 以下内容为学习 涂伟忠前辈的自强学堂的课堂笔记, 用来查漏补缺.

python3 -m venv ll_env
source ll_env/bin/activate
pip install django==?
django-admin startproject project_name .
python manage.py startapp app_name
python manage.py migrate

还有要在project_name下的settings.py里面添加所有的app, 等等...

这些我是不会去细说的

下面, 是一些我个人需要熟悉的点:

视图(VIEWS)

views.py 中GET请求的获取:
1, a = request.GET['a']
2, a = request.GET.get('a', 0)
最好是用第二种, 当没有传递 a 的时候默认 a 为 0, 增加容错率

URL

urlpatterns = [
url(r'^add/(\d+)/(\d+)/$', calc_views.add, name = 'add' ),
]

其中的name = 'add', 可以用于在 templates, models, views ……中得到对应的网址,相当于“给网址取了个名字”,只要这个名字不变,网址变了也能通过名字获取到。
比如在模板中, 对于这个请求链接可以写死:
<a href="/add/4/5/">计算 4+5</a>
但如果我们改变了URL中的正则表达, 那么这个模板中的链接就失效了.
所以前辈们给出了更好的解决方法:
<a href="{% url 'add' 4 5 %}">link</a>
其中的add就是URL中的name所命的名
这个例子对应的是含参的, 不含参的直接把上边的 4 5去掉即可
<a href="{% url 'add2' %}">link</a>

另外, 引入一个实例:

  • 比如用户收藏夹中收藏的URL是旧的,如何让以前的 /add/3/4/自动跳转到现在新的网址呢?

要清楚我们需要的做的是把老的链接, 链接到也就是重定向到新的URL匹配中;
那么重定向的问题我们在视图里去写:

from django.core.urlresolvers import 

def old_add2_redirect(request, a, b):
    return HttpResponseRedirect(reverse('add2', args=(a, b)))

# URL中
 url(r'^add/(\d+)/(\d+)/$', calc_views.old_add2_redirect),
 url(r'^new_add/(\d+)/(\d+)/$', calc_views.add2, name='add2'),

这样就实现了一次我们对网站的更新换代

模板

{% include 'xxxx.html' %}, 是包含其它文件的内容,就是把一些网页共用的部分拿出来,重复利用,改动的时候也方便一些,还可以把广告代码放在一个单独的html中,改动也方便一些,在用到的地方include进去

模板支持语法:
1, 列表, 字典, 类的实例的使用 {{ info_dict.site }}
2, 循环, 迭代显示可迭代对象内容 {% for item in List %}
3, 条件判断 {% if var >= 90 %}
4, 标签 {{ the_url }}
5, 过滤器
6, 逻辑运算符, 比较运算符 {% if num <= 100 and num >= 0 %}
7, 身份判断 {% if 'ziqiangxuetang' in List %}

下面这些是for循环中很有用的东西:

{% for .. %}
...
{% empty %}
...
{% endfor %}
变量 描述
forloop.counter 索引从 1 开始算
forloop.counter0 索引从 0 开始算
forloop.revcounter 索引从最大长度到 1
forloop.revcounter0 索引从最大长度到 0
forloop.first 当遍历的元素为第一项时为真
forloop.last 当遍历的元素为最后一项时为真
forloop.parentloop 用在嵌套的 for 循环中,

注: 以下内容可以暂时不看

如果views 里面使用的不是render而是 render_ to_response, 有一个叫上下文渲染器的内容:
原文: 有时候我们想让一些内容在多个模板中都要有,比如导航内容,我们又不想每个视图函数都写一次这些变量内容,怎么办呢?
在1.8版本以后的settings.py中 的TEMPLATES下, 有 'django.template.context_processors.request',
这里的 context_processors 中放了一系列的 渲染器
上下文渲染器 其实就是函数返回字典,字典的 keys 可以用在模板中。
request 函数就是在返回一个字典,每一个模板中都可以使用这个字典中提供的 request 变量。
比如{{ request.user.username }}
下面手动写一个上下文渲染器:
在settings.py同级目录下新建一个 context_processor.py

from django.conf import settings as original_settings
 
def settings(request):
    return {'settings': original_settings}
 
def ip_address(request):
    return {'ip_address': request.META['REMOTE_ADDR']}

把新建的两个 上下文渲染器 加入到 settings.py 中的TEMPLATES下

'项目名.context_processor.settings',
'项目名.context_processor.ip_address',

在模板中直接使用, 而不用在views.py下传给模板html.

DEBUG: {{ settings.DEBUG }}
 
ip: {{ ip_address }}

以上内容可以先不看

模型(数据库)

命名字段中不能有 __ (双下划线),
因为在Django QuerySet API中有特殊含义(用于关系,包含,不区分大小写,以什么开头或结尾,日期的大于小于,正则等), 也不能有Python的关键字

新建一个对象的方法:

1.  Person.objects.create(name=name,age=age)

2.  p = Person(name="WZ", age=23)
    p.save()

3.  p = Person(name="TWZ")
    p.age = 23
    p.save()

前面三种返回的都是对应的object

4.  Person.objects.get_or_create(name="WZT", age=23)
这种方法是防止重复很好的方法,但是速度要相对慢些,返回一个元组,第一个为Person对象,第二个为True或False, 新建时返回的是True, 已经存在时返回False.

获取对象的方法:

Person.objects.all()

Person.objects.all()[:10] # 切片操作,获取10个人,不支持负索引,切片可以节约内存

Person.objects.get(name=name)# get是用来获取一个对象的,如果需要获取满足条件的一些人,就要用到filter
Person.objects.filter(name="abc")  # 等于Person.objects.filter(name__exact="abc") 名称严格等于 "abc" 的人

Person.objects.filter(name__iexact="abc")  # 名称为 abc 但是不区分大小写,可以找到 ABC, Abc, aBC,这些都符合条件
Person.objects.filter(name__contains="abc")  # 名称中包含 "abc"的人

Person.objects.filter(name__icontains="abc")  #名称中包含 "abc",且abc不区分大小写
Person.objects.filter(name__regex="^abc")  # 正则表达式查询
Person.objects.filter(name__iregex="^abc")  # 正则表达式不区分大小写

filter是找出满足条件的,当然也有排除符合某条件的

Person.objects.exclude(name__contains="WZ")  # 排除包含 WZ 的Person对象
Person.objects.filter(name__contains="abc").exclude(age=23)  # 找出名称含有abc, 但是排除年龄是23岁的

注: 以下内容可以先不看

QuerySet API

1 当有一对多,多对一,或者多对多的关系的时候,先把相关的对象查询出来

>>> from blog.models import Entry
>>> entry = Entry.objects.get(pk=1)
>>> cheese_blog = Blog.objects.get(name="Cheddar Talk")
>>> entry.blog = cheese_blog
>>> entry.save()

2 注意事项:
(1). 如果只是检查 Entry 中是否有对象,应该用 Entry.objects.all().exists()
(2). QuerySet 支持切片 Entry.objects.all()[:10] 取出10条,可以节省内存
(3). 用 len(es) 可以得到Entry的数量,但是推荐用 Entry.objects.count()来查询数量,后者用的是SQL:SELECT COUNT(*)
(4). list(es) 可以强行将 QuerySet 变成 列表

3 QuerySet 是可以用pickle序列化到硬盘再读取出来的

>>> import pickle
>>> query = pickle.loads(s)     # Assuming 's' is the pickled string.
>>> qs = MyModel.objects.all()
>>> qs.query = query            # Restore the original 'query'.

4 不支持负索引
5 去重: .distinct()
当跨越多张表进行检索后,结果并到一起,可能会出来重复的值

QuerySet进阶

from django.utils.encoding import python_2_unicode_compatible

@python_2_unicode_compatible
class Author(models.Model):
    pass

其中的python_2_unicode_compatible是为了向下兼容, 有兴趣的同学可以去看源码

1, 查看Django queryset执行的SQL语句:
>>> print(str(Author.objects.all().query))
SELECT "blog_author"."id", "blog_author"."name", "blog_author"."qq", "blog_author"."addr", "blog_author"."email" FROM "blog_author"

>>> print str(Author.objects.filter(name="WeizhongTu").query)
SELECT "blog_author"."id", "blog_author"."name", "blog_author"."qq", "blog_author"."addr", "blog_author"."email" FROM "blog_author" WHERE "blog_author"."name" = WeizhongTu

当不知道Django做了什么时, 可以把执行的SQL语句打印出来,
也可以借助 django-debug-toolbar 等工具在页面上看到访问当前页面执行了哪些SQL,耗时等。
还有一种办法就是修改一下 log 的设置...后续

2, values_list 获取元组形式结果

获取作者的 name 和 qq:

In [8]: authors = Author.objects.values_list('name', 'qq')
In [9]: authors
Out[9]: [('WeizhouTu', '545071666'), ('twz916', '099569249'), ('dachui', '686331473'), ('zhe', '643326207'), ('zhen', '063342958')]

如果只需要 1 个字段,可以指定 flat=True

In [10]: Author.objects.values_list('name', flat=True)
Out[10]: ['WeizhouTu', 'twz916', 'dachui', 'zhe', 'zhen']

In [14]: type(Author.objects.values_list('name', flat=True))
Out[14]: django.db.models.query.ValuesListQuerySet

可以通过list转换为列表
In [19]: type(list(Author.objects.values_list('name', flat=True)))
Out [19]: list

# 默认是False
In [11]: Author.objects.values_list('name')
Out[11]: [('WeizhouTu',), ('twz916',), ('dachui',), ('zhe',), ('zhen',)]

查询 twz915 这个人的文章标题, 以列表表示出来

In [11]: Article.objects.filter(author__name='twz915').values_list('title', flat=True)
3, values获取字典形式的结果
In [17]: Author.objects.values('name', 'qq')
Out[17]: [{'name': 'WeizhouTu', 'qq': '545071666'}, {'name': 'twz916', 'qq': '099569249'}, {'name': 'dachui', 'qq': '686331473'}, {'name': 'zhe', 'qq': '643326207'}, {'name': 'zhen', 'qq': '063342958'}]

注意:

  • values_list 和 values 返回的并不是真正的 列表 或 字典,也是 queryset,他们也是 lazy evaluation 的(惰性评估,通俗地说,就是用的时候才真正的去数据库查)
  • 如果查询后没有使用,在数据库更新后再使用,你发现得到的是新内容!!!如果想要旧内容保持着,数据库更新后不要变,可以 list 一下
  • 如果只是遍历这些结果,没有必要 list 它们转成列表(浪费内存,数据量大的时候要更谨慎!!!)
4, extra 实现 别名, 条件, 排序等

extra 中可实现别名,条件,排序等,后面两个用 filter, exclude 一般都能实现,排序用 order_by 也能实现。
我们主要看一下别名这个

比如 Author 中有 name, Tag 中有 name 我们想执行
SELECT name AS tag_name FROM blog_tag;

可以这样实现:

In [34]: tags = Tag.objects.all().extra(select={'tag_name':'name'})

In [35]: tags[0].name
Out[35]: 'Django教程'

In [36]: tags[0].tag_name
Out[36]: 'Django教程'

发现name 和 tag_name 都可以使用,确认一下执行的 SQL
查看以下SQL语句:

In [37]: Tag.objects.all().extra(select={'tag_name':'name'}).query.__
    ...: str__()
Out[37]: 'SELECT (name) AS "tag_name", "blog_tag"."id", "blog_tag"."name" FROM "blog_tag"'

发现查询的时候弄了两次 (name) AS "tag_name" 和 "blog_tag"."name"
如果我们只想其中一个能用,可以用 defer 排除掉原来的 name
最常见的需求就是数据转变成 list,然后可视化等,我们在下面一个里面讲。
---但是不知道为什么我这里还是都能用

5, annotate 聚合 技术, 求和, 平均数等
  • 计数
In [48]: from django.db.models import Count
In [50]: Article.objects.all().values('author_id').annotate(count=Count('author')).values('author_id', 'count')
Out[50]: [{'author_id': 3, 'count': 40}, {'author_id': 4, 'count': 20}]

查看SQL语句

In [51]: Article.objects.all().values('author_id').annotate(count=Count('author')).values('author_id', 'count').query.__str__()
Out[51]: 'SELECT "blog_article"."author_id", COUNT("blog_article"."author_id") AS "count" FROM "blog_article" GROUP BY "blog_article"."author_id"'

简化一下SQL: SELECT author_id, COUNT(author_id) AS count FROM blog_article GROUP BY author_id

获取作者名称 及 作者文章数

In [68]: Article.objects.all().values('author__name').annotate(count=
    ...: Count('author'))
Out[68]: [{'author_s_name': 'dachui', 'count': 40}, {'author__name': 'zhe', 'count': 20}]

这是跨表查询

  • 求和 与 平均值
In [70]: from django.db.models import Avg

In [71]: Article.objects.values('author_id').annotate(avg_score=Avg('score'))
Out[71]: [{'author_id': 3, 'avg_score': 84.95}, {'author_id': 4, 'avg_score': 81.45}]
  • 求一个作者所有文章的总分
In [82]: from django.db.models import Sum

In [83]: Article.objects.values('author__name').annotate(sum_scoress=
    ...: Sum('score'))
Out[83]: [{'author__name': 'dachui', 'sum_scoress': 3398}, {'author__name': 'zhe', 'sum_scoress': 1629}]
6, select_related 优化一对一, 多对一查询

开始之前我们修改一个 settings.py 让Django打印出在数据库中执行的语句
settings.py 尾部加上

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'level': 'DEBUG' if DEBUG else 'INFO',
        },
    },
}

这样当 DEBUG 为 True 的时候,我们可以看出 django 执行了什么 SQL 语句

注: 数据库查询 一个下划线 _ 查询不是跨表查询, 是自身的字段, 比如:
author = models.ForeignKey(Author)
author 关联外键到Author的主键 id, 这时候查询内容 author 等同于 author_id
而author__ 则为跨表查询, 查询的内容是Author中的字段, 比如查询
author__name, author__addr, 这name, addr都是Author类模型中的字段.

In [2]: from blog.models import *

In [3]: Author.objects.all()
Out[3]: (0.001) QUERY = 'SELECT "blog_author"."id", "blog_author"."name", "blog_author"."qq", "blog_author"."addr", "blog_author"."email" FROM "blog_author" LIMIT 21' - PARAMS = (); args=()
[<Author: WeizhouTu>, <Author: twz916>, <Author: dachui>, <Author: zhe>, <Author: zhen>]

重点来了:


In [13]: articles = Article.objects.all()[:10]   

此处没有与数据库交互

In [14]: a1 = articles[0]  
(0.000) QUERY = 'SELECT "blog_article"."id", "blog_article"."title", "blog_article"."author_id", "blog_article"."content", "blog_article"."score" FROM "blog_article" LIMIT 1' - PARAMS = (); args=()

将其第一个内容赋给其他变量时 查询了!

In [15]: a1.title  
Out[15]: 'Django教程_1'

In [16]: a1.author_id
Out[16]: 4

In [17]: a1.author.name  
(0.001) QUERY = 'SELECT "blog_author"."id", "blog_author"."name", "blog_author"."qq", "blog_author"."addr", "blog_author"."email" FROM "blog_author" WHERE "blog_author"."id" = %s' - PARAMS = (4,); args=(4,)
Out[17]: 'zhe'

此时因为有跨表查询, 所以又进行与数据库交互

这样的话我们遍历查询结果的时候就会查询很多次数据库,能不能只查询一次,把作者的信息也查出来呢?
这就要使用select_related ,

In [18]: articles = Article.objects.all().select_related('author')[:10]

In [19]: a1 = articles[0]
(0.001) QUERY = 'SELECT "blog_article"."id", "blog_article"."title", "blog_article"."author_id", "blog_article"."content", "blog_article"."score", "blog_author"."id", "blog_author"."name", "blog_author"."qq", "blog_author"."addr", "blog_author"."email" FROM "blog_article" INNER JOIN "blog_author" ON ( "blog_article"."author_id" = "blog_author"."id" ) LIMIT 1' - PARAMS = (); args=()

In [20]: a1.title
Out[20]: 'Django教程_1'

In [21]: a1.author.name
Out[21]: 'zhe'

In [22]: a1.author.addr
Out[22]: 'addr_1'

In [23]: a1.author.qq
Out[23]: '643326207'

此时, 再进行作者信息的查询便不会再与数据库进行交互了
而且, 我们可以发现, 当对数据库的查询结果赋给其他变量时, 不会立即查询, 用到哪个, 才会进行查询哪个

7, prefetch_related 优化一对多, do对多查询

和 select_related 功能类似,但是实现不同。
select_related 是使用 SQL JOIN 一次性取出相关的内容。
prefetch_related 用于 一对多,多对多 的情况,这时 select_related 用不了,因为当前一条有好几条与之相关的内容。
prefetch_related是通过再执行一条额外的SQL语句,然后用 Python 把两次SQL查询的内容关联(joining)到一起
我们来看个例子,查询文章的同时,查询文章对应的标签。“文章”与“标签”是多对多的关系。
下面来看两个例子: 一个是不适用prefetch_related进行赋值遍历查询, 另一个使用, 看有什么区别

In [33]: articles = Article.objects.all()[:3]

In [34]: for a in articles:
    ...:     print(a.title, a.tags.all())
    ...:     
(0.000) QUERY = 'SELECT "blog_article"."id", "blog_article"."title", "blog_article"."author_id", "blog_article"."content", "blog_article"."score" FROM "blog_article" LIMIT 3' - PARAMS = (); args=()
(0.000) QUERY = 'SELECT "blog_tag"."id", "blog_tag"."name" FROM "blog_tag" INNER JOIN "blog_article_tags" ON ( "blog_tag"."id" = "blog_article_tags"."tag_id" ) WHERE "blog_article_tags"."article_id" = %s LIMIT 21' - PARAMS = (1,); args=(1,)
Django教程_1 [<Tag: Django教程>]
(0.004) QUERY = 'SELECT "blog_tag"."id", "blog_tag"."name" FROM "blog_tag" INNER JOIN "blog_article_tags" ON ( "blog_tag"."id" = "blog_article_tags"."tag_id" ) WHERE "blog_article_tags"."article_id" = %s LIMIT 21' - PARAMS = (2,); args=(2,)
Django教程_2 [<Tag: Django教程>]
(0.000) QUERY = 'SELECT "blog_tag"."id", "blog_tag"."name" FROM "blog_tag" INNER JOIN "blog_article_tags" ON ( "blog_tag"."id" = "blog_article_tags"."tag_id" ) WHERE "blog_article_tags"."article_id" = %s LIMIT 21' - PARAMS = (3,); args=(3,)
Django教程_3 [<Tag: Django教程>]

可以看出, 执行的SQL语句是查询了三次, 也就是与数据库交互了三次

In [35]: articles = Article.objects.all().prefetch_related('tags')[:3
    ...: ]

In [36]: for a in articles:
    ...:     print(a.title, a.tags.all())
    ...:     
(0.002) QUERY = 'SELECT "blog_article"."id", "blog_article"."title", "blog_article"."author_id", "blog_article"."content", "blog_article"."score" FROM "blog_article" LIMIT 3' - PARAMS = (); args=()
(0.003) QUERY = 'SELECT ("blog_article_tags"."article_id") AS "_prefetch_related_val_article_id", "blog_tag"."id", "blog_tag"."name" FROM "blog_tag" INNER JOIN "blog_article_tags" ON ( "blog_tag"."id" = "blog_article_tags"."tag_id" ) WHERE "blog_article_tags"."article_id" IN (%s, %s, %s)' - PARAMS = (1, 2, 3); args=(1, 2, 3)
Django教程_1 [<Tag: Django教程>]
Django教程_2 [<Tag: Django教程>]
Django教程_3 [<Tag: Django教程>]

明显看出, 一次性查处了所有相关内容, 遍历的是查询到的结果

8, defer 排除不需要的字段

在复杂的情况下,表中可能有些字段内容非常多,取出来转化成 Python 对象会占用大量的资源。
这时候可以用 defer 来排除这些字段,比如我们在文章列表页,只需要文章的标题和作者,没有必要把文章的内容也获取出来(因为会转换成python对象,浪费内存)

In [47]: Article.objects.all().defer('content', 'score', 'author_id')

Out[47]: (0.000) QUERY = 'SELECT "blog_article"."id", "blog_article"."title" FROM "blog_article" LIMIT 21' - PARAMS = (); args=()
[<Article_Deferred_author_id_content_score: Django教程_1>, <Article_Deferred_author_id_content_score: Django教程_2>, <Article_Deferred_author_id_content_score: Django教程_3>, <Article_Deferred_author_id_content_score: Django教程_4>, <Article_Deferred_author_id_content_score: Django教程_5>, <Article_Deferred_author_id_content_score: Django教程_6>, <Article_Deferred_author_id_content_score: Django教程_7>, <Article_Deferred_author_id_content_score: Django教程_8>, <Article_Deferred_author_id_content_score: Django教程_9>, <Article_Deferred_author_id_content_score: Django教程_10>, <Article_Deferred_author_id_content_score: Django教程_11>, <Article_Deferred_author_id_content_score: Django教程_12>, <Article_Deferred_author_id_content_score: Django教程_13>, <Article_Deferred_author_id_content_score: Django教程_14>, <Article_Deferred_author_id_content_score: Django教程_15>, <Article_Deferred_author_id_content_score: Django教程_16>, <Article_Deferred_author_id_content_score: Django教程_17>, <Article_Deferred_author_id_content_score: Django教程_18>, <Article_Deferred_author_id_content_score: Django教程_19>, <Article_Deferred_author_id_content_score: Django教程_20>, '...(remaining elements truncated)...']

尝试把id defer掉, 但是好像没什么用

9, only 仅选择需要的字段

和 defer 相反,only 用于取出需要的字段,假如我们只需要查出 作者的名称, 如果再去把别的都defer掉, 那就麻烦了.

In [49]: Author.objects.all().only('name')
Out[49]: (0.000) QUERY = 'SELECT "blog_author"."id", "blog_author"."name" FROM "blog_author" LIMIT 21' - PARAMS = (); args=()
[<Author_Deferred_addr_email_qq: WeizhouTu>, <Author_Deferred_addr_email_qq: twz916>, <Author_Deferred_addr_email_qq: dachui>, <Author_Deferred_addr_email_qq: zhe>, <Author_Deferred_addr_email_qq: zhen>]
10, 自定义聚合功能 ( 比较高深, 暂未看懂 )

前面可以发现 django.db.models 中有 Count, Avg, Sum 等,也有一些没有的,比如 GROUP_CONCAT,它用来聚合时将符合某分组条件(group by)的不同的值,连到一起,作为整体返回。
新建一个文件 比如 my_aggregate.py

from django.db.models import Aggregate, CharField
 
 
class GroupConcat(Aggregate):
    function = 'GROUP_CONCAT'
    template = '%(function)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=CharField(),
            **extra        )

使用时先引入 GroupConcat 这个类,比如聚合后的错误日志记录有这些字段 time, level, info

我们想把 level, info 一样的 聚到到一起,按时间和发生次数倒序排列,并含有每次日志发生的时间。

ErrorLogModel.objects.values('level', 'info').annotate(
    count=Count(1), time=GroupConcat('time', ordering='time DESC', separator=' | ')
).order_by('-time', '-count')

以下内容可以先不看

自定义Field

Django 的官方提供了很多的 Field,但是有时候还是不能满足我们的需求,不过Django提供了自定义 Field 的方法:

1, 减少文本的长度,保存数据的时候压缩,读取的时候解压缩,如果发现压缩后更长,就用原文本直接存储:
2. 比如我们想保存一个 列表到数据库中,在读取用的时候要是 Python的列表的形式,我们来自己写一个 ListField:

Django后台

1 django-admin startprojcet name .创建好项目
2 python manage.py startapp name 创建好应用
3 修改应用中的models
4 添加到settings.py
5 迁移数据库
6 修改admin.py
from django.contrib import admin
from .models import Article
 
admin.site.register(Article)
7 打开服务器

看到显示的列表都是 xxxx object
修改应用中的models
在末尾添加如下内容

 def __unicode__(self):# 在Python3中用 __str__ 代替 __unicode__
        return self.title

就会显示self.title的内容了.

8 兼容问题: 需要向下兼容Python2
# coding:utf-8
from __future__ import unicode_literals
 
from django.db import models
from django.utils.encoding import python_2_unicode_compatible

@python_2_unicode_compatible
class Article(models.Model):
    pass

这样Django就会自适应处理python2

9 在列表显示与字段相关的其他内容

定义admin.py

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.py中

class PersonAdmin(admin.ModelAdmin):
    list_display = ('full_name',)  

注意list_display 后面需要是元祖, 记得加 , 逗号

其他功能


表单

在views.py同级目录下创建 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})

对应模板html

<form method='post'>
{% csrf_token %}
{{ form }}
<input type="submit" value="提交">
</form>

这有以下好处:

  • 模板中表单的渲染
  • 数据的验证工作,某一些输入不合法也不会丢失已经输入的数据。
  • 还可以定制更复杂的验证工作,如果提供了10个输入框,必须必须要输入其中两个以上,在 forms.py 中都很容易实现

进阶AJAX

Django配置

1 settings.py 里有一句
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))

os.path.dirname(__file__) 指的是当前文件的路径, 也就是settings.py的路径, 外面在加一层, 也就是BASE_DIR就是 项目 所在的路径了,

2 DEBUG
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
TEMPLATE_DEBUG = True

DEBUT = True 便于我们看到bug所在, 部署的时候记得False掉

3 ALLOWED_HOSTS

ALLOWED_HOSTS = ['*.besttome.com','www.ziqiangxuetang.com']
ALLOWED_HOSTS 允许你设置哪些域名可以访问,即使在 Apache 或 Nginx 等中绑定了,这里不允许的话,也是不能访问的。

当 DEBUG=False 时,这个为必填项,如果不想输入,可以用 ALLOW_HOSTS = ['*'] 来允许所有的。

4 STATIC
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也能找到它们。

5 MEDIA
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR,'media')

media文件夹用来存放用户上传的文件, 详情见后

有时候有一些模板不是属于app的,比如 baidutongji.html, share.html等,

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 文件夹中了。

静态文件

当运行 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/',  # 用不到的时候可以不写这一行
)

静态文件放在对应的 app 下的 static 文件夹中 或者 STATICFILES_DIRS 中的文件夹中。
当 DEBUG = True 时,Django 就能自动找到放在里面的静态文件。

部署Nginx

自强学堂 + uWSGI

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,377评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,390评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,967评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,344评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,441评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,492评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,497评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,274评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,732评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,008评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,184评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,837评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,520评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,156评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,407评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,056评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,074评论 2 352

推荐阅读更多精彩内容