腾讯云Django+

准备工具

1、腾讯云服务器(当然其它的阿里云之类的也是没问题的,选择腾讯云是因为腾讯云有学生价;阿里云也有但是我一直学生认证不了。。。没办法;另外听说华为云的性能要好很多但是没有学生价)。
2、接下来是申请域名,按照官网的步骤来就可以了。
3、ssh( Secure Shell)远程访问工具,我选择的是SecureCRT。这个用于远程访问我们的服务器。
4、winSCP 由于远程传输文件。

安装部分

安装python3.6

这部分参考这篇博客

  1. 输入 sudo add-apt-repository ppa:jonathonf/python-3.6
 A plain backport of *just* Python 3.6. System extensions/Python libraries may or may not work.
Don't remove Python 3.5 from your system - it will break.
 More info: https://launchpad.net/~jonathonf/+archive/ubuntu/python-3.6
Press [ENTER] to continue or ctrl-c to cancel adding it

也就是说腾讯云服务器上默认安装了python2.7.11和python3.5.2的python版本。一般来书这两个版本也够用了。但是python新版本还是添加了一些新特性,虽然前段时间python3.7已经出来了,但是相对来说python3.6应该算是又稳定且也有大部分最新的特性。因此我选择安装3.6的版本。

现在我想要安装3.6 的版本,如果直接使用命令:

sudo apt-get install python3.6

sudo apt-get install python3.6 命令解释:
sudo在/etc/sudoers中设置了可执行sudo指令的用户。若其未经授权的用户企图使用sudo,
则会发出警告的邮件给管理员。用户使用sudo时,必须先输入密码,之后有5分钟的有效期限,
超过期限则必须重新输入密码。

apt-get 一个下载的命令参数有install 安装 update 更新 remove 移除 check 检查。
比如: sudo apt-get install samba-3.0-7 下载并安装一个名字为samba-3.0-7的程序。

我们发现是安装不了的。因为我不是经常使用linux,因此希望在使用的过程中熟悉linux的一些命令,所以对于一些命令也会做一些解释。关于apt-get更加详细的内容可以参考这里

接下来我按照网上的说明来做个安装python3.6的尝试(可能有坑):

1、 sudo add-apt-repository ppa:jonathonf/python-3.6
命令解析:
什么是ppa?
PPA,表示Personal Package Archives,也就是个人软件包集
很多软件包由于各种原因吧,不能进入官方的Ubuntu软件仓库。为了方便Ubuntu用户使用,
launchpad.net提供了ppa,允许用户建立自己的软件仓库,自由的上传软件。PPA也被用来对一些打算进入
Ubuntu官方仓库的软件,或者某些软件的新版本进行测试。
Launchpad是Ubuntu母公司canonical有限公司所架设的网站,是一个提供维护、支援或联络Ubuntu开发
者的平台。
add-apt-repositor不是内建指令,需要安装,安装命令如下:
sudo apt-get install python-software-properties 可以看到这个东西实际上是一个python脚本
添加源地址、密钥等内容,只需要一条简单的命令即可:
sudo add-apt-repository ppa:user/ppa-name

2、输入 sudo apt-get update 

3、输入命令 sudo apt-get install python3.6 

4、设置python3之间的优先级和py2和py3的优先级
python默认为Python2,现在修改为Python3:
sudo update-alternatives --install /usr/bin/python python /usr/bin/python2 100 
sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 150

通过上面这两条语句之后,python的默认版本为python3.5.1,现在要将3.5.1改为3.6:
sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.5 1
sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.6 2

5、安装pip
sudo apt-get install python3-pip

步骤1的解析参考这篇博客
步骤4关于设置命令优先级的指令参考这篇博客
亲测上面的步骤是没问题的^_^

Python虚拟环境安装以及使用

这部分参考这篇博客
主要步骤以及命令:
1、安装虚拟环境工具

在没有pip指令的情况:
sudo apt install python-virtualenv
sudo easy_install virtualenvwrapper

如果安装了pip可以使用下面的指令:
sudo pip install virtualenv
sudo pip install virtualenvwrapper

virtualenv是虚拟环境,virtualenvwrapper对virtualenv的命令进行了封装,使得其更加友好。
2、使用上面安装好的虚拟环境工具

