如何让 Django AutoFields 以更高的数字开始

发布于 2024-07-06 01:57:33 字数 95 浏览 4 评论 0原文

对于我们的 Django 应用程序,我们希望获得一个从 1 以外的数字开始的 AutoField。似乎没有明显的方法可以做到这一点。 有任何想法吗?

For our Django App, we'd like to get an AutoField to start at a number other than 1. There doesn't seem to be an obvious way to do this. Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

记忆消瘦 2024-07-13 01:57:34

我找到了一个非常简单的解决方案! AutoField 使用先前的值来确定下一个分配的值。 因此,我发现,如果我插入一个带有所需起始自动字段值的虚拟值,则后续插入将从该值开始递增。

一个简单的例子,只需几个步骤:

1.)
models.py

class Product(models.Model):
    id = model.AutoField(primaryKey=True) # this is a dummy PK for now
    productID = models.IntegerField(default=0)
    productName = models.TextField()
    price = models.DecimalField(max_digits=6, decimal_places=2)
  • makemigrations
  • migrate

完成后,您将需要插入初始行,其中“productID”包含所需的 AutoField 起始值。 您可以编写一个方法或从 django shell 执行它。

从视图上看,插入可能如下所示:
views.py

from app.models import Product

dummy = {
   'productID': 100000,
   'productName': 'Item name',
   'price': 5.98,
}

Products.objects.create(**product)

插入后,您可以对模型进行以下更改:

models.py

class Product(models.Model):
    productID = models.AutoField(primary_key=True)
    productName = models.TextField()
    price = models.DecimalField(max_digits=6, decimal_places=2)

所有以下插入都会获得一个从 100000...100001...100002... 开始递增的“productID”...

I found a really easy solution to this! AutoField uses the previous value used to determine what the next value assigned will be. So I found that if I inserted a dummy value with the start AutoField value that I want, then following insertions will increment from that value.

A simple example in a few steps:

1.)
models.py

class Product(models.Model):
    id = model.AutoField(primaryKey=True) # this is a dummy PK for now
    productID = models.IntegerField(default=0)
    productName = models.TextField()
    price = models.DecimalField(max_digits=6, decimal_places=2)
  • makemigrations
  • migrate

Once that is done, you will need to insert the initial row where "productID" holds a value of your desired AutoField start value. You can write a method or do it from django shell.

From view the insertion could look like this:
views.py

from app.models import Product

dummy = {
   'productID': 100000,
   'productName': 'Item name',
   'price': 5.98,
}

Products.objects.create(**product)

Once inserted you can make the following change to your model:

models.py

class Product(models.Model):
    productID = models.AutoField(primary_key=True)
    productName = models.TextField()
    price = models.DecimalField(max_digits=6, decimal_places=2)

All following insertions will get a "productID" incrementing starting at 100000...100001...100002...

戈亓 2024-07-13 01:57:34

自动字段在一定程度上取决于所使用的数据库驱动程序。

您必须查看为特定数据库实际创建的对象才能了解发生了什么。

The auto fields depend, to an extent, on the database driver being used.

You'll have to look at the objects actually created for the specific database to see what's happening.

ゃ懵逼小萝莉 2024-07-13 01:57:34

对于那些对现代解决方案感兴趣的人,我发现在 post_migrate 信号中运行以下处理程序非常有用。

在您的 apps.py 文件中:

import logging

from django.apps import AppConfig
from django.db import connection, transaction
from django.db.models.signals import post_migrate

logger = logging.getLogger(__name__)


def auto_increment_start(sender, **kwargs):
    min_value = 10000
    with connection.cursor() as cursor:
        logger.info('Altering BigAutoField starting value...')
        cursor.execute(f"""
        SELECT setval(pg_get_serial_sequence('"apiV1_workflowtemplate"','id'), coalesce(max("id"), {min_value}), max("id") IS NOT null) FROM "apiV1_workflowtemplate";
        SELECT setval(pg_get_serial_sequence('"apiV1_workflowtemplatecollection"','id'), coalesce(max("id"), {min_value}), max("id") IS NOT null) FROM "apiV1_workflowtemplatecollection";
        SELECT setval(pg_get_serial_sequence('"apiV1_workflowtemplatecategory"','id'), coalesce(max("id"), {min_value}), max("id") IS NOT null) FROM "apiV1_workflowtemplatecategory";
      """)
        transaction.atomic()
        logger.info(f'BigAutoField starting value changed successfully to {min_value}')


