IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Django 学习手记 三 数据操作的常用方法

    Dimpurr发表于 2016-02-04 15:45:15
    love 0

    上一篇中,我们已经建立了基本的 Model 数据模型,并且熟悉了关于数据结构的存取、更新操作。本篇中主要介绍了对 Model 数据进行操作的常用方法,包含有许多示例 参见 ,亲自操作一下就很容易明白。

    为了方便,我们可以通过 Python 在终端提供的交互式 Shell 来尝试和熟悉各种数据接口类的 API 。

    python manage.py shell

    使用这个命令会启动 Python 的交互式 Shell ,并且预先加载好 Django 所需的环境和变量。

    示例:创建和修改新对象

    涉及到的新方法:

    • all() 列出所有对象
    • save() 将该对象存入数据库

    from polls.models import Question, Choice # 导入要操作的 Model
    Question.objects.all()
    
    from django.utils import timezone
    q = Question(question_text="What's new?", pub_date=timezone.now()) # 创建一个新的 Question 对象
    q.save() # 保存后才会被写入数据库
    
    q.id # 输出属性
    q.question_text
    q.pub_date
    q.question_text = "What's up?" # 修改属性
    q.save()
    Question.objects.all()

    示例:为 Model 编写自定义方法

    因为 Question.objects.all() 的输出 [<Question: Question object>] 是一个没有任何意义的对象标识,我们可以为 Question 类型增一个 __str__ 方法。同时可以了解一下如何添加自定义方法。修改之前的 polls/models.py ,在里面加入:

    import datetime
    from django.utils import timezone
    # …
    
    class Author(models.Model):
    # …
    def __str__(self):
    return self.name
    
    class Question(models.Model):
    # ...
    def __str__(self):
    return self.question_text
    def was_published_recently(self): # 判断该 Question 是否为 1 天内添加的自定义方法
    return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
    
    class Choice(models.Model):
    # ...
    def __str__(self):
    return self.choice_text

    现在再回到交互式 Shell ,测试刚才新增的方法的效果。在 models.py 中对方法的修改并不需要重新迁移生成,就可以马上生效:

    from polls.models import Question, Choice
    Question.objects.all() # 此时的输出已经带有描述文字

    当然,如果改动了 models.py 中的数据结构,记得要重新 makemigrations 和 migrate 。

    关联对象常用方法参考

    这些方法常用在含有 ForeignKey 或 ManyToManyField 类的关联对象中。

    • add(obj1, obj2, ...) 添加新的关联
    • remove(obj1, obj2, ...) 删除关联
    • clear() 删除所有关联
    • set([obj1, obj2, …]) 直接用新的对象组覆盖已有的关联
    • count() 计数子对象数
    • delete() 删除对象
    • create() 新建关联对象并直接引用到数据库(不需要再手动保存)

    示例:数据的添加

    a1 = Author(name="dim”,email="dim@example.com")
    a2 = Author(name="ikaros",email="ikaros@example.com")
    a1.save()
    a2.save()
    q.authors.add(a1,a2) # 给 ManyToManyField 添加多个指向
    q.authors.all()
    
    q.authors.count()
    q.authors.all()[1].delete()
    q.authors.all()
    
    q.choice_set.create(choice_text='Not much', votes=0) # 在 Question 下新建一个 Choice
    q.choice_set.create(choice_text='The sky', votes=0)
    q.choice_set.all()
    
    c = q.choice_set.create(choice_text='Just hacking again', votes=0)
    c.question # 从 q.choice_set 新创建的 Choice 已经自动指向了父级 q

    其他 Model 类型方法参考

    以下是前文未提到的一些对 Model 对象实例进行操作的方法。参见

    • refresh_from_db() 将缓存中该对象的值更新为与数据库相同
    • clean_fields(exclude=None) 验证 Field 有效性
    • clean() 应当由你自行定义,提供验证 Field 是否有效和自动修复(填入数据)的功能
    • full_clean() 调用 clean_fields() 和 clean() 方法(如果有)
    • validate_unique() 类似 clean_fields() ,用于检测重复
    • save(force_insert=True, force_update=True) 启用强制插入或更新

    数据的取出、复制和筛选

    针对每个 Models ,都提供了一个称为 objects 的对象管理器 (Manager)。利用 objects 的各种方法,可以方便的进行数据的管理工作。关于筛选对象的条件语句称为 QuerySet 。

    涉及到的新方法:

    • objects.get() 获取单个对象
    • objects.filter() 获取多个对象
    • exclude() 排除符合条件的对象
    • F() 在条件语句中引用其他属性的值
    • Q() 合并复杂查询
    • update() 批量修改

    为了方便,再增加一组测试数据,然后尝试示例:

    q2 = Question(question_text=“Try another?”, pub_date=timezone.now())
    q2.save()
    
    Question.objects.get(id=1) # 根据 id 获取对象,也可以用其他 Field 的值搜索
    q3 = Question.objects.get(pk=1) # 根据主键 (Primary Key) 获取对象,在这里就是 id

    将一个对象副本的唯一标识 (pk, id 等) 删除,再重新存入,此时会自动分配 pk 或 id ,即实现了对象的复制。

    q3.pk = None
    q3.save()
    q3.pk # 可以看出 id 已经更新

    get() 只能取得一个对象,无匹配或者不止一个匹配时都会报错,而 filter() 可以取得多个匹配。

    from django.utils import timezone
    current_year = timezone.now().year
    Question.objects.get(pub_date__year=current_year) Question.objects.filter(pub_date__year=current_year)
    
    qlist = Question.objects.filter(question_text__startswith='What')
    from datetime import timedelta
    qlist2 = qlist.exclude(pub_date__gte=datetime.date.today() + timedelta(days=3))

    对 ManyToManyField 类 Field 指向的对象集,同样可以应用 get() 和 filter() 。举例来说,要获取关联了该 Question 对象的全部 Choice 对象,只需要加上一个 _set 后缀:

    q.choice_set.filter(choice_text__startswith='Just hacking')

    至于 F() 和 Q() ,使用时需要额外引用其所在的模块。

    from django.db.models import F
    Author.objects.filter(email__startswith=F('name'))
    
    from django.db.models import Q
    Question.objects.filter(Q(question_text__startswith='What'),Q(pub_date__lt=date(2011, 11, 11)) | Q(pub_date__gte=date(2012, 3, 4)))
    
    Author.objects.all().update(email="admin@example.com")
    Author.objects.all().update(email=F('name'))

    QuerySet 条件语句参考

    这里是在括号中使用的一些常用条件语句后缀,在这些条件语句中,利用双下划线区分层级来描述最终的指向,比如连接 Model 和 Field 的名称,最后再加上双下划线以及条件后缀。具体可以参考上方的示例。

    • __excat 精确等于,如果是字符则大小写也要相同
    • __contains 内容包含
    • __startswith, __endswith 开始于,结尾于
    • __iexact, __istartswith, __endswith 不精确等于, 不开始于,不结尾于
    • __gt, __gte, __lt, __lte 大于,大于等于,小于,小于等于

    本文来自 钉子の次元 - Dimpurr - an artist, designer and developer from China. ,原文地址 Django 学习手记 三 数据操作的常用方法



沪ICP备19023445号-2号
友情链接