1.创建虚拟环境:
mkvirtualenv 虚拟环境名
例如:mkvirtualenv mywork 会创建一个名为mywork的虚拟环境,创建的虚拟环境都保存在/home/.virtualenvs目录下,创建成功后会自动进入该虚拟环境。

上面的指令是使用默认的python版本,我们也可以指定python版来创建虚拟环境:
mkvirtualenvs -p python路径 虚拟环境名
例如:mkvirtualenv -p /usr/bin/python2 mywork

细节:不需要进入到/home/.virtualenvs目录,在任何目录下都可以执行命令,创建的虚拟环境的位置都一样。
注意:创建虚拟环境是需要在联网下进行,否则创建失败

可能遇到的问题:
在使用mkvirtualenv安装虚拟环境时,可能提示找不到命令,一般是脚本文件没有加入系统路径。
解决方法有两种:
第一种:
1.找到virtualenvwrapper的脚本文件:whereis virtualenvwrapper
2.进入该目录 cd /usr/local/python3/bin
3.执行脚本激活virtualenvwrapper :source virtualenvwrapper.sh
4.可以正常使用命令了。

第二种:
第一种方法每次机器重启之后会失效,要重新执行之前的操作
如果将命令添加到环境变量就可以解决这问题,一劳永逸:
1. 打开系统环境变量文件:sudo vi ~/.bashrc
2.在末尾添没次开机时我们希望系统执行的命令:source /usr/local/python3/bin/virtualenvwrapper.sh
3.保存后执行:source ~/.bashrc

2、虚拟环境的查看和使用
删除虚拟环境:rmvirtualenv [虚拟环境名称]
例如:rmvirtualenv mywork
 注意:如果目前的位置在虚拟环境中,需要先退出虚拟环境,然后才能执行删除
 注意:可以在任何目录执行删除操作,如果不知道名字,可以rmvirtualen + 两次Tab键,提示所有的虚拟环境
 
退出虚拟环境:deactivate

进入虚拟环境:workon 虚拟环境名
注意:按workon+两次tab键会提示所有的虚拟环境

查看虚拟环境中安装的python包
pip list
pip freeze

在虚拟环境中安装python包
进入虚拟环境,在终端输入:pip install 包的名字
注意:一定不要使用sudo pip,否则会安装在全局的环境中。

上面再更新了pip3之后会报错:会提示找到一个main模块:
解决方法参考这篇博客

安装Django

只需要在虚拟环境中执行pip install --user django就会直接安装最新的django包。

django极简使用方法

在安装好上面的这些基本工具之后,就可以开始创建一个django工程。

1、 到你想要将工程创建的目录下输入如下命令:
django start-project  [工程名]
2、启动开发服务器
输入命令:python manage.py runserver
或者指定端口号:python manage.py runserver 【端口号】
上面的这两条启动命令默认只监听本地连接。
如果要添加服务器连接可以使用下面的命令:
python manage.py runserver 0.0.0.0:【端口号】
这样非本地连接也可以访问服务器
3 、创建一个新的应用:
python manage.py startapp 【应用名】
4、把我们新定义的app加到settings.py中的INSTALL_APPS中
5、
修改文件:mysite/mysite/settings.py
中的:
INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
 
    'learn',
)

实现网页的hello world

在我们创建应用learn的views.py中修改内容添加一下内容:

from django.http import HttpResponse

def hello(request):
    return HttpResponse("Hello world")

显然这样写完之后我们的网页内容没有一点变化,还是停留在django的欢迎界面。
接下来我们需要将我们添加的内容和我们的网页关联起来。
配置URLconf
将现在的网页和视图配置关联起来

from django.contrib import admin
from django.urls import path
from learn import views as learn_views  # new

urlpatterns = [
        path('hello/', learn_views.index, name='index'),
    path('admin/', admin.site.urls),
]

上面有一个name属性,下面我们重点说一下这个属性的作用。

URL name详解

简单说,name 可以用于在 templates, models, views ……中得到对应的网址,相当于“给网址取了个名字”,只要这个名字不变,网址变了也能通过名字获取到。
为了进一步弄清这个问题,我们先建一个首页的视图和url:在learn这个应用的views.py中添加一下代码

