• django中F函数的应用


    mysite/feed/models.py
    #!/usr/bin/python
    #
    -*- coding: utf-8 -*-

    from django.db import models
    from django.db.models import F

    class Account(models.Model):
    """ 账户"""
    balance = models.DecimalField('余额', max_digits=19, decimal_places=4)
    version = models.IntegerField('版本号')
    created = models.DateTimeField('创建时间', auto_now_add=True)
    updated = models.DateTimeField('最后修改时间', auto_now=True)

    def add(self, amount):
    """ 增加金额"""
    self.balance += amount
    self.save()

    self = self.__class__.objects.get(pk=self.id)

    TradeRecord(
    account=self,
    amount=amount,
    balance=self.balance,
    ).save()
    return self.balance

    def f_add(self, amount):
    """ F函数"""
    self.balance = F('balance') + amount
    self.save()

    self = self.__class__.objects.get(pk=self.id)

    TradeRecord(
    account=self,
    amount=amount,
    balance=self.balance,
    ).save()
    return self.balance

    def lock_add(self, amount):
    """ 乐观锁"""
    self.balance += amount
    self.version += 1

    new_self = self.__class__.objects.get(pk=self.id)
    print self.version, new_self.version
    if self.version > new_self.version:
    self.save()

    TradeRecord(
    account=self,
    amount=amount,
    balance=self.balance,
    ).save()
    return self.balance
    return False

    class TradeRecord(models.Model):
    """ 交易明细"""
    account = models.ForeignKey(Account)
    amount = models.DecimalField('交易金额', max_digits=19, decimal_places=4)
    balance = models.DecimalField('交易后余额', max_digits=19, decimal_places=4)
    created = models.DateTimeField('创建时间', auto_now_add=True)
    updated = models.DateTimeField('最后修改时间', auto_now=True)



    终端1

    >>> from mysite.feed.models import *
    >>> account = Account.objects.get(pk=1)
    >>> account.balance
    Decimal("9.0000")
    >>> account.add(1)
    Decimal("10.0000")
    >>> account.balance
    Decimal("10.0000")
    >>>


    终端2

    >>> from mysite.feed.models import *
    >>> account = Account.objects.get(pk=1)
    >>> account.balance
    Decimal("10.0000")
    >>> account.add(1)
    Decimal("11.0000")
    >>> account.balance
    Decimal("11.0000")
    >>>


    终端1

    >>> account.balance
    Decimal("10.0000")
    >>> account.add(1)
    Decimal("11.0000")
    >>> account.balance
    Decimal("11.0000")
    >>>

    初始值为9,在终端1进行了两次加1,终端2进行了一次加1操作,期望值为12,实际值为11。因为在终端1进行第二次加1操作时,余额已经读出为10.


    使用F函数

    终端2

    >>> from django.db.models import F
    >>> account.balance
    Decimal("11.0000")
    >>> account.balance = F('balance') + 1
    >>> account.save()
    >>> account.balance
    <django.db.models.expressions.ExpressionNode object at 0x02984850>
    >>> account = Account.objects.get(pk=1)
    >>> account.balance
    Decimal("12.0000")
    >>>


    终端1

    >>> from django.db.models import F
    >>> account.balance
    Decimal("11.0000")
    >>> account.balance = F('balance') + 1
    >>> account.save()
    >>> account.balance
    <django.db.models.expressions.ExpressionNode object at 0x029BB8B0>
    >>> account = Account.objects.get(pk=1)
    >>> account.balance
    Decimal("13.0000")
    >>>

    在终端1执行时,虽然已经读出balance的值为11,但是加1后的结果仍然是13。可以看出使用F函数进行累加,在执行Save时,始终会去取数据库中最新的值,而不是已经取出的值。所以我们可以用F函数改写add函数,来保证并发执行时数据的正确性。

    我们可以看到Django ORM在处理这两种累加在实际执行的SQL语句上的差异。

    from django.db.models import F
    from mysite.feed.models import *

    account = Account.objects.get(pk=1)
    account
    <Account: Account object>
    account.balance
    Decimal("0.0000")
    from django.db import connection
    connection.queries

    [{'time': '0.000', 'sql': u'SELECT `feed_account`.`id`, `feed_account`.`balance`, `feed_account`.`version`, `feed_account`.`created`, `feed_account`.`updated` FROM `feed_account` WHERE `feed_account`.`id` = 1 '}]

    account.balance += 1
    connection.queries

    [{'time': '0.000', 'sql': u'SELECT `feed_account`.`id`, `feed_account`.`balance`, `feed_account`.`version`, `feed_account`.`created`, `feed_account`.`updated` FROM `feed_account` WHERE `feed_account`.`id` = 1 '}]

    account.save()
    connection.queries

    [{'time': '0.000', 'sql': u'SELECT `feed_account`.`id`, `feed_account`.`balance`, `feed_account`.`version`, `feed_account`.`created`, `feed_account`.`updated` FROM `feed_account` WHERE `feed_account`.`id` = 1 '}, {'time': '0.000', 'sql': u'SELECT (1) AS `a` FROM `feed_account` WHERE `feed_account`.`id` = 1 LIMIT 1'}, {'time': '0.000', 'sql': u'UPDATE `feed_account` SET`balance` = 1.0000, `version` = 1, `created` = 2011-06-10 14:20:36, `updated` = 2011-06-10 16:00:52 WHERE `feed_account`.`id` = 1 '}]

    account.balance = F('balance') + 1
    account.save()
    connection.queries

    [{'time': '0.000', 'sql': u'SELECT `feed_account`.`id`, `feed_account`.`balance`, `feed_account`.`version`, `feed_account`.`created`, `feed_account`.`updated` FROM `feed_account` WHERE `feed_account`.`id` = 1 '}, {'time': '0.000', 'sql': u'SELECT (1) AS `a` FROM `feed_account` WHERE `feed_account`.`id` = 1 LIMIT 1'}, {'time': '0.000', 'sql': u'UPDATE `feed_account` SET `balance` = 1.0000, `version` = 1, `created` = 2011-06-10 14:20:36, `updated` = 2011-06-10 16:00:52 WHERE `feed_account`.`id` = 1 '}, {'time': '0.000', 'sql': u'SELECT (1) AS `a` FROM `feed_account` WHERE `feed_account`.`id` = 1 LIMIT 1'}, {'time': '0.000', 'sql': u'UPDATE `feed_account` SET `balance` = `feed_account`.`balance` + 1, `version` = 1, `created` = 2011-06-10 14:20:36, `updated` = 2011-06-10 16:02:21 WHERE `feed_account`.`id` = 1 '}]

    参考资料:

    https://docs.djangoproject.com/en/1.3/topics/db/queries/#filters-can-reference-fields-on-the-model

  • 相关阅读:
    一台计算机安装两个版本的MySQL
    用php实现显示上个月的最后一天
    SQL 如何去掉字段中千位的逗号(比如set @= '1,320.00' 想得到@= '1320.00' )
    jsp表单提交中的逻辑判断
    将两个字段中的值合并到一个字段中
    vue判断开始日期不能大于截至日期
    mySql中The user specified as a definer ('root'@'%') does not exist
    mysql GROUP_CONCAT给每个值加上单引号后再拼接
    javascript如何获取复选框中的值?
    mybatis中的useGeneratedKeys="true"
  • 原文地址:https://www.cnblogs.com/crafter/p/2262906.html
Copyright © 2020-2023  润新知