美文网首页
DJANGO回顾

DJANGO回顾

作者: 一把猫粮 | 来源:发表于2018-08-11 16:23 被阅读0次

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

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

相关文章

  • DJANGO回顾

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

  • django_rfw_4

    上篇回顾 为什么用Django rest_Framework框架?----首先没有Django rest_Fram...

  • 七、DRF之视图

    写在前面-->视图回顾: Django视图的使用 Django的函数视图:注意这里的 request 和 resp...

  • django源码分析--02url解析

    回顾上一章 wsgi通过ServerHandler来执行django的应用程序,第一个落地对象是,django.c...

  • django_rfw_3

    本篇内容 补充: 关于实例化 回顾 为什么用 django restframework? 关于认证、权限、节流,只...

  • 2019-11-09

    Django回顾 1 web应用本质是基于socket实现的应用程序 浏览器-----------服务器 2 ht...

  • 第一章 基础知识回顾

    django 基础知识回顾 标签: djanjo djanjo实战环境搭建 虚拟环境搭建 具体内容详见环境搭建 m...

  • About Django

    Django: 安装Django pip3 install django 创建Django工程 运行Django功...

  • Django之旅:1

    包含内容 Django简介 Django环境搭建 Django创建项目 访问Django项目 Django简介 在...

  • 难忘的301 Moved Permanently (from d

    一、事件回顾:早上django写好代码,和前端联调代码。 获取数据列表OK 获取数据详情301,但是仍然能获取到数...

网友评论

      本文标题:DJANGO回顾

      本文链接:https://www.haomeiwen.com/subject/utplbftx.html