def index(request):
    return render(request, 'home.html')

我们在 learn 这个 app 中新建一个 templates (文件夹的名字必须要是这个)文件夹,在templates中新建一个 home.html
文件 learn/templates/home.html 中写入以下内容:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>学习Django</title>
</head>

<body>
<a href="/add/4/5/"> 计算 4+5</a>
</body>
</html>

在上面的home.html文件中,使用了绝对的地址"/add/4/5/"作为引用。如果以后更改了页面就要一个地方一个地方修改。这里有一个解决办法:使用django提供的reverse函数可以很好的解决这个问题。下面简单的介绍一下这个函数的基本用法

reverse 接收 url 中的 name 作为第一个参数,我们在代码中就可以通过 reverse() 来获取对应的网址(这个网址可以用来跳转,也可以用来计算相关页面的地址),只要对应的 url 的name不改,就不用改代码中的网址。

不带参数的:
{% url 'name' %}
带参数的:参数可以是变量名
{% url 'name' 参数 %}
例如:
<a href="{% url 'add2' 4 5 %}">link</a>
因此之前的代码<a href="/add/4/5/"> 计算 4+5</a>
可以写成:
<a href="{% url 'add2' 4 5 %}"> 计算 4+5</a>

当 urls.py 进行更改,前提是不改 name(这个参数设定好后不要轻易改),获取的网址也会动态地跟着变。

另外,比如用户收藏夹中收藏的URL是旧的,如何让以前的 /add/3/4/自动跳转到现在新的网址呢?
具体思路是,在 views.py 写一个跳转的函数:
from django.urls import reverse  # Django 1.10.x - Django 2.x
def old_add2_redirect(request, a, b):
    return HttpResponseRedirect(
        reverse('add2', args=(a, b))
    )
    
urls.py中添加如下代码:
    path('new_add/<int:a>/<int:b>/', learn_views.old_add2_redirect),  # 这里居然不可以用正则表达式
    path('add2/<int:a>/<int:b>/', learn_views.add2, name='add2'),
    在测试的时候发现这里用正则表达式的限制起始字符的表达式的话要出错。

模板使用

网站模板的设计,一般的,我们做网站有一些通用的部分,比如 导航,底部,访问统计代码等等。nav.html, bottom.html, tongji.html

可以写一个 base.html 来包含这些通用文件(include)

<!DOCTYPE html>
<html>
<head>
    <title>{% block title %}默认标题{% endblock %} - 自强学堂</title>
</head>
<body>
 
{% include 'nav.html' %}
 
{% block content %}
<div>这里是默认内容,所有继承自这个模板的,如果不覆盖就显示这里的默认内容。</div>
{% endblock %}
 
{% include 'bottom.html' %}
 
{% include 'tongji.html' %}
 
</body>
</html>

如果需要,写足够多的 block 以便继承的模板可以重写该部分,include 是包含其它文件的内容,就是把一些网页共用的部分拿出来,重复利用,改动的时候也方便一些,还可以把广告代码放在一个单独的html中,改动也方便一些,在用到的地方include进去。其它的页面继承自 base.html 就好了,继承后的模板也可以在 block 块中 include 其它的模板文件。

比如我们的首页 home.html,继承或者说扩展(extends)原来的 base.html,可以简单这样写,重写部分代码(默认值的那一部分不用改)

{% extends 'base.html' %}
 
{% block title %}欢迎光临首页{% endblock %}
 
{% block content %}
{% include 'ad.html' %}
这里是首页,欢迎光临
{% endblock %}

注意:模板一般放在app下的templates中,Django会自动去这个文件夹中找。但 假如我们每个app的templates中都有一个 index.html,当我们在views.py中使用的时候,直接写一个 render(request, ‘index.html’),Django 能不能找到当前 app 的 templates 文件夹中的 index.html 文件夹呢?(答案是不一定能,有可能找错)