class Apiv1Config(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'apiV1'

    def ready(self):
        post_migrate.connect(auto_increment_start, sender=self)

当然,正如一些人已经指出的那样,这样做的缺点是这是特定于数据库的。

For those who are interested in a modern solution, I found out to be quite useful running the following handler in a post_migrate signal.

Inside your apps.py file:

import logging

from django.apps import AppConfig
from django.db import connection, transaction
from django.db.models.signals import post_migrate

logger = logging.getLogger(__name__)


def auto_increment_start(sender, **kwargs):
    min_value = 10000
    with connection.cursor() as cursor:
        logger.info('Altering BigAutoField starting value...')
        cursor.execute(f"""
        SELECT setval(pg_get_serial_sequence('"apiV1_workflowtemplate"','id'), coalesce(max("id"), {min_value}), max("id") IS NOT null) FROM "apiV1_workflowtemplate";
        SELECT setval(pg_get_serial_sequence('"apiV1_workflowtemplatecollection"','id'), coalesce(max("id"), {min_value}), max("id") IS NOT null) FROM "apiV1_workflowtemplatecollection";
        SELECT setval(pg_get_serial_sequence('"apiV1_workflowtemplatecategory"','id'), coalesce(max("id"), {min_value}), max("id") IS NOT null) FROM "apiV1_workflowtemplatecategory";
      """)
        transaction.atomic()
        logger.info(f'BigAutoField starting value changed successfully to {min_value}')


class Apiv1Config(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'apiV1'

    def ready(self):
        post_migrate.connect(auto_increment_start, sender=self)

Of course the downside of this, as some already have pointed out, is that this is DB specific.

甜扑 2024-07-13 01:57:34

我需要做类似的事情。 我避免了复杂的东西,只是创建了两个字段:

id_no = models.AutoField(unique=True)
my_highvalue_id = models.IntegerField(null=True)

在views.py中,然后我简单地向id_no添加了一个固定数字:

my_highvalue_id = id_no + 1200

我不确定它是否有助于解决您的问题,但我认为您可能会发现这是一个简单的复飞。

I needed to do something similar. I avoided the complex stuff and simply created two fields:

id_no = models.AutoField(unique=True)
my_highvalue_id = models.IntegerField(null=True)

In views.py, I then simply added a fixed number to the id_no:

my_highvalue_id = id_no + 1200

I'm not sure if it helps resolve your issue, but I think you may find it an easy go-around.

悲凉≈ 2024-07-13 01:57:34

在模型中,您可以添加以下内容:

def save(self, *args, **kwargs):
       if not User.objects.count():
          self.id = 100
       else:
          self.id = User.objects.last().id + 1
       super(User, self).save(*args, **kwargs)

仅当数据库当前为空(没有对象)时才有效,因此第一个项目将被分配 id 100(如果没有先前的对象)存在),下一个插入将遵循最后一个 id + 1

In the model you can add this:

def save(self, *args, **kwargs):
       if not User.objects.count():
          self.id = 100
       else:
          self.id = User.objects.last().id + 1
       super(User, self).save(*args, **kwargs)

This works only if the DataBase is currently empty (no objects), so the first item will be assigned id 100 (if no previous objects exist) and next inserts will follow the last id + 1

感性 2024-07-13 01:57:33

正如其他人所说,这在数据库端比在 Django 端容易得多。

对于 Postgres,它是像这样ALTER SEQUENCE sequence_name RESTART WITH 12345; 查看您自己的数据库引擎的文档,了解如何执行此操作。

Like the others have said, this would be much easier to do on the database side than the Django side.

For Postgres, it'd be like so: ALTER SEQUENCE sequence_name RESTART WITH 12345; Look at your own DB engine's docs for how you'd do it there.

绿光 2024-07-13 01:57:33

对于MySQL,我创建了一个信号,在syncdb之后执行此操作:

from django.db.models.signals import post_syncdb
from project.app import models as app_models

def auto_increment_start(sender, **kwargs):
    from django.db import connection, transaction
    cursor = connection.cursor()
    cursor = cursor.execute("""
                                ALTER table app_table AUTO_INCREMENT=2000
                            """)
    transaction.commit_unless_managed()

post_syncdb.connect(auto_increment_start, sender=app_models)

在syncdb之后,执行alter table语句。 这将使您不必登录 mysql 并手动发出它。

编辑:我知道这是一个旧线程,但我认为它可能对某人有帮助。

For MySQL i created a signal that does this after syncdb:

from django.db.models.signals import post_syncdb
from project.app import models as app_models

def auto_increment_start(sender, **kwargs):
    from django.db import connection, transaction
    cursor = connection.cursor()
    cursor = cursor.execute("""
                                ALTER table app_table AUTO_INCREMENT=2000
                            """)
    transaction.commit_unless_managed()

post_syncdb.connect(auto_increment_start, sender=app_models)

After a syncdb the alter table statement is executed. This will exempt you from having to login into mysql and issuing it manually.

EDIT: I know this is an old thread, but I thought it might help someone.

故乡的云 2024-07-13 01:57:33

A quick peek at the source shows that there doesn't seem to be any option for this, probably because it doesn't always increment by one; it picks the next available key: "An IntegerField that automatically increments according to available IDs" — djangoproject.com

温柔戏命师 2024-07-13 01:57:33

这就是我所做的..

def update_auto_increment(value=5000, app_label="xxx_data"):
    """Update our increments"""
    from django.db import connection, transaction, router
    models = [m for m in get_models() if m._meta.app_label == app_label]
    cursor = connection.cursor()
    for model in models:
        _router = settings.DATABASES[router.db_for_write(model)]['NAME']
        alter_str = "ALTER table {}.{} AUTO_INCREMENT={}".format(
            _router, model._meta.db_table, value)
        cursor.execute(alter_str)
        transaction.commit_unless_managed()

Here is what I did..

def update_auto_increment(value=5000, app_label="xxx_data"):
    """Update our increments"""
    from django.db import connection, transaction, router
    models = [m for m in get_models() if m._meta.app_label == app_label]
    cursor = connection.cursor()
    for model in models:
        _router = settings.DATABASES[router.db_for_write(model)]['NAME']
        alter_str = "ALTER table {}.{} AUTO_INCREMENT={}".format(
            _router, model._meta.db_table, value)
        cursor.execute(alter_str)
        transaction.commit_unless_managed()
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文