- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个 Django 模型(我们称它为 ObjectLog),其中许多模型通过外键与单个对象相关。请参阅下面的简要定义:
class ObjectLog(models.Model):
class Meta:
ordering = ['-created','-N']
unique_together = ("object","N")
object = models.ForeignKey(Object, null=False)
created = models.DateTimeField(auto_now_add=True)
issuer = models.ForeignKey(User)
N = models.IntegerField(null=False)
与单个对象相关的每个 ObjectLog 都应具有唯一的 N 值(如 unique_together
要求所示)。另一种表达方式是 N 本质上应该是一个自动增量字段,但仅相对于为单个对象设置的 ObjectLog。使用自定义保存方法从逻辑上讲这不是一件难事:
def save(self, *args, **kwargs):
with transaction.atomic():
logs = self.object.objectlog_set.select_for_update().order_by('-N')
if logs:
self.N = logs[0].N + 1
else:
self.N = 1
super(ObjectLog, self).save(*args, **kwargs)
但是,我在处理并发时遇到了麻烦。当多个进程同时尝试为单个对象创建 ObjectLog 时,它们通常以相同的 N 值结束,从而导致错误,如“Duplicate entry\'249244-169\' for key”。我试图通过在我的 save
方法中使用 transaction.atomic
和 select_for_update
来处理这个问题,尽管我现在意识到原子性是不是真的会在这里帮助我的属性(property)。看起来我需要某种方法来锁定 ObjectLog 表中与相关对象相关的行,同时代码确定 N 应该是什么并保存新行,但我不知道该怎么做。
我正在使用 Django 1.8 和 MySQL 5.5 以及 MyISAM 引擎。我还尝试修改有问题的表以使用 InnoDB。使用 InnoDB 时,我收到类似“1213,\'尝试获取锁时发现死锁;尝试重新启动事务\'”的错误。所以看起来好像锁定在这种情况下有效,但也许我做得过头了?一个糟糕的解决方案是捕获这些错误并使用 while 循环强制重试保存方法,但我真的不想这样做。
非常感谢任何建议!如果我误用了一些术语,我深表歉意,我是这个领域的新手。如果我遗漏了一些重要信息,我很乐意提供更多信息。
最佳答案
我最终通过构造和执行原始 SQL 查询来在单个数据库事务中执行自动增量和插入来解决问题。我花了很多时间仔细研究 Django 源代码,以了解他们默认的模型保存方法是如何工作的,这样我就可以尽可能稳健地做到这一点。但是,我完全预计这将需要针对非 MySQL 后端进行修改。
首先,我创建了一个抽象类,ObjectLog 现在将派生自它,它具有这个新的保存方法:
class AutoIncrementModel(models.Model):
"""
An abstract class used as a base for classes which need the
autoincrementing save method described below.
"""
class Meta:
abstract = True
def save(self, auto_field, auto_fk, *args, **kwargs):
"""
Arguments:
auto_field: name of field which acts as an autoincrement field.
auto_fk: name of ForeignKey to which the auto_field is relative.
"""
# Do normal save if this is not an insert (i.e., the instance has a
# primary key already).
meta = self.__class__._meta
pk_set = self._get_pk_val(meta) is not None
if pk_set:
super(ObjectLog, self).save(*args, **kwargs)
return
# Otherwise, we'll generate some raw SQL to do the
# insert and auto-increment.
# Get model fields, except for primary key field.
fields = meta.local_concrete_fields
if not pk_set:
fields = [f for f in fields if not
isinstance(f, models.fields.AutoField)]
# Setup for generating base SQL query for doing an INSERT.
query = models.sql.InsertQuery(self.__class__._base_manager.model)
query.insert_values(fields, objs=[self])
compiler = query.get_compiler(using=self.__class__._base_manager.db)
compiler.return_id = meta.has_auto_field and not pk_set
fk_name = meta.get_field(auto_fk).column
with compiler.connection.cursor() as cursor:
# Get base SQL query as string.
for sql, params in compiler.as_sql():
# compiler.as_sql() looks like:
# INSERT INTO `table_objectlog` VALUES (%s,...,%s)
# We modify this to do:
# INSERT INTO `table_objectlog` SELECT %s,...,%s FROM
# `table_objectlog` WHERE `object_id`=id
# NOTE: it's unlikely that the following will generate
# a functional database query for non-MySQL backends.
# Replace VALUES (%s, %s, ..., %s) with
# SELECT %s, %s, ..., %s
sql = re.sub(r"VALUES \((.*)\)", r"SELECT \1", sql)
# Add table to SELECT from and ForeignKey id corresponding to
# our autoincrement field.
sql += " FROM `{tbl_name}` WHERE `{fk_name}`={fk_id}".format(
tbl_name=meta.db_table,
fk_name=fk_name,
fk_id=getattr(self, fk_name)
)
# Get index corresponding to auto_field.
af_idx = [f.name for f in fields].index(auto_field)
# Put this directly in the SQL. If we use parameter
# substitution with cursor.execute, it gets quoted
# as a literal, which causes the SQL command to fail.
# We shouldn't have issues with SQL injection because
# auto_field should never be a user-defined parameter.
del params[af_idx]
sql = re.sub(r"((%s, ){{{0}}})%s".format(af_idx),
r"\1IFNULL(MAX({af}),0)+1", sql, 1).format(af=auto_field)
# IFNULL(MAX({af}),0)+1 is the autoincrement SQL command,
# {af} is substituted as the column name.
# Execute SQL command.
cursor.execute(sql, params)
# Get primary key from database and set it in memory.
if compiler.connection.features.can_return_id_from_insert:
id = compiler.connection.ops.fetch_returned_insert_id(cursor)
else:
id = compiler.connection.ops.last_insert_id(cursor,
meta.db_table, meta.pk.column)
self._set_pk_val(id)
# Refresh object in memory in order to get auto_field value.
self.refresh_from_db()
然后 ObjectLog 模型像这样使用它:
class ObjectLog(AutoIncrementModel):
class Meta:
ordering = ['-created','-N']
unique_together = ("object","N")
object = models.ForeignKey(Object, null=False)
created = models.DateTimeField(auto_now_add=True)
issuer = models.ForeignKey(User)
N = models.IntegerField(null=False)
def save(self, *args, **kwargs):
# Set up to call save method of the base class (AutoIncrementModel)
kwargs.update({'auto_field': 'N', 'auto_fk': 'event'})
super(EventLog, self).save(*args, **kwargs)
这允许对 ObjectLog.save() 的调用仍然按预期工作。
关于python - 具有相同外键的对象的类自动增量字段(Django 1.8、MySQL 5.5),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43265818/
在有些场景下,我们需要对我们的varchar类型的字段做修改,而修改的结果为两个字段的拼接或者一个字段+字符串的拼接。 如下所示,我们希望将xx_role表中的name修改为name+id。
SELECT incMonth as Month, SUM( IF(item_type IN('typ1', 'typ2') AND incMonth = Month, 1, 0 ) )AS
我最近读到 volatile 字段是线程安全的,因为 When we use volatile keyword with a variable, all the threads read its va
我在一些模型中添加了一个 UUID 字段,然后使用 South 进行了迁移。我创建的任何新对象都正确填充了 UUID 字段。但是,我所有旧数据的 UUID 字段为空。 有没有办法为现有数据填充 UUI
刚刚将我的网站从 mysql_ 更新为 mysqli,并破坏了之前正常运行的查询。 我试图从旋转中提取 id,因为它每次都会增加 1,但我不断获取玩家 id,有人可以告诉我我做错了什么吗?我尝试了将
我在 Mac OS X 上使用带有 Sequel Pro 的 MySQL。我想将一个表中的一个字段(即名为“GAME_DY”的列)复制到另一个名为“DAY_ID”的表的空字段中。两个表都是同一数据库的
问题: 是否有可能有一个字段被 JPA 保留但被序列化跳过? 可以实现相反的效果(JPA 跳过字段而序列化则不会),如果使用此功能,那么相反的操作肯定会很有用。 类似这样的事情: @Entity cl
假设我有一个名为“dp”的表 Year | Month | Payment| Payer_ID | Payment_Recipient | 2008/2009 | July
我将尝试通过我的 Raspberry Pi 接入点保证一些 QoS。 开始之前,我先动手:我阅读了有关 tcp、udp 和 ip header 的内容。在IP header description我看
如果你能弄清楚如何重命名这个问题,我愿意接受建议。 在 Dart 语言中,可以编写一个带有 final 字段的类。这些是只能设置的字段构造函数前 body 跑。这可以在声明中(通常用于类中的静态常量)
你怎么样? 我有两个带有两个字段的日期选择器 我希望当用户选择 (From) 时,第二个字段 (TO) 将是 next day 。比如 booking.com 例如:当用户选择From 01-01-2
我想我已经看到了这个问题的一些答案,这些答案可能与我需要的相差不远,但我对 mysql 的了解还不够确定,所以我会根据我的具体情况提出问题。 我有一个包含多个表的数据库,为此,如果“image”表上的
我在 mySQL 数据库中有 2 个表: customers ============ customer_id (1, 2 ) customer_name (john, mark) orders ==
我正在开发一个员工目标 Web 应用程序。 领导/经理在与团队成员讨论后为他们设定目标。这是一年/半年/季度,具体取决于组织遵循的评估周期。 现在的问题是添加基于时间段的字段或存档上一季度/年度数据的
我正在寻找允许内容编辑器从媒体库中选择多个文件的东西,这些文件将在渲染中列出。他们还需要能够上传文件和搜索。它必须在页面编辑器(版本 8 中称为体验编辑器)中工作。 到目前为止我所考虑的: 一堆文件字
现在,我有以下由 original.df %.% group_by(Category) %.% tally() %.% arrange(desc(n)) 创建的 data.frame。 DF 5),
我想知道是否有一些步骤/解决方案可以处理错误消息并将它们放入 Pentaho 工具中的某个字符串或字段中?例如,如果连接到数据库时发生某些错误,则将该消息从登录到字符串/字段。 最佳答案 我们在作业的
如何制作像短信应用程序一样的“收件人”字段?例如,右侧有一个“+”按钮,当添加某人时,名称将突出显示并可单击,如圆角矩形等。有没有内置的框架? 最佳答案 不,但请参阅 Three20 的 TTMess
是否可以获取记录的元素或字段的列表 通过类型信息类似于类的已发布属性的列表吗? 谢谢 ! 最佳答案 取决于您的delphi版本,如果您使用的是delphi 2010或更高版本,则可以使用“新rtti”
我正在构建一个 SQLite 数据库来保存我的房地产经纪人的列表。我已经能够使用外键来识别每个代理的列表,但我想在每个代理的记录中创建一个列表;从代理商和列表之间的一对一关系转变为一对多关系。 看这里
我是一名优秀的程序员,十分优秀!