Django 模板查找机制: Django 查找模板的过程是在每个 app 的 templates 文件夹中找(而不只是当前 app 中的代码只在当前的 app 的 templates 文件夹中找)。各个 app 的 templates 形成一个文件夹列表,Django 遍历这个列表,一个个文件夹进行查找,当在某一个文件夹找到的时候就停止,所有的都遍历完了还找不到指定的模板的时候就是 Template Not Found (过程类似于Python找包)。这样设计有利当然也有弊,有利是的地方是一个app可以用另一个app的模板文件,弊是有可能会找错了。所以我们使用的时候在 templates 中建立一个 app 同名的文件夹,这样就好了。

这就需要把每个app中的 templates 文件夹中再建一个 app 的名称,仅和该app相关的模板放在 app/templates/app/ 目录下面,
这样,使用的时候,模板就是 “app1/index.html” 和 “app2/index.html” 这样有app作为名称的一部分,就不会混淆。

Django模板中的循环,条件判断,常用的标签,过滤器的使用

1、列表,字典,类的实例的使用
2、循环:迭代显示列表,字典等中的内容
3、条件判断:判断是否显示该内容,比如判断是手机访问,还是电脑访问,给出不一样的代码。
4、标签:for,if 这样的功能都是标签。
5、过滤器:管道符号后面的功能,比如{{ var|length }},求变量长度的 length 就是一个过滤器。

实例一,显示一个基本的字符串在网页上
views.py
# -*- coding: utf-8 -*-
from django.shortcuts import render
 
def home(request):
    string = u"我在自强学堂学习Django,用它来建网站"
    return render(request, 'home.html', {'string': string})
在视图中我们传递了一个字符串名称是 string 到模板 home.html,在模板中这样使用它:

home.html
{{ string }}


实例二,讲解了基本的 for 循环 和 List内容的显示
views.py
def home(request):
    TutorialList = ["HTML", "CSS", "jQuery", "Python", "Django"]
    return render(request, 'home.html', {'TutorialList': TutorialList})
在视图中我们传递了一个List到模板 home.html,在模板中这样使用它:

home.html
教程列表:
{% for i in TutorialList %}
{{ i }}
{% endfor %}


实例三,显示字典中内容:
views.py
def home(request):
    info_dict = {'site': u'自强学堂', 'content': u'各种IT技术教程'}
    return render(request, 'home.html', {'info_dict': info_dict})
    
home.html
站点:{{ info_dict.site }} 内容:{{ info_dict.content }}
还可以这样遍历字典:
{% for key, value in info_dict.items %}
    {{ key }}: {{ value }}
{% endfor %}


实例四,在模板进行 条件判断和 for 循环的详细操作:
views.py
def home(request):
    List = map(str, range(100))# 一个长度为100的 List
    return render(request, 'home.html', {'List': List})
假如我们想用逗号将这些元素连接起来:

home.html
{% for item in List %}
    {{ item }}, 
{% endfor %}
我们会发现最后一个元素后面也有一个逗号,这样肯定不爽,如果判断是不是遍历到了最后一个元素了呢?
用变量 forloop.last 这个变量,如果是最后一项其为真,否则为假,更改如下:
{% for item in List %}
    {{ item }}{% if not forloop.last %},{% endif %} 
{% endfor %}


实例五,模板上得到视图对应的网址:
# views.py
def add(request, a, b):
    c = int(a) + int(b)
    return HttpResponse(str(c))
 
# urls.py
urlpatterns = patterns('',
    url(r'^add/(\d+)/(\d+)/$', 'app.views.add', name='add'),
)
 
# template.html
{% url 'add' 4 5 %}
这样网址上就会显示出:/add/4/5/ 这个网址,假如我们以后修改 urls.py 中的 
r'^add/<int:a>/<int:b>/$'
这一部分,改成另的,比如:
r'^jiafa/<int:a>/<int:b>/$'
这样,我们不需要再次修改模板,当再次访问的时候,网址会自动变成 /jiafa/4/5/

还可以使用 as 语句将内容取别名(相当于定义一个变量),多次使用(但视图名称到网址转换只进行了一次)
{% url 'some-url-name' arg arg2 as the_url %}
<a href="{{ the_url }}">链接到:{{ the_url }}</a>

