Django技巧

2019-09-09
2分钟阅读时长

Model 相关操作

反向外键

class DictKanaItem(models.Model):
        # ....

class DictKanjiItem(models.Model):
        kana = models.ForeignKey('DictKanaItem', related_name='kanji', on_delete=models.PROTECT)
        # Onetoone 同理
        update_date = models.DateField('更新时间', auto_now=True)
        create_time = models.DateTimeField('创建时间', auto_now_add=True, null=True)

可以使用 DictKanaItem.kanji (列表) 和 DictKanjiItem.kana 双向查询

F 运算

用于动态运算

record_item = RecordItem.object.filter(sex=1).first()  # 一个 QuerySet
record_item.score = F('score') + 1  # score = score + 1
record_item.save()  # 每运行一次 save 都会 +1

数据库的 Bitwise 操作

获取 number 字段第一位为 1 的所有行(相当于所有奇数)

result = Item.objects.extra(where=['number & 1 = 1'])
# 相当于数据库的 where number & 1 = 1

事物锁

处理并发情况保持数据一致性可以使用乐观锁或者悲观锁

悲观锁

锁住某个资源, 不让其他人使用(排他), 直到完成工作后释放

# 外面需要 @transaction.atomic 或者 with transaction.atomic():
# 使用 select_for_update 可以确保该资源可以被唯一的占用直到事物结束
item = RecordItem.objects.select_for_update().get(id=1)
# some operation
item.save()

乐观锁

正常运行, 如果发现失败就进行回滚

with transaction.atomic():
        # some operation
        for i in range(1,5):
                # 直接修改, 如果成功的行数为 1 表示修改成功
                updated = RecordItem.objects.filter(id=1).update(key=value)
                if updated > 0:
                        return 'OK'
        # 连续多次修改失败
        transaction.rollback()
        return 'Failed'

批量操作

使用批量操作的方式可以简化 SQL 操作以提升速度

RecordItem.objects.filter(sex=1).update(sex=0)   # 批量修改
RecordItem.objects.filter(sex=1).delete()        # 批量删除

# 多个不同对象 save 用 bulk_update
record_item[0].sex=0
# record_item.save()    # Bad
record_item[1].sex=1
# record_item.save()    # Bad
RecordItem.objects.bulk_update(record_item, ['sex'])    # Better

# Manytomany 字段操作
# ManyToMany 的和添加或删除使用一个 .add() 或 .remove()
my_band.members.add(me, my_friend)
# my_band.members.remove(me)           # Bad
# my_band.members.remove(my_friend)    # Bad
my_band.members.remove(me, my_friend)  # Better
# bulk_create
RecordItem.objects.bulk_create([                  # 批量新建
        RecordItem(sex=1)
        RecordItem(sex=1)
])

字段为 DateTimeField,通过日期查询

__date 可以将 DateTime 转为 Date

import datetime

date = datetime.datetime.strptime('2019-09-09', '%Y-%m-%d').date()
result = Item.objects.filter(time__date=date)

数据库相关

查看 database 占用的磁盘空间

select TABLE_NAME, concat(truncate(data_length/1024/1024,2),' MB') as data_size,
	concat(truncate(index_length/1024/1024,2),' MB') as index_size
	from information_schema.tables where TABLE_SCHEMA = 'database_name'
	order by data_length desc;
下一页 PostgreSQL