实例六,模板中的逻辑操作:
 ==, !=, >=, <=, >, < 这些比较都可以在模板中使用,比如:
{% if var >= 90 %}
成绩优秀,自强学堂你没少去吧!学得不错
{% elif var >= 80 %}
成绩良好
{% elif var >= 70 %}
成绩一般
{% elif var >= 60 %}
需要努力
{% else %}
不及格啊,大哥!多去自强学堂学习啊!
{% endif %}
(注意:比较符号前后必须有至少一个空格!)

and, or, not, in, not in 也可以在模板中使用
假如我们判断 num 是不是在 0 到 100 之间:
{% if num <= 100 and num >= 0 %}
num在0到100之间
{% else %}
数值不在范围之内!
{% endif %}
假如我们判断 'ziqiangxuetang' 在不在一个列表变量 List 中:
{% if 'ziqiangxuetang' in List %}
自强学堂在名单中
{% endif %}

实例七,模板中 获取当前网址,当前用户等:
7.1 获取当前用户:
{{ request.user }}
如果登陆就显示内容,不登陆就不显示内容:
{% if request.user.is_authenticated %}
    {{ request.user.username }},您好!
{% else %}
    请登陆,这里放登陆链接
{% endif %}

7.2.1 获取当前网址:
{{ request.path }}
7.2.2 获取当前 GET 参数:
{{ request.GET.urlencode }}
7.2.3 合并到一起用的一个例子:
<a href="{{ request.path }}?{{ request.GET.urlencode }}&delete=1">当前网址加参数 delete</a>
比如我们可以判断 delete 参数是不是 1 来删除当前的页面内容。

Django 模型(数据库)

Django 模型是与数据库相关的,与数据库相关的代码一般写在 models.py 中,Django 支持 sqlite3, MySQL, PostgreSQL等数据库,只需要在settings.py中配置即可,不用更改models.py中的代码,丰富的API极大的方便了使用。

1、修改models.py
我们打开 learn/models.py 文件,修改其中的代码如下:
from django.db import models
 
class Person(models.Model):
    name = models.CharField(max_length=30)
    age = models.IntegerField()

2、创建数据表
我们来同步一下数据库(我们使用默认的数据库 SQLite3,无需配置)
先 cd 进入 manage.py 所在的那个文件夹下,输入下面的命令
# Django 1.7 及以上的版本需要用以下命令
python manage.py makemigrations
python manage.py migrate

3、使用 Django 提供的 QuerySet API
from people.models import Person
Person.objects.create(name="WeizhongTu", age=24)
我们新建了一个用户WeizhongTu 那么如何从数据库是查询到它呢?
Person.objects.get(name="WeizhongTu")
我们用了一个 .objects.get() 方法查询出来符合条件的对象,但是大家注意到了没有,查询结果中显示<Person: Person object>,这里并没有显示出与WeizhongTu的相关信息,如果用户多了就无法知道查询出来的到底是谁,查询结果是否正确,我们重新修改一下 learn/models.py
from django.db import models
 
class Person(models.Model):
    name = models.CharField(max_length=30)
    age = models.IntegerField()
     
    def __str__(self):
        return self.name
name 和 age 等字段中不能有 __(双下划线,因为在Django QuerySet API中有特殊含义(用于关系,包含,不区分大小写,以什么开头或结尾,日期的大于小于,正则等)

Django QuerySet API
这里专门来讲一下数据库接口相关的接口(QuerySet API),当然您也可以选择暂时跳过此节,如果以后用到数据库相关的时候再看也是可以的。
从数据库中查询出来的结果一般是一个集合,这个集合叫做 QuerySet。

文中的例子大部分是基于这个 blog/models.py

from django.db import models
 
 
class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()
 
    def __str__(self):  # __str__ on Python 3
        return self.name
 
class Author(models.Model):
    name = models.CharField(max_length=50)
    email = models.EmailField()
 
    def __str__(self):  # __str__ on Python 3
        return self.name
 
class Entry(models.Model):
    blog = models.ForeignKey(Blog)
    headline = models.CharField(max_length=255)
    body_text = models.TextField()
    pub_date = models.DateField()
    mod_date = models.DateField()
    authors = models.ManyToManyField(Author)
    n_comments = models.IntegerField()
    n_pingbacks = models.IntegerField()
    rating = models.IntegerField()
 
    def __str__(self):  
        return self.headline
  1. QuerySet 创建对象的方法
from blog.models import Blog
b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
b.save()

总之,一共有四种方法
# 方法 1
Author.objects.create(name="WeizhongTu", email="[email protected]")
 
# 方法 2
twz = Author(name="WeizhongTu", email="[email protected]")
twz.save()
 
# 方法 3
twz = Author()
twz.name="WeizhongTu"
twz.email="[email protected]"
twz.save()
 
# 方法 4,首先尝试获取,不存在就创建,可以防止重复
Author.objects.get_or_create(name="WeizhongTu", email="[email protected]")
# 返回值(object, True/False)

当有一对多,多对一,或者多对多的关系的时候,先把相关的对象查询出来
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()

前三种方法返回的都是对应的 object,最后一种方法返回的是一个元组,(object, True/False),创建时返回 True, 已经存在时返回 False。

  1. 获取对象的方法(上一篇的部分代码)
Person.objects.all() # 查询所有
Person.objects.all()[:10] 切片操作,获取10个人,不支持负索引,切片可以节约内存,不支持负索引,后面有相应解决办法,第7条
Person.objects.get(name="WeizhongTu") # 名称为 WeizhongTu 的一条,多条会报错
 
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岁的
  1. 删除符合条件的结果
Person.objects.filter(name__contains="abc").delete() # 删除 名称中包含 "abc"的人
 
如果写成 
people = Person.objects.filter(name__contains="abc")
people.delete()
效果也是一样的,Django实际只执行一条 SQL 语句。
  1. 更新某个内容
    (1) 批量更新,适用于 .all() .filter() .exclude() 等后面 (危险操作,正式场合操作务必谨慎)
    Person.objects.filter(name__contains="abc").update(name='xxx') # 名称中包含 "abc"的人 都改成 xxx
    Person.objects.all().delete() # 删除所有 Person 记录

(2) 单个 object 更新,适合于 .get(), get_or_create(), update_or_create() 等得到的 obj,和新建很类似。

    twz = Author.objects.get(name="WeizhongTu")
    twz.name="WeizhongTu"
    twz.email="[email protected]"
    twz.save()  # 最后不要忘了保存!!!
  1. QuerySet 是可迭代的,比如:
es = Entry.objects.all()
for e in es:
      print(e.headline)

Entry.objects.all() 或者 es 就是 QuerySet 是查询所有的 Entry 条目。

注意事项:

(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 变成 列表

  1. 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'.
  1. QuerySet 查询结果排序
    作者按照名称排序
Author.objects.all().order_by('name')
Author.objects.all().order_by('-name') # 在 column name 前加一个负号,可以实现倒序
  1. QuerySet 支持链式查询
Author.objects.filter(name__contains="WeizhongTu").filter(email="[email protected]")
Author.objects.filter(name__contains="Wei").exclude(email="[email protected]")
 
# 找出名称含有abc, 但是排除年龄是23岁的
Person.objects.filter(name__contains="abc").exclude(age=23)
  1. QuerySet 不支持负索引
Person.objects.all()[:10] 切片操作,前10条
Person.objects.all()[-10:] 会报错!!!
 
# 1. 使用 reverse() 解决
Person.objects.all().reverse()[:2] # 最后两条
Person.objects.all().reverse()[0] # 最后一条
 
# 2. 使用 order_by,在栏目名(column name)前加一个负号
Author.objects.order_by('-id')[:20] # id最大的20条
  1. QuerySet 重复的问题,使用 .distinct() 去重
    一般的情况下,QuerySet 中不会出来重复的,重复是很罕见的,但是当跨越多张表进行检索后,结果并到一起,可能会出来重复的值(我最近就遇到过这样的问题)
qs1 = Pathway.objects.filter(label__name='x')
qs2 = Pathway.objects.filter(reaction__name='A + B >> C')
qs3 = Pathway.objects.filter(inputer__name='WeizhongTu')
 
# 合并到一起
qs = qs1 | qs2 | qs3
这个时候就有可能出现重复的
 
# 去重方法
qs = qs.distinct()

猜你喜欢

转载自blog.csdn.net/wuye999/article/details/82784618
今日推荐