标签归档:Django

如何在两个Django应用之间移动模型(Django 1.7)

问题:如何在两个Django应用之间移动模型(Django 1.7)

因此,大约一年前,我开始了一个项目,像所有新开发人员一样,我并没有真正专注于结构,但是现在我与Django一起走得更远,它开始似乎表明我的项目布局主要是我的模型在结构上很糟糕。

我的模型主要保存在单个应用程序中,实际上这些模型中的大多数应该放在自己的单个应用程序中,我确实尝试解决了此问题并将其向南移动,但是由于外键等原因,我发现它很棘手,而且确实很困难。

但是,由于Django 1.7并内置了对迁移的支持,现在有更好的方法吗?

So about a year ago I started a project and like all new developers I didn’t really focus too much on the structure, however now I am further along with Django it has started to appear that my project layout mainly my models are horrible in structure.

I have models mainly held in a single app and really most of these models should be in their own individual apps, I did try and resolve this and move them with south however I found it tricky and really difficult due to foreign keys ect.

However due to Django 1.7 and built in support for migrations is there a better way to do this now?


回答 0

我正在删除旧答案,因为这可能会导致数据丢失。如ozan所述,我们可以在每个应用中创建2个迁移。这篇文章下面的评论指的是我的旧答案。

第一次迁移以从第一个应用中删除模型。

$ python manage.py makemigrations old_app --empty

编辑迁移文件以包括这些操作。

class Migration(migrations.Migration):

    database_operations = [migrations.AlterModelTable('TheModel', 'newapp_themodel')]

    state_operations = [migrations.DeleteModel('TheModel')]

    operations = [
      migrations.SeparateDatabaseAndState(
        database_operations=database_operations,
        state_operations=state_operations)
    ]

第二次迁移取决于第一次迁移并在第二个应用程序中创建新表。将模型代码移至第二个应用程序后

$ python manage.py makemigrations new_app 

然后将迁移文件编辑为类似的内容。

class Migration(migrations.Migration):

    dependencies = [
        ('old_app', 'above_migration')
    ]

    state_operations = [
        migrations.CreateModel(
            name='TheModel',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
            ],
            options={
                'db_table': 'newapp_themodel',
            },
            bases=(models.Model,),
        )
    ]

    operations = [
        migrations.SeparateDatabaseAndState(state_operations=state_operations)
    ]

I am removing the old answer as may result in data loss. As ozan mentioned, we can create 2 migrations one in each app. The comments below this post refer to my old answer.

First migration to remove model from 1st app.

$ python manage.py makemigrations old_app --empty

Edit migration file to include these operations.

class Migration(migrations.Migration):

    database_operations = [migrations.AlterModelTable('TheModel', 'newapp_themodel')]

    state_operations = [migrations.DeleteModel('TheModel')]

    operations = [
      migrations.SeparateDatabaseAndState(
        database_operations=database_operations,
        state_operations=state_operations)
    ]

Second migration which depends on first migration and create the new table in 2nd app. After moving model code to 2nd app

$ python manage.py makemigrations new_app 

and edit migration file to something like this.

class Migration(migrations.Migration):

    dependencies = [
        ('old_app', 'above_migration')
    ]

    state_operations = [
        migrations.CreateModel(
            name='TheModel',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
            ],
            options={
                'db_table': 'newapp_themodel',
            },
            bases=(models.Model,),
        )
    ]

    operations = [
        migrations.SeparateDatabaseAndState(state_operations=state_operations)
    ]

回答 1

使用可以很容易地做到这一点migrations.SeparateDatabaseAndState。基本上,我们使用数据库操作来同时重命名表,同时使用两个状态操作从一个应用程序的历史记录中删除模型并在另一个应用程序的历史记录中创建模型。

从旧应用中删除

python manage.py makemigrations old_app --empty

在迁移中:

class Migration(migrations.Migration):

    dependencies = []

    database_operations = [
        migrations.AlterModelTable('TheModel', 'newapp_themodel')
    ]

    state_operations = [
        migrations.DeleteModel('TheModel')
    ]

    operations = [
        migrations.SeparateDatabaseAndState(
            database_operations=database_operations,
            state_operations=state_operations)
    ]

添加到新应用

首先,将模型复制到新应用的model.py中,然后:

python manage.py makemigrations new_app

这将生成一个迁移CreateModel操作,其中天真的操作是唯一的操作。将其包装在一个SeparateDatabaseAndState操作中,这样我们就不会尝试重新创建表。还包括先前的迁移作为依赖项:

class Migration(migrations.Migration):

    dependencies = [
        ('old_app', 'above_migration')
    ]

    state_operations = [
        migrations.CreateModel(
            name='TheModel',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
            ],
            options={
                'db_table': 'newapp_themodel',
            },
            bases=(models.Model,),
        )
    ]

    operations = [
        migrations.SeparateDatabaseAndState(state_operations=state_operations)
    ]

This can be done fairly easily using migrations.SeparateDatabaseAndState. Basically, we use a database operation to rename the table concurrently with two state operations to remove the model from one app’s history and create it in another’s.

Remove from old app

python manage.py makemigrations old_app --empty

In the migration:

class Migration(migrations.Migration):

    dependencies = []

    database_operations = [
        migrations.AlterModelTable('TheModel', 'newapp_themodel')
    ]

    state_operations = [
        migrations.DeleteModel('TheModel')
    ]

    operations = [
        migrations.SeparateDatabaseAndState(
            database_operations=database_operations,
            state_operations=state_operations)
    ]

Add to new app

First, copy the model to the new app’s model.py, then:

python manage.py makemigrations new_app

This will generate a migration with a naive CreateModel operation as the sole operation. Wrap that in a SeparateDatabaseAndState operation such that we don’t try to recreate the table. Also include the prior migration as a dependency:

class Migration(migrations.Migration):

    dependencies = [
        ('old_app', 'above_migration')
    ]

    state_operations = [
        migrations.CreateModel(
            name='TheModel',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
            ],
            options={
                'db_table': 'newapp_themodel',
            },
            bases=(models.Model,),
        )
    ]

    operations = [
        migrations.SeparateDatabaseAndState(state_operations=state_operations)
    ]

回答 2

我遇到了同样的问题。 奥赞的回答对我有很大帮助,但不幸的是还不够。确实,我有几个ForeignKey链接到我想移动的模型。经过一番头痛之后,我发现了解决方案,因此决定发布该解决方案以解决人们的时间问题。

您还需要2个步骤:

  1. 在执行任何操作之前,请将所有ForeignKey链接更改TheModelIntegerfield。然后跑python manage.py makemigrations
  2. 完成Ozan的步骤后,请重新转换外键:放回ForeignKey(TheModel)而不是IntegerField()。然后再次进行迁移(python manage.py makemigrations)。然后,您可以迁移,它应该可以工作(python manage.py migrate

希望能帮助到你。当然,在尝试生产之前,请先在本地进行测试,以避免出现意外情况:)

I encountered the same problem. Ozan’s answer helped me a lot but unfortunately was not enough. Indeed I had several ForeignKey linking to the model I wanted to move. After some headache I found the solution so decided to post it to solve people time.

You need 2 more steps:

  1. Before doing anything, change all your ForeignKey linking to TheModel into Integerfield. Then run python manage.py makemigrations
  2. After doing Ozan’s steps, re-convert your foreign keys: put back ForeignKey(TheModel)instead of IntegerField(). Then make the migrations again (python manage.py makemigrations). You can then migrate and it should work (python manage.py migrate)

Hope it helps. Of course test it in local before trying in production to avoid bad suprises :)


回答 3

我是如何做到的(在PostgreSQL == 1.8上进行了测试,使用postgres,可能也是1.7)

情况

app1.YourModel

但您希望它转到: app2.YourModel

  1. 将YourModel(代码)从app1复制到app2。
  2. 将此添加到app2.YourModel:

    Class Meta:
        db_table = 'app1_yourmodel'
  3. $ python manage.py makemigrations app2

  4. 使用migrations.CreateModel()语句在app2中进行了新的迁移(例如0009_auto_something.py),将该语句移至app2的初始迁移(例如0001_initial.py)(就像它一直在那儿一样)。现在删除创建的迁移= 0009_auto_something.py

  5. 就像您执行操作一样,就像app2.YourModel一直存在一样,现在从迁移中删除app1.YourModel的存在。含义:注释掉CreateModel语句,以及之后使用的所有调整或数据迁移。

  6. 当然,必须在您的项目中将对app1.YourModel的每个引用都更改为app2.YourModel。另外,不要忘记迁移中所有可能的app1.YourModel外键都必须更改为app2.YourModel。

  7. 现在,如果您执行$ python manage.py迁移,则什么都没有改变,同样,当您执行$ python manage.py makemigrations时,也不会检测到新的东西。

  8. 现在画龙点睛:从app2.YourModel中删除Class Meta并执行$ python manage.py makemigrations app2 && python manage.py migration app2(如果您研究此迁移,您将看到类似以下的内容:)

        migrations.AlterModelTable(
        name='yourmodel',
        table=None,
    ),

table = None,表示它将采用默认的表名,在这种情况下为app2_yourmodel。

  1. 完成,保存数据。

PS在迁移期间,它将看到content_type app1.yourmodel已被删除并且可以删除。您可以对此说是,但前提是您不使用它。如果您非常依赖它来使该内容类型的FK保持完整,则不要回答yes或no,而是手动进入该时间的db,并删除co​​ntentype app2.yourmodel,然后重命名contenttype app1。 yourmodel到app2.yourmodel,然后继续回答否。

How I did it (tested on Django==1.8, with postgres, so probably also 1.7)

Situation

app1.YourModel

but you want it to go to: app2.YourModel

  1. Copy YourModel (the code) from app1 to app2.
  2. add this to app2.YourModel:

    Class Meta:
        db_table = 'app1_yourmodel'
    
  3. $ python manage.py makemigrations app2

  4. A new migration (e.g. 0009_auto_something.py) is made in app2 with a migrations.CreateModel() statement, move this statement to the initial migration of app2 (e.g. 0001_initial.py) (it will be just like it always have been there). And now remove the created migration = 0009_auto_something.py

  5. Just as you act, like app2.YourModel always has been there, now remove the existence of app1.YourModel from your migrations. Meaning: comment out the CreateModel statements, and every adjustment or datamigration you used after that.

  6. And of course, every reference to app1.YourModel has to be changed to app2.YourModel through your project. Also, don’t forget that all possible foreign keys to app1.YourModel in migrations have to be changed to app2.YourModel

  7. Now if you do $ python manage.py migrate, nothing has changed, also when you do $ python manage.py makemigrations, nothing new has been detected.

  8. Now the finishing touch: remove the Class Meta from app2.YourModel and do $ python manage.py makemigrations app2 && python manage.py migrate app2 (if you look into this migration you’ll see something like this:)

        migrations.AlterModelTable(
        name='yourmodel',
        table=None,
    ),
    

table=None, means it will take the default table-name, which in this case will be app2_yourmodel.

  1. DONE, with data saved.

P.S during the migration it will see that that content_type app1.yourmodel has been removed and can be deleted. You can say yes to that but only if you don’t use it. In case you heavily depend on it to have FKs to that content-type be intact, don’t answer yes or no yet, but go into the db that time manually, and remove the contentype app2.yourmodel, and rename the contenttype app1.yourmodel to app2.yourmodel, and then continue by answering no.


回答 4

我会感到紧张的手工编码迁移(这是Ozan的回答所要求),因此以下内容结合了Ozan和Michael的策略以最大程度地减少所需的手工编码量:

  1. 在移动任何模型之前,请通过运行确保使用干净的基线makemigrations
  2. 将模型的代码从app1移至app2
  3. 按照@Michael的建议,我们使用db_table“新”模型上的Meta选项将新模型指向旧数据库表:

    class Meta:
        db_table = 'app1_yourmodel'
  4. 运行makemigrations。这将CreateModelapp2DeleteModel中生成app1。从技术上讲,这些迁移将引用完全相同的表,并且将删除(包括所有数据)并重新创建表。

  5. 实际上,我们不希望(或不需要)对表做任何事情。我们只需要Django相信所做的更改即可。根据@Ozan的回答,中的state_operations标志将SeparateDatabaseAndState执行此操作。因此,我们使用来将所有migrations条目包装在两个迁移文件SeparateDatabaseAndState(state_operations=[...])。例如,

    operations = [
        ...
        migrations.DeleteModel(
            name='YourModel',
        ),
        ...
    ]

    变成

    operations = [
        migrations.SeparateDatabaseAndState(state_operations=[
            ...
            migrations.DeleteModel(
                name='YourModel',
            ),
            ...
        ])
    ]
  6. 您还需要确保新的“虚拟” CreateModel迁移取决于实际创建或更改原始表的任何迁移。例如,如果您的新迁移是app2.migrations.0004_auto_<date>(针对Create)和app1.migrations.0007_auto_<date>(针对Delete),则最简单的操作是:

    • 打开app1.migrations.0007_auto_<date>并复制其app1依赖项(例如 ('app1', '0006...'),)。这是“立即优先”的迁移app1,应该包括对所有实际模型构建逻辑的依赖。
    • 打开 app2.migrations.0004_auto_<date>并将刚刚复制的依赖项添加到其dependencies列表中。

如果您ForeignKey与要移动的模型有关系,则上述方法可能无效。发生这种情况是因为:

  • 不会自动为ForeignKey更改创建依赖关系
  • 我们不想包装这些ForeignKey更改,state_operations因此我们需要确保它们与表操作是分开的。

注意:Django 2.2添加了一个警告(models.E028),它破坏了此方法。您也许可以解决该问题,managed=False但我尚未对其进行测试。

“最小”操作集因情况而异,但是以下过程应适用于大多数/所有ForeignKey迁移:

  1. app1复制模型app2,设置db_table,但不要更改任何FK引用。
  2. 运行makemigrations并包装所有app2迁移state_operations(请参见上文)
    • 如上所述,将依赖项添加app2 CreateTable到最新的app1迁移中
  3. 将所有FK参考指向新模型。如果您不使用字符串引用,请将旧模型移到models.py(不要删除它)的底部,这样它就不会与导入的类竞争。
  4. 运行,makemigrations但不要包装任何内容state_operations(实际上应该发生FK更改)。将所有ForeignKey迁移(即AlterField)中的依赖项添加到其中的CreateTable迁移中app2(下一步将需要此列表,因此请对其进行跟踪)。例如:

    • 找到包含迁移CreateModelapp2.migrations.0002_auto_<date>和复制迁移的名称。
    • 查找所有具有该模型的ForeignKey的迁移(例如,通过搜索app2.YourModel找到类似以下的迁移:

      class Migration(migrations.Migration):
      
          dependencies = [
              ('otherapp', '0001_initial'),
          ]
      
          operations = [
              migrations.AlterField(
                  model_name='relatedmodel',
                  name='fieldname',
                  field=models.ForeignKey(... to='app2.YourModel'),
              ),
          ]
    • CreateModel迁移作为依赖项添加:

      class Migration(migrations.Migration):
      
          dependencies = [
              ('otherapp', '0001_initial'),
              ('app2', '0002_auto_<date>'),
          ]  
  5. 从中删除模型 app1

  6. 运行迁移makemigrations并将其包装在app1state_operations
    • 为上一步的所有ForeignKey迁移(即AlterField)添加一个依赖项(可能包括app1和中的迁移app2)。
    • 当我构建这些迁移时,DeleteTable已经依赖于AlterField迁移了,因此我不需要手动执行它(即Alterbefore Delete)。

在这一点上,Django是个不错的选择。新模型指向旧表,并且Django的迁移使它确信所有内容都已适当地重新放置。最大的警告(来自@Michael的答案)是ContentType为新模型创建了一个新模型。如果您链接(例如通过ForeignKey)到内容类型,则需要创建一个迁移来更新ContentType表。

我想自己清理一下(元选项和表名),所以我使用了以下过程(来自@Michael):

  1. 删除db_table元条目
  2. makemigrations再次运行以生成数据库重命名
  3. 编辑此最后的迁移,并确保它取决于DeleteTable迁移。似乎没有必要,因为它应该Delete纯粹是逻辑上的,但是app1_yourmodel如果我不这样做,就会遇到错误(例如,不存在)。

I get nervous hand-coding migrations (as is required by Ozan’s answer) so the following combines Ozan’s and Michael’s strategies to minimize the amount of hand-coding required:

  1. Before moving any models, make sure you’re working with a clean baseline by running makemigrations.
  2. Move the code for the Model from app1 to app2
  3. As recommended by @Michael, we point the new model to the old database table using the db_table Meta option on the “new” model:

    class Meta:
        db_table = 'app1_yourmodel'
    
  4. Run makemigrations. This will generate CreateModel in app2 and DeleteModel in app1. Technically, these migrations refer to the exact same table and would remove (including all data) and re-create the table.

  5. In reality, we don’t want (or need) to do anything to the table. We just need Django to believe that the change has been made. Per @Ozan’s answer, the state_operations flag in SeparateDatabaseAndState does this. So we wrap all of the migrations entries IN BOTH MIGRATIONS FILES with SeparateDatabaseAndState(state_operations=[...]). For example,

    operations = [
        ...
        migrations.DeleteModel(
            name='YourModel',
        ),
        ...
    ]
    

    becomes

    operations = [
        migrations.SeparateDatabaseAndState(state_operations=[
            ...
            migrations.DeleteModel(
                name='YourModel',
            ),
            ...
        ])
    ]
    
  6. You also need to make sure the new “virtual” CreateModel migration depends on any migration that actually created or altered the original table. For example, if your new migrations are app2.migrations.0004_auto_<date> (for the Create) and app1.migrations.0007_auto_<date> (for the Delete), the simplest thing to do is:

    • Open app1.migrations.0007_auto_<date> and copy its app1 dependency (e.g. ('app1', '0006...'),). This is the “immediately prior” migration in app1 and should include dependencies on all of the actual model building logic.
    • Open app2.migrations.0004_auto_<date> and add the dependency you just copied to its dependencies list.

If you have ForeignKey relationship(s) to the model you’re moving, the above may not work. This happens because:

  • Dependencies are not automatically created for the ForeignKey changes
  • We do not want to wrap the ForeignKey changes in state_operations so we need to ensure they are separate from the table operations.

NOTE: Django 2.2 added a warning (models.E028) that breaks this method. You may be able to work around it with managed=False but I have not tested it.

The “minimum” set of operations differ depending on the situation, but the following procedure should work for most/all ForeignKey migrations:

  1. COPY the model from app1 to app2, set db_table, but DON’T change any FK references.
  2. Run makemigrations and wrap all app2 migration in state_operations (see above)
    • As above, add a dependency in the app2 CreateTable to the latest app1 migration
  3. Point all of the FK references to the new model. If you aren’t using string references, move the old model to the bottom of models.py (DON’T remove it) so it doesn’t compete with the imported class.
  4. Run makemigrations but DON’T wrap anything in state_operations (the FK changes should actually happen). Add a dependency in all the ForeignKey migrations (i.e. AlterField) to the CreateTable migration in app2 (you’ll need this list for the next step so keep track of them). For example:

    • Find the migration that includes the CreateModel e.g. app2.migrations.0002_auto_<date> and copy the name of that migration.
    • Find all migrations that have a ForeignKey to that model (e.g. by searching app2.YourModel to find migrations like:

      class Migration(migrations.Migration):
      
          dependencies = [
              ('otherapp', '0001_initial'),
          ]
      
          operations = [
              migrations.AlterField(
                  model_name='relatedmodel',
                  name='fieldname',
                  field=models.ForeignKey(... to='app2.YourModel'),
              ),
          ]
      
    • Add the CreateModel migration as as a dependency:

      class Migration(migrations.Migration):
      
          dependencies = [
              ('otherapp', '0001_initial'),
              ('app2', '0002_auto_<date>'),
          ]  
      
  5. Remove the models from app1

  6. Run makemigrations and wrap the app1 migration in state_operations.
    • Add a dependency to all of the ForeignKey migrations (i.e. AlterField) from the previous step (may include migrations in app1 and app2).
    • When I built these migrations, the DeleteTable already depended on the AlterField migrations so I didn’t need to manually enforce it (i.e. Alter before Delete).

At this point, Django is good to go. The new model points to the old table and Django’s migrations have convinced it that everything has been relocated appropriately. The big caveat (from @Michael’s answer) is that a new ContentType is created for the new model. If you link (e.g. by ForeignKey) to content types, you’ll need to create a migration to update the ContentType table.

I wanted to cleanup after myself (Meta options and table names) so I used the following procedure (from @Michael):

  1. Remove the db_table Meta entry
  2. Run makemigrations again to generate the database rename
  3. Edit this last migration and make sure it depends on the DeleteTable migration. It doesn’t seem like it should be necessary as the Delete should be purely logical, but I’ve run into errors (e.g. app1_yourmodel doesn’t exist) if I don’t.

回答 5

如果数据不是很大或太复杂,但仍然很重要,则另一种骇人听闻的选择是:

  • 使用manage.py dumpdata获取数据固定装置
  • 继续正确建模更改和迁移,而不涉及更改
  • 全局将设备从旧型号和应用名称替换为新的
  • 使用manage.py loaddata加载数据

Another hacky alternative if the data is not big or too complicated, but still important to maintain, is to:

  • Get data fixtures using manage.py dumpdata
  • Proceed to model changes and migrations properly, without relating the changes
  • Global replace the fixtures from the old model and app names to the new
  • Load data using manage.py loaddata

回答 6

从我在https://stackoverflow.com/a/47392970/8971048的回答中复制

万一您需要移动模型而又无权访问该应用程序(或者您不想访问该应用程序),则可以创建一个新的Operation并考虑仅在迁移的模型不具有该模型的情况下创建一个新模型存在。

在此示例中,我将“ MyModel”从old_app传递到myapp。

class MigrateOrCreateTable(migrations.CreateModel):
    def __init__(self, source_table, dst_table, *args, **kwargs):
        super(MigrateOrCreateTable, self).__init__(*args, **kwargs)
        self.source_table = source_table
        self.dst_table = dst_table

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        table_exists = self.source_table in schema_editor.connection.introspection.table_names()
        if table_exists:
            with schema_editor.connection.cursor() as cursor:
                cursor.execute("RENAME TABLE {} TO {};".format(self.source_table, self.dst_table))
        else:
            return super(MigrateOrCreateTable, self).database_forwards(app_label, schema_editor, from_state, to_state)


class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0002_some_migration'),
    ]

    operations = [
        MigrateOrCreateTable(
            source_table='old_app_mymodel',
            dst_table='myapp_mymodel',
            name='MyModel',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=18))
            ],
        ),
    ]

Copied from my answer at https://stackoverflow.com/a/47392970/8971048

In case you need to move the model and you don’t have access to the app anymore (or you don’t want the access), you can create a new Operation and consider to create a new model only if the migrated model does not exist.

In this example I am passing ‘MyModel’ from old_app to myapp.

class MigrateOrCreateTable(migrations.CreateModel):
    def __init__(self, source_table, dst_table, *args, **kwargs):
        super(MigrateOrCreateTable, self).__init__(*args, **kwargs)
        self.source_table = source_table
        self.dst_table = dst_table

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        table_exists = self.source_table in schema_editor.connection.introspection.table_names()
        if table_exists:
            with schema_editor.connection.cursor() as cursor:
                cursor.execute("RENAME TABLE {} TO {};".format(self.source_table, self.dst_table))
        else:
            return super(MigrateOrCreateTable, self).database_forwards(app_label, schema_editor, from_state, to_state)


class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0002_some_migration'),
    ]

    operations = [
        MigrateOrCreateTable(
            source_table='old_app_mymodel',
            dst_table='myapp_mymodel',
            name='MyModel',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=18))
            ],
        ),
    ]

回答 7

这是经过粗略测试的,所以不要忘记备份数据库!!!

例如,有两个应用程序:src_appdst_app,我们希望将模型MoveMesrc_app移至dst_app

为两个应用程序创建空迁移:

python manage.py makemigrations --empty src_app
python manage.py makemigrations --empty dst_app

让我们假设,新的迁移是XXX1_src_app_newXXX1_dst_app_new,之前的主要迁移是XXX0_src_app_oldXXX0_dst_app_old

添加一个操作,该操作重命名MoveMe模型的表,并将其在ProjectState中的app_label重命名为XXX1_dst_app_new。不要忘记增加对XXX0_src_app_old迁移的依赖。产生的XXX1_dst_app_new迁移是:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

# this operations is almost the same as RenameModel
# https://github.com/django/django/blob/1.7/django/db/migrations/operations/models.py#L104
class MoveModelFromOtherApp(migrations.operations.base.Operation):

    def __init__(self, name, old_app_label):
        self.name = name
        self.old_app_label = old_app_label

    def state_forwards(self, app_label, state):

        # Get all of the related objects we need to repoint
        apps = state.render(skip_cache=True)
        model = apps.get_model(self.old_app_label, self.name)
        related_objects = model._meta.get_all_related_objects()
        related_m2m_objects = model._meta.get_all_related_many_to_many_objects()
        # Rename the model
        state.models[app_label, self.name.lower()] = state.models.pop(
            (self.old_app_label, self.name.lower())
        )
        state.models[app_label, self.name.lower()].app_label = app_label
        for model_state in state.models.values():
            try:
                i = model_state.bases.index("%s.%s" % (self.old_app_label, self.name.lower()))
                model_state.bases = model_state.bases[:i] + ("%s.%s" % (app_label, self.name.lower()),) + model_state.bases[i+1:]
            except ValueError:
                pass
        # Repoint the FKs and M2Ms pointing to us
        for related_object in (related_objects + related_m2m_objects):
            # Use the new related key for self referential related objects.
            if related_object.model == model:
                related_key = (app_label, self.name.lower())
            else:
                related_key = (
                    related_object.model._meta.app_label,
                    related_object.model._meta.object_name.lower(),
                )
            new_fields = []
            for name, field in state.models[related_key].fields:
                if name == related_object.field.name:
                    field = field.clone()
                    field.rel.to = "%s.%s" % (app_label, self.name)
                new_fields.append((name, field))
            state.models[related_key].fields = new_fields

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        old_apps = from_state.render()
        new_apps = to_state.render()
        old_model = old_apps.get_model(self.old_app_label, self.name)
        new_model = new_apps.get_model(app_label, self.name)
        if self.allowed_to_migrate(schema_editor.connection.alias, new_model):
            # Move the main table
            schema_editor.alter_db_table(
                new_model,
                old_model._meta.db_table,
                new_model._meta.db_table,
            )
            # Alter the fields pointing to us
            related_objects = old_model._meta.get_all_related_objects()
            related_m2m_objects = old_model._meta.get_all_related_many_to_many_objects()
            for related_object in (related_objects + related_m2m_objects):
                if related_object.model == old_model:
                    model = new_model
                    related_key = (app_label, self.name.lower())
                else:
                    model = related_object.model
                    related_key = (
                        related_object.model._meta.app_label,
                        related_object.model._meta.object_name.lower(),
                    )
                to_field = new_apps.get_model(
                    *related_key
                )._meta.get_field_by_name(related_object.field.name)[0]
                schema_editor.alter_field(
                    model,
                    related_object.field,
                    to_field,
                )

    def database_backwards(self, app_label, schema_editor, from_state, to_state):
        self.old_app_label, app_label = app_label, self.old_app_label
        self.database_forwards(app_label, schema_editor, from_state, to_state)
        app_label, self.old_app_label = self.old_app_label, app_label

    def describe(self):
        return "Move %s from %s" % (self.name, self.old_app_label)


class Migration(migrations.Migration):

    dependencies = [
       ('dst_app', 'XXX0_dst_app_old'),
       ('src_app', 'XXX0_src_app_old'),
    ]

    operations = [
        MoveModelFromOtherApp('MoveMe', 'src_app'),
    ]

将依赖项添加XXX1_dst_app_newXXX1_src_app_newXXX1_src_app_new是No-op迁移,可确保src_app在之后执行将来的迁移XXX1_dst_app_new

移动MoveMesrc_app/models.pydst_app/models.py。然后运行:

python manage.py migrate

就这样!

This is tested roughly, so do not forget to backup your DB!!!

For example, there are two apps: src_app and dst_app, we want to move model MoveMe from src_app to dst_app.

Create empty migrations for both apps:

python manage.py makemigrations --empty src_app
python manage.py makemigrations --empty dst_app

Let’s assume, that new migrations are XXX1_src_app_new and XXX1_dst_app_new, previuos top migrations are XXX0_src_app_old and XXX0_dst_app_old.

Add an operation that renames table for MoveMe model and renames its app_label in ProjectState to XXX1_dst_app_new. Do not forget to add dependency on XXX0_src_app_old migration. The resulting XXX1_dst_app_new migration is:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

# this operations is almost the same as RenameModel
# https://github.com/django/django/blob/1.7/django/db/migrations/operations/models.py#L104
class MoveModelFromOtherApp(migrations.operations.base.Operation):

    def __init__(self, name, old_app_label):
        self.name = name
        self.old_app_label = old_app_label

    def state_forwards(self, app_label, state):

        # Get all of the related objects we need to repoint
        apps = state.render(skip_cache=True)
        model = apps.get_model(self.old_app_label, self.name)
        related_objects = model._meta.get_all_related_objects()
        related_m2m_objects = model._meta.get_all_related_many_to_many_objects()
        # Rename the model
        state.models[app_label, self.name.lower()] = state.models.pop(
            (self.old_app_label, self.name.lower())
        )
        state.models[app_label, self.name.lower()].app_label = app_label
        for model_state in state.models.values():
            try:
                i = model_state.bases.index("%s.%s" % (self.old_app_label, self.name.lower()))
                model_state.bases = model_state.bases[:i] + ("%s.%s" % (app_label, self.name.lower()),) + model_state.bases[i+1:]
            except ValueError:
                pass
        # Repoint the FKs and M2Ms pointing to us
        for related_object in (related_objects + related_m2m_objects):
            # Use the new related key for self referential related objects.
            if related_object.model == model:
                related_key = (app_label, self.name.lower())
            else:
                related_key = (
                    related_object.model._meta.app_label,
                    related_object.model._meta.object_name.lower(),
                )
            new_fields = []
            for name, field in state.models[related_key].fields:
                if name == related_object.field.name:
                    field = field.clone()
                    field.rel.to = "%s.%s" % (app_label, self.name)
                new_fields.append((name, field))
            state.models[related_key].fields = new_fields

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        old_apps = from_state.render()
        new_apps = to_state.render()
        old_model = old_apps.get_model(self.old_app_label, self.name)
        new_model = new_apps.get_model(app_label, self.name)
        if self.allowed_to_migrate(schema_editor.connection.alias, new_model):
            # Move the main table
            schema_editor.alter_db_table(
                new_model,
                old_model._meta.db_table,
                new_model._meta.db_table,
            )
            # Alter the fields pointing to us
            related_objects = old_model._meta.get_all_related_objects()
            related_m2m_objects = old_model._meta.get_all_related_many_to_many_objects()
            for related_object in (related_objects + related_m2m_objects):
                if related_object.model == old_model:
                    model = new_model
                    related_key = (app_label, self.name.lower())
                else:
                    model = related_object.model
                    related_key = (
                        related_object.model._meta.app_label,
                        related_object.model._meta.object_name.lower(),
                    )
                to_field = new_apps.get_model(
                    *related_key
                )._meta.get_field_by_name(related_object.field.name)[0]
                schema_editor.alter_field(
                    model,
                    related_object.field,
                    to_field,
                )

    def database_backwards(self, app_label, schema_editor, from_state, to_state):
        self.old_app_label, app_label = app_label, self.old_app_label
        self.database_forwards(app_label, schema_editor, from_state, to_state)
        app_label, self.old_app_label = self.old_app_label, app_label

    def describe(self):
        return "Move %s from %s" % (self.name, self.old_app_label)


class Migration(migrations.Migration):

    dependencies = [
       ('dst_app', 'XXX0_dst_app_old'),
       ('src_app', 'XXX0_src_app_old'),
    ]

    operations = [
        MoveModelFromOtherApp('MoveMe', 'src_app'),
    ]

Add dependency on XXX1_dst_app_new to XXX1_src_app_new. XXX1_src_app_new is no-op migration that is needed to make sure that future src_app migrations will be executed after XXX1_dst_app_new.

Move MoveMe from src_app/models.py to dst_app/models.py. Then run:

python manage.py migrate

That’s all!


回答 8

您可以尝试以下(未试用):

  1. 将模型从src_app移至dest_app
  2. 迁移dest_app; 确保模式迁移依赖于最新的src_app迁移(https://docs.djangoproject.com/en/dev/topics/migrations/#migration-files
  3. 将数据迁移添加到dest_app,从中复制所有数据src_app
  4. 迁移src_app; 确保模式迁移依赖于-的最新(数据)迁移,dest_app即:步骤3的迁移

请注意,您将复制整个表格,而不是移动整个表格,但是那样,两个应用程序都不必触摸属于另一个应用程序的表,我认为这更重要。

You can try the following (untested):

  1. move the model from src_app to dest_app
  2. migrate dest_app; make sure the schema migration depends on the latest src_app migration (https://docs.djangoproject.com/en/dev/topics/migrations/#migration-files)
  3. add a data migration to dest_app, that copies all data from src_app
  4. migrate src_app; make sure the schema migration depends on the latest (data) migration of dest_app — that is: the migration of step 3

Note that you will be copying the whole table, instead of moving it, but that way both apps don’t have to touch a table that belongs to the other app, which I think is more important.


回答 9

假设您要将模型TheModel从app_a移至app_b。

另一种解决方案是手动更改现有迁移。这样做的想法是,每次在app_a的迁移过程中看到更改TheModel的操作时,都会将该操作复制到app_b的初始迁移的末尾。并且每次在app_a的迁移中看到引用’app_a.TheModel’时,都将其更改为’app_b.TheModel’。

我只是对一个现有项目执行此操作,在该项目中我想将某个模型提取到可重用的应用程序中。程序进行得很顺利。我想如果有从app_b到app_a的引用,事情会更加困难。另外,我为模型手动定义了Meta.db_table,这可能有所帮助。

值得注意的是,您最终会更改迁移历史记录。即使您的数据库已应用原始迁移,也没关系。如果原始迁移和重写迁移最终都具有相同的数据库模式,则这种重写应该可以。

Lets say you are moving model TheModel from app_a to app_b.

An alternate solution is to alter the existing migrations by hand. The idea is that each time you see an operation altering TheModel in app_a’s migrations, you copy that operation to the end of app_b’s initial migration. And each time you see a reference ‘app_a.TheModel’ in app_a’s migrations, you change it to ‘app_b.TheModel’.

I just did this for an existing project, where I wanted to extract a certain model to an reusable app. The procedure went smoothly. I guess things would be much harder if there were references from app_b to app_a. Also, I had a manually defined Meta.db_table for my model which might have helped.

Notably you will end up with altered migration history. This doesn’t matter, even if you have a database with the original migrations applied. If both the original and the rewritten migrations end up with the same database schema, then such rewrite should be OK.


回答 10

  1. 将旧模型的名称更改为“ model_name_old”
  2. 移民
  3. 制作名为“ model_name_new”的新模型,并在相关模型上具有相同的关系(例如,用户模型现在具有user.blog_old和user.blog_new)
  4. 移民
  5. 编写自定义迁移,将所有数据迁移到新模型表
  6. 通过在运行迁移之前和之后将备份与新的数据库副本进行比较来测试这些迁移的难处
  7. 当一切都令人满意时,删除旧模型
  8. 移民
  9. 将新模型更改为正确的名称’model_name_new’->’model_name’
  10. 在登台服务器上测试整个迁移过程
  11. 将您的生产站点关闭几分钟,以便在不干扰用户的情况下运行所有​​迁移

对每个需要移动的模型分别执行此操作。我不建议通过更改为整数然后再返回外键来执行其他答案所说的事情,在迁移之后,新的外键可能会有所不同,并且行的ID可能会有所不同,并且我不想冒任何风险切换回外键时ID不匹配的问题。

  1. change the names of old models to ‘model_name_old’
  2. makemigrations
  3. make new models named ‘model_name_new’ with identical relationships on the related models (eg. user model now has user.blog_old and user.blog_new)
  4. makemigrations
  5. write a custom migration that migrates all the data to the new model tables
  6. test the hell out of these migrations by comparing backups with new db copies before and after running the migrations
  7. when all is satisfactory, delete the old models
  8. makemigrations
  9. change the new models to the correct name ‘model_name_new’ -> ‘model_name’
  10. test the whole slew of migrations on a staging server
  11. take your production site down for a few minutes in order to run all migrations without users interfering

Do this individually for each model that needs to be moved. I wouldn’t suggest doing what the other answer says by changing to integers and back to foreign keys There is a chance that new foreign keys will be different and rows may have different IDs after the migrations and I didn’t want to run any risk of mismatching ids when switching back to foreign keys.


django-debug-toolbar未显示

问题:django-debug-toolbar未显示

我看着其他问题,无法解决…

我做了以下安装django-debug-toolbar的操作:

  1. pip安装django-debug-toolbar
  2. 添加到中间件类:
MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    # Uncomment the next line for simple clickjacking protection:
    # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'debug_toolbar.middleware.DebugToolbarMiddleware',
)

3添加了INTERNAL_IPS:

INTERNAL_IPS =(’174.121.34.187’,)

4将debug_toolbar添加到已安装的应用程序

我没有收到任何错误或任何内容,并且该工具栏也没有显示在任何页面上,甚至没有显示在管理页面上。

我什至将debug_toolbar模板的目录添加到了我的 TEMPLATE_DIRS

I looked at other questions and can’t figure it out…

I did the following to install django-debug-toolbar:

  1. pip install django-debug-toolbar
  2. added to middleware classes:
MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    # Uncomment the next line for simple clickjacking protection:
    # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'debug_toolbar.middleware.DebugToolbarMiddleware',
)

3 Added INTERNAL_IPS:

INTERNAL_IPS = (‘174.121.34.187’,)

4 Added debug_toolbar to installed apps

I am not getting any errors or anything, and the toolbar doesn’t show up on any page, not even admin.

I even added the directory of the debug_toolbar templates to my TEMPLATE_DIRS


回答 0

愚蠢的问题,但您没有提及,所以… DEBUG设置为什么?它不会加载,除非它是True

如果仍然无法使用,请尝试同时添加“ 127.0.0.1” INTERNAL_IPS

更新

这是最后的努力,您不应该这样这样做,但它清楚地表明,如果有一些只是配置问题,或者是否有一些更大的问题。

将以下内容添加到settings.py:

def show_toolbar(request):
    return True
SHOW_TOOLBAR_CALLBACK = show_toolbar

这将有效地删除调试工具栏上的所有检查,以确定是否应该加载自身。它总是会加载。仅将其保留用于测试目的,如果您忘记了并随它一起启动,所有访客也将看到您的调试工具栏。

对于显式配置,另请参阅此处的官方安装文档

编辑(6/17/2015):

显然,核选项的语法已更改。现在在它自己的字典中:

def show_toolbar(request):
    return True
DEBUG_TOOLBAR_CONFIG = {
    "SHOW_TOOLBAR_CALLBACK" : show_toolbar,
}

他们的测试使用此词典。

Stupid question, but you didn’t mention it, so… What is DEBUG set to? It won’t load unless it’s True.

If it’s still not working, try adding ‘127.0.0.1’ to INTERNAL_IPS as well.

UPDATE

This is a last-ditch-effort move, you shouldn’t have to do this, but it will clearly show if there’s merely some configuration issue or whether there’s some larger issue.

Add the following to settings.py:

def show_toolbar(request):
    return True
SHOW_TOOLBAR_CALLBACK = show_toolbar

That will effectively remove all checks by debug toolbar to determine if it should or should not load itself; it will always just load. Only leave that in for testing purposes, if you forget and launch with it, all your visitors will get to see your debug toolbar too.

For explicit configuration, also see the official install docs here.

EDIT(6/17/2015):

Apparently the syntax for the nuclear option has changed. It’s now in its own dictionary:

def show_toolbar(request):
    return True
DEBUG_TOOLBAR_CONFIG = {
    "SHOW_TOOLBAR_CALLBACK" : show_toolbar,
}

Their tests use this dictionary.


回答 1

调试工具栏希望在INTERNAL_IPS设置中设置request.META [‘REMOTE_ADDR’]中的IP地址。在您的其中一种视图中放入打印语句,例如:

print("IP Address for debug-toolbar: " + request.META['REMOTE_ADDR'])

然后加载该页面。确保IP位于settings.py中的INTERNAL_IPS设置中。

通常,我认为您可以通过查看计算机的ip地址来轻松确定该地址,但是就我而言,我是在具有端口转发功能的Virtual Box中运行服务器……谁知道发生了什么。尽管在VB或我自己的OS上的ifconfig中没有看到它,但是REMOTE_ADDR键中显示的IP是激活工具栏的窍门。

Debug toolbar wants the ip address in request.META[‘REMOTE_ADDR’] to be set in the INTERNAL_IPS setting. Throw in a print statement in one of your views like such:

print("IP Address for debug-toolbar: " + request.META['REMOTE_ADDR'])

And then load that page. Make sure that IP is in your INTERNAL_IPS setting in settings.py.

Normally I’d think you would be able to determine the address easily by looking at your computer’s ip address, but in my case I’m running the server in a Virtual Box with port forwarding…and who knows what happened. Despite not seeing it anywhere in ifconfig on the VB or my own OS, the IP that showed up in the REMOTE_ADDR key was what did the trick of activating the toolbar.


回答 2

如果其他方法都没问题,则可能是您的模板缺少明确的结束<body>标记-

注意:仅当响应的模仿类型是text / html或application / xhtml + xml且包含结束标记时,调试工具栏才会显示。


回答 3

当前的稳定版本0.11.0要求满足以下条件才能显示工具栏:

设置文件:

  1. DEBUG = True
  2. INTERNAL_IPS包括您的浏览器IP地址,而不是服务器地址。如果在本地浏览,则应为INTERNAL_IPS = ('127.0.0.1',)。如果要远程浏览,只需指定您的公共地址
  3. 要安装的debug_toolbar应用程序,即 INSTALLED_APPS = (..., 'debug_toolbar',)
  4. 要添加的调试工具栏中间件类,即MIDDLEWARE_CLASSES = ('debug_toolbar.middleware.DebugToolbarMiddleware', ...)。它应尽早放在列表中。

模板文件:

  1. 必须是类型 text/html
  2. 必须有结束</html>标签

静态文件:

如果您要提供静态内容,请确保通过执行以下步骤来收集CSS,JS和html:

./manage.py collectstatic 


注意即将发布的django-debug-toolbar版本

较新的开发版本为设置点2、3和4添加了默认值,这使工作变得更简单了,但是,与任何开发版本一样,它都有错误。我发现git的最新版本导致ImproperlyConfigured通过nginx / uwsgi运行时错误。

无论哪种方式,如果要从github安装最新版本,请运行:

pip install -e git+https://github.com/django-debug-toolbar/django-debug-toolbar.git#egg=django-debug-toolbar 

您还可以通过执行以下操作来克隆特定的提交:

pip install -e git+https://github.com/django-debug-toolbar/django-debug-toolbar.git@ba5af8f6fe7836eef0a0c85dd1e6d7418bc87f75#egg=django_debug_toolbar

The current stable version 0.11.0 requires the following things to be true for the toolbar to be shown:

Settings file:

  1. DEBUG = True
  2. INTERNAL_IPS to include your browser IP address, as opposed to the server address. If browsing locally this should be INTERNAL_IPS = ('127.0.0.1',). If browsing remotely just specify your public address.
  3. The debug_toolbar app to be installed i.e INSTALLED_APPS = (..., 'debug_toolbar',)
  4. The debug toolbar middleware class to be added i.e. MIDDLEWARE_CLASSES = ('debug_toolbar.middleware.DebugToolbarMiddleware', ...). It should be placed as early as possible in the list.

Template files:

  1. Must be of type text/html
  2. Must have a closing </html> tag

Static files:

If you are serving static content make sure you collect the css, js and html by doing:

./manage.py collectstatic 


Note on upcoming versions of django-debug-toolbar

Newer, development versions have added defaults for settings points 2, 3 and 4 which makes life a bit simpler, however, as with any development version it has bugs. I found that the latest version from git resulted in an ImproperlyConfigured error when running through nginx/uwsgi.

Either way, if you want to install the latest version from github run:

pip install -e git+https://github.com/django-debug-toolbar/django-debug-toolbar.git#egg=django-debug-toolbar 

You can also clone a specific commit by doing:

pip install -e git+https://github.com/django-debug-toolbar/django-debug-toolbar.git@ba5af8f6fe7836eef0a0c85dd1e6d7418bc87f75#egg=django_debug_toolbar

回答 4

我尝试了所有操作,从设置DEBUG = True到设置INTERNAL_IPS到客户端IP地址,甚至手动配置Django Debug Toolbar(请注意,最新版本会自动进行所有配置,例如添加中间件和URL)。在远程开发服务器上没有任何工作(尽管它在本地工作)。唯一起作用的是配置工具栏,如下所示:

DEBUG_TOOLBAR_CONFIG = {
    "SHOW_TOOLBAR_CALLBACK" : lambda request: True,
}

这将替换默认方法,该默认方法确定是否应显示工具栏,并始终返回true。

I tried everything, from setting DEBUG = True, to settings INTERNAL_IPS to my client’s IP address, and even configuring Django Debug Toolbar manually (note that recent versions make all configurations automatically, such as adding the middleware and URLs). Nothing worked in a remote development server (though it did work locally). The ONLY thing that worked was configuring the toolbar as follows:

DEBUG_TOOLBAR_CONFIG = {
    "SHOW_TOOLBAR_CALLBACK" : lambda request: True,
}

This replaces the default method that decides if the toolbar should be shown, and always returns true.


回答 5

码头工人

如果您要在具有docker的Docker容器中使用Django服务器进行开发,则启用工具栏的说明无效。原因与以下事实有关:您需要添加的实际地址将INTERNAL_IPS是动态的,例如172.24.0.1。而不是尝试动态设置的值INTERNAL_IPS,直接的解决方案是替换您的中启用工具栏的功能,settings.py例如:

DEBUG_TOOLBAR_CONFIG = {
    'SHOW_TOOLBAR_CALLBACK': lambda _request: DEBUG
}


这也应该适用于其他动态路由情况,例如无业游民。


这里有一些好奇的细节。django_debug_tool中的确定是否显示工具栏的代码检查如下值REMOTE_ADDR

if request.META.get('REMOTE_ADDR', None) not in INTERNAL_IPS:
       return False

因此,如果REMOTE_ADDR由于动态docker路由而实际上不知道的值,则该工具栏将无法工作。您可以使用docker network命令查看动态IP值,例如docker network inspect my_docker_network_name

Docker

If you’re developing with a Django server in a Docker container with docker, the instructions for enabling the toolbar don’t work. The reason is related to the fact that the actual address that you would need to add to INTERNAL_IPS is going to be something dynamic, like 172.24.0.1. Rather than trying to dynamically set the value of INTERNAL_IPS, the straightforward solution is to replace the function that enables the toolbar, in your settings.py, for example:

DEBUG_TOOLBAR_CONFIG = {
    'SHOW_TOOLBAR_CALLBACK': lambda _request: DEBUG
}


This should also work for other dynamic routing situations, like vagrant.


Here are some more details for the curious. The code in django_debug_tool that determines whether to show the toolbar examines the value of REMOTE_ADDR like this:

if request.META.get('REMOTE_ADDR', None) not in INTERNAL_IPS:
       return False

so if you don’t actually know the value of REMOTE_ADDR due to your dynamic docker routing, the toolbar will not work. You can use the docker network command to see the dynamic IP values, for example docker network inspect my_docker_network_name


回答 6

我的工具栏工作得非常完美。使用此配置:

  1. DEBUG = True
  2. INTERNAL_IPS = ('127.0.0.1', '192.168.0.1',)
  3. DEBUG_TOOLBAR_CONFIG = {'INTERCEPT_REDIRECTS': False,}
  4. 中间件是MIDDLEWARE_CLASSES
MIDDLEWARE_CLASSES = (
    'debug_toolbar.middleware.DebugToolbarMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
)

希望对您有所帮助

I have the toolbar working just perfect. With this configurations:

  1. DEBUG = True
  2. INTERNAL_IPS = ('127.0.0.1', '192.168.0.1',)
  3. DEBUG_TOOLBAR_CONFIG = {'INTERCEPT_REDIRECTS': False,}
  4. The middleware is the first element in MIDDLEWARE_CLASSES:
MIDDLEWARE_CLASSES = (
    'debug_toolbar.middleware.DebugToolbarMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
)

I hope it helps


回答 7

10.0.2.2在Windows上添加到您的INTERNAL_IPS,内部与流浪汉一起使用

INTERNAL_IPS =(’10 .0.2.2’,)

这应该工作。

Add 10.0.2.2 to your INTERNAL_IPS on Windows, it is used with vagrant internally

INTERNAL_IPS = ( ‘10.0.2.2’, )

This should work.


回答 8

我遇到了同样的问题,经过谷歌搜索后终于解决了。

在INTERNAL_IPS中,您需要具有客户端的 IP地址。

I had the same problem and finally resolved it after some googling.

In INTERNAL_IPS, you need to have the client’s IP address.


回答 9

导致工具栏保持隐藏状态的另一件事是,它找不到所需的静态文件。debug_toolbar模板使用{{STATIC_URL}}模板标记,因此请确保您的静态文件中有一个名为debug工具栏的文件夹。

在大多数安装中,collectstatic管理命令应注意这一点。

Another thing that can cause the toolbar to remain hidden is if it cannot find the required static files. The debug_toolbar templates use the {{ STATIC_URL }} template tag, so make sure there is a folder in your static files called debug toolbar.

The collectstatic management command should take care of this on most installations.


回答 10

我尝试从pydanny的cookiecutter-django配置,它对有用

# django-debug-toolbar
MIDDLEWARE_CLASSES = Common.MIDDLEWARE_CLASSES + ('debug_toolbar.middleware.DebugToolbarMiddleware',)
INSTALLED_APPS += ('debug_toolbar',)

INTERNAL_IPS = ('127.0.0.1',)

DEBUG_TOOLBAR_CONFIG = {
    'DISABLE_PANELS': [
        'debug_toolbar.panels.redirects.RedirectsPanel',
    ],
    'SHOW_TEMPLATE_CONTEXT': True,
}
# end django-debug-toolbar

我只是通过添加'debug_toolbar.apps.DebugToolbarConfig'而不是django-debug-toolbar官方文档中'debug_toolbar'提到的方式对其进行了修改,因为我使用的是Django 1.7。

I tried the configuration from pydanny’s cookiecutter-django and it worked for me:

# django-debug-toolbar
MIDDLEWARE_CLASSES = Common.MIDDLEWARE_CLASSES + ('debug_toolbar.middleware.DebugToolbarMiddleware',)
INSTALLED_APPS += ('debug_toolbar',)

INTERNAL_IPS = ('127.0.0.1',)

DEBUG_TOOLBAR_CONFIG = {
    'DISABLE_PANELS': [
        'debug_toolbar.panels.redirects.RedirectsPanel',
    ],
    'SHOW_TEMPLATE_CONTEXT': True,
}
# end django-debug-toolbar

I just modified it by adding 'debug_toolbar.apps.DebugToolbarConfig' instead of 'debug_toolbar' as mentioned in the official django-debug-toolbar docs, as I’m using Django 1.7.


回答 11

除了以前的答案:

如果工具栏未显示,但已加载到html中(在浏览器中检查您的站点html,向下滚动)

问题可能是找不到调试工具栏静态文件(然后您也可以在站点的访问日志中看到此信息,例如/static/debug_toolbar/js/toolbar.js的404错误)

然后可以通过以下方式进行修复(nginx和apache的示例):

Nginx的配置:

location ~* ^/static/debug_toolbar/.+.(ico|css|js)$ {
    root [path to your python site-packages here]/site-packages/debug_toolbar;
}

apache配置

Alias /static/debug_toolbar [path to your python site-packages here]/site-packages/debug_toolbar/static/debug_toolbar

要么:

manage.py collectstatic

在这里更多关于collectstatic的内容: https //docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#collectstatic

或手动将debug_toolbar静态文件的debug_toolbar文件夹移动到您设置的静态文件文件夹中

An addition to previous answers:

if the toolbar doesn’t show up, but it loads in the html (check your site html in a browser, scroll down)

the issue can be that debug toolbar static files are not found (you can also see this in your site’s access logs then, e.g. 404 errors for /static/debug_toolbar/js/toolbar.js)

It can be fixed the following way then (examples for nginx and apache):

nginx config:

location ~* ^/static/debug_toolbar/.+.(ico|css|js)$ {
    root [path to your python site-packages here]/site-packages/debug_toolbar;
}

apache config:

Alias /static/debug_toolbar [path to your python site-packages here]/site-packages/debug_toolbar/static/debug_toolbar

Or:

manage.py collectstatic

more on collectstatic here: https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#collectstatic

Or manualy move debug_toolbar folder of debug_toolbar static files to your set static files folder


回答 12

就我而言,这是这里尚未提及的另一个问题:我的中间件列表中有GZipMiddleware。

由于调试工具栏的自动配置将调试工具栏的中间件放在顶部,因此它只能“看到” gzip压缩的HTML,因此无法在其中添加工具栏。

我在开发设置中删除了GZipMiddleware。手动设置调试工具栏的配置,并将中间件放置 GZip 之后也应该可以。

In my case, it was another problem that hasn’t been mentioned here yet: I had GZipMiddleware in my list of middlewares.

As the automatic configuration of debug toolbar puts the debug toolbar’s middleware at the top, it only gets the “see” the gzipped HTML, to which it can’t add the toolbar.

I removed GZipMiddleware in my development settings. Setting up the debug toolbar’s configuration manually and placing the middleware after GZip’s should also work.


回答 13

就我而言,我只需要删除python编译文件(*.pyc

In my case I just needed to remove the python compiled files (*.pyc)


回答 14

Django 1.8.5:

我必须将以下内容添加到项目url.py文件中,以显示调试工具栏。之后,将显示调试工具栏。

 from django.conf.urls import include
 from django.conf.urls import patterns
 from django.conf import settings


  if settings.DEBUG:
      import debug_toolbar
      urlpatterns += patterns('',
              url(r'^__debug__/', include(debug_toolbar.urls)),
              )

Django 1.10:及更高版本:

from django.conf.urls import include, url
from django.conf.urls import patterns
from django.conf import settings


if settings.DEBUG:

  import debug_toolbar
  urlpatterns =[
         url(r'^__debug__/', include(debug_toolbar.urls)),
         ] + urlpatterns

同样不要忘记在中间件中包含debug_toolbar。调试工具栏主要在中间件中实现。如下在您的设置模块中启用它:(django较新版本)


MIDDLEWARE = [
# ...
'debug_toolbar.middleware.DebugToolbarMiddleware',
#

旧式中间件:(需要在中间件中具有_CLASSES键盘功能)

MIDDLEWARE_CLASSES = [
# ...
'debug_toolbar.middleware.DebugToolbarMiddleware',
# ...
]

django 1.8.5:

I had to add the following to the project url.py file to get the debug toolbar display. After that debug tool bar is displayed.

 from django.conf.urls import include
 from django.conf.urls import patterns
 from django.conf import settings


  if settings.DEBUG:
      import debug_toolbar
      urlpatterns += patterns('',
              url(r'^__debug__/', include(debug_toolbar.urls)),
              )

django 1.10: and higher:

from django.conf.urls import include, url
from django.conf.urls import patterns
from django.conf import settings


if settings.DEBUG:

  import debug_toolbar
  urlpatterns =[
         url(r'^__debug__/', include(debug_toolbar.urls)),
         ] + urlpatterns

Also don’t forget to include the debug_toolbar to your middleware. The Debug Toolbar is mostly implemented in a middleware. Enable it in your settings module as follows: (django newer versions)


MIDDLEWARE = [
# ...
'debug_toolbar.middleware.DebugToolbarMiddleware',
#

Old-style middleware:(need to have _CLASSES keywork in the Middleware)

MIDDLEWARE_CLASSES = [
# ...
'debug_toolbar.middleware.DebugToolbarMiddleware',
# ...
]

回答 15

对于这个特定的作者来说不是这种情况,但是我一直在苦苦挣扎,因为Debug Toolbar没有显示出来,并且在他们指出所有步骤之后,我发现MIDDLEWARE订单有问题。因此,将中间件放在列表的前面是可行的。我的是第一个:

MIDDLEWARE_CLASSES = ( 'debug_toolbar.middleware.DebugToolbarMiddleware', 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'dynpages.middleware.DynpageFallbackMiddleware', 'utils.middleware.UserThread', )

This wasn’t the case for this specific author but I just have been struggling with the Debug Toolbar not showing and after doing everything they pointed out, I found out it was a problem with MIDDLEWARE order. So putting the middleware early in the list could work. Mine is first:

MIDDLEWARE_CLASSES = ( 'debug_toolbar.middleware.DebugToolbarMiddleware', 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'dynpages.middleware.DynpageFallbackMiddleware', 'utils.middleware.UserThread', )


回答 16

您必须确保模板中有一个结束标记。

我的问题是我的模板中没有常规的html标签,我只是以纯文本形式显示内容。我通过从base.html继承每个带有标签的html文件来解决它。

you have to make sure there is a closing tag in your templates.

My problem is that there is no regular html tags in my templates, I just display content in plain text. I solved it by inheriting every html file from base.html, which has a tag.


回答 17

对我来说,这就像127.0.0.1:8000在地址栏中键入内容一样简单,而不是localhost:8000显然与INTERNAL_IPS不匹配。

For me this was as simple as typing 127.0.0.1:8000 into the address bar, rather than localhost:8000 which apparently was not matching the INTERNAL_IPS.


回答 18

我遇到了同样的问题,我通过查看Apache的错误日志解决了它。我用mod_wsgi在Mac OS X上运行了Apache。debug_toolbar的tamplete文件夹未加载

日志样本:

==> /private/var/log/apache2/dummy-host2.example.com-error_log <==
[Sun Apr 27 23:23:48 2014] [error] [client 127.0.0.1] File does not exist: /Library/WebServer/Documents/rblreport/rbl/static/debug_toolbar, referer: http://127.0.0.1/

==> /private/var/log/apache2/dummy-host2.example.com-access_log <==
127.0.0.1 - - [27/Apr/2014:23:23:48 -0300] "GET /static/debug_toolbar/css/toolbar.css HTTP/1.1" 404 234 "http://127.0.0.1/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:28.0) Gecko/20100101 Firefox/28.0"

我只是将以下行添加到我的VirtualHost文件中:

Alias /static/debug_toolbar /Library/Python/2.7/site-packages/debug_toolbar/static/debug_toolbar
  • 当然,您必须更改python路径

I got the same problem, I solved it by looking at the Apache’s error log. I got the apache running on mac os x with mod_wsgi The debug_toolbar’s tamplete folder wasn’t being load

Log sample:

==> /private/var/log/apache2/dummy-host2.example.com-error_log <==
[Sun Apr 27 23:23:48 2014] [error] [client 127.0.0.1] File does not exist: /Library/WebServer/Documents/rblreport/rbl/static/debug_toolbar, referer: http://127.0.0.1/

==> /private/var/log/apache2/dummy-host2.example.com-access_log <==
127.0.0.1 - - [27/Apr/2014:23:23:48 -0300] "GET /static/debug_toolbar/css/toolbar.css HTTP/1.1" 404 234 "http://127.0.0.1/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:28.0) Gecko/20100101 Firefox/28.0"

I just add this line to my VirtualHost file:

Alias /static/debug_toolbar /Library/Python/2.7/site-packages/debug_toolbar/static/debug_toolbar
  • Of course you must change your python path

回答 19

我在使用Vagrant时遇到了同样的问题。我通过添加::ffff:192.168.33.1到INTERNAL_IPS来解决此问题,如下例。

INTERNAL_IPS = (
    '::ffff:192.168.33.1',
)

记住那192.168.33.10是我在Vagrantfile中的专用网络中的IP。

I had the same problem using Vagrant. I solved this problem by adding ::ffff:192.168.33.1 to the INTERNAL_IPS as below example.

INTERNAL_IPS = (
    '::ffff:192.168.33.1',
)

Remembering that 192.168.33.10 is the IP in my private network in Vagrantfile.


回答 20

我遇到了这个问题,不得不从源代码安装调试工具栏。

如果使用PureCSS和其他CSS框架,则1.4版存在一个隐藏的问题。

是修复此问题的提交。

该文档解释了如何从源代码安装。

I had this problem and had to install the debug toolbar from source.

Version 1.4 has a problem where it’s hidden if you use PureCSS and apparently other CSS frameworks.

This is the commit which fixes that.

The docs explain how to install from source.


回答 21

对于使用Pycharm 5的任何人-模板调试在某些版本中均不起作用。在5.0.4修复,影响vesions – 5.0.1,5.0.2退房问题

花很多时间找出答案。也许会帮助某人

For anyone who is using Pycharm 5 – template debug is not working there in some versions. Fixed in 5.0.4, affected vesions – 5.0.1, 5.0.2 Check out issue

Spend A LOT time to find that out. Maybe will help someone


回答 22

在我正在处理的代码中,在处理主请求期间提出了多个小请求(这是非常特殊的用例)。它们是由同一Django线程处理的请求。Django调试工具栏(DjDT)不会出现这种情况,它会在第一个响应中包含DjDT的工具栏,然后删除其线程状态。因此,当主请求发送回浏览器时,响应中不包含DjDT。

经验教训:DjDT保存每个线程的状态。它在第一个响应后删除线程的状态。

In the code I was working on, multiple small requests were made during handling of main request (it’s very specific use case). They were requests handled by the same Django’s thread. Django debug toolbar (DjDT) doesn’t expect this behaviour and includes DjDT’s toolbars to the first response and then it removes its state for the thread. So when main request was sent back to the browser, DjDT was not included in the response.

Lessons learned: DjDT saves it’s state per thread. It removes state for a thread after the first response.


回答 23

什么让我是一个过时的浏览器!

注意,它从调试工具栏加载了一些样式表,并猜测可能是前端问题。

What got me is an outdated browser!

Noticed that it loads some stylesheets from debug toolbar and guessed it might be a front-end issue.


回答 24

一件愚蠢的事让我..如果使用apache wsgi,请记住触摸.wsgi文件以强制重新编译代码。只是浪费了我20分钟的时间来调试愚蠢的错误:(

One stupid thing got me.. that if you use apache wsgi, remember to touch the .wsgi file to force your code recompile. just waste 20 minutes of my time to debug the stupid error :(


对于Django 2.0,在urls.py中使用path()或url()更好吗?

问题:对于Django 2.0,在urls.py中使用path()或url()更好吗?

在django在线类中,讲师让我们使用该url()函数调用视图并使用urlpatterns列表中的正则表达式。我在YouTube上看到了其他示例。例如

from django.contrib import admin
from django.urls import include
from django.conf.urls import url

urlpatterns = [
    path('admin/', admin.site.urls),
    url(r'^polls/', include('polls.urls')),
]


#and in polls/urls.py

urlpatterns = [        
    url(r'^$', views.index, name="index"),
]

但是,在阅读Django教程时,他们path()改用例如:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.index, name="index"),        
]

此外,正则表达式似乎不适用于该path()函数,因为使用path(r'^$', views.index, name="index")将找不到mysite.com/polls/视图。

使用path()没有正则表达式匹配的正确方法是正确的吗?是url()更强大,但更复杂,所以他们正在使用path()与开始我们吗?还是针对不同工作使用不同工具的情况?

In a django online course, the instructor has us use the url() function to call views and utilize regular expressions in the urlpatterns list. I’ve seen other examples on youtube of this. e.g.

from django.contrib import admin
from django.urls import include
from django.conf.urls import url

urlpatterns = [
    path('admin/', admin.site.urls),
    url(r'^polls/', include('polls.urls')),
]


#and in polls/urls.py

urlpatterns = [        
    url(r'^$', views.index, name="index"),
]

However, in going through the Django tutorial, they use path() instead e.g.:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.index, name="index"),        
]

Furthermore regular expressions don’t seem to work with the path() function as using a path(r'^$', views.index, name="index") won’t find the mysite.com/polls/ view.

Is using path() without regex matching the proper way going forward? Is url() more powerful but more complicated so they’re using path() to start us out with? Or is it a case of different tools for different jobs?


回答 0

从Django文档获取url

url(regex, view, kwargs=None, name=None)此函数是的别名django.urls.re_path()。在将来的版本中可能不推荐使用。

path和之间的主要区别re_pathpath使用不带正则表达式的路由

您可以re_path用于复杂的正则表达式调用,也可以仅path用于更简单的查找

From Django documentation for url

url(regex, view, kwargs=None, name=None) This function is an alias to django.urls.re_path(). It’s likely to be deprecated in a future release.

Key difference between path and re_path is that path uses route without regex

You can use re_path for complex regex calls and use just path for simpler lookups


回答 1

django.urls.path()功能允许使用更简单,更易读的URL路由语法。例如,此示例来自先前的Django版本:

url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive)

可以写成:

path('articles/<int:year>/', views.year_archive)

django.conf.urls.url() 以前版本中的功能现在可以作为django.urls.re_path()。保留旧位置是为了向后兼容,而不会很快淘汰。django.conf.urls.include()现在django.urls可以从导入旧功能,因此您可以使用:

from django.urls import include, path, re_path

URLconfs中。进一步阅读django doc

The new django.urls.path() function allows a simpler, more readable URL routing syntax. For example, this example from previous Django releases:

url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive)

could be written as:

path('articles/<int:year>/', views.year_archive)

The django.conf.urls.url() function from previous versions is now available as django.urls.re_path(). The old location remains for backwards compatibility, without an imminent deprecation. The old django.conf.urls.include() function is now importable from django.urls so you can use:

from django.urls import include, path, re_path

in the URLconfs. For further reading django doc


回答 2

pathDjango 2.0只是几周前才发布的新功能。大多数教程都不会针对新语法进行更新。

当然,这应该是一种更简单的处理方式。我不会说URL更强大,但是您应该能够以任何一种格式表示模式。

path is simply new in Django 2.0, which was only released a couple of weeks ago. Most tutorials won’t have been updated for the new syntax.

It was certainly supposed to be a simpler way of doing things; I wouldn’t say that URL is more powerful though, you should be able to express patterns in either format.


回答 3

正则表达式似乎不适用于path()具有以下参数的函数:path(r'^$', views.index, name="index")

应该是这样的:path('', views.index, name="index")

第一个参数必须为空才能输入正则表达式。

Regular expressions don’t seem to work with the path() function with the following arguments: path(r'^$', views.index, name="index").

It should be like this: path('', views.index, name="index").

The 1st argument must be blank to enter a regular expression.


回答 4

Path是Django 2.0的新功能。在这里解释:https : //docs.djangoproject.com/en/2.0/releases/2.0/#whats-new-2-0

看起来更像pythonic方式,并允许在传递给视图的参数中不使用正则表达式…例如,您可以使用int()函数。

Path is a new feature of Django 2.0. Explained here : https://docs.djangoproject.com/en/2.0/releases/2.0/#whats-new-2-0

Look like more pythonic way, and enable to not use regular expression in argument you pass to view… you can ue int() function for exemple.


回答 5

从v2.0开始,许多用户正在使用path,但是我们可以使用path或url。例如,在django 2.1.1中,可以通过url映射到函数

from django.contrib import admin
from django.urls import path

from django.contrib.auth import login
from posts.views import post_home
from django.conf.urls import url

urlpatterns = [
    path('admin/', admin.site.urls),
    url(r'^posts/$', post_home, name='post_home'),

]

其中posts是应用程序,而post_home是views.py中的函数

From v2.0 many users are using path, but we can use either path or url. For example in django 2.1.1 mapping to functions through url can be done as follows

from django.contrib import admin
from django.urls import path

from django.contrib.auth import login
from posts.views import post_home
from django.conf.urls import url

urlpatterns = [
    path('admin/', admin.site.urls),
    url(r'^posts/$', post_home, name='post_home'),

]

where posts is an application & post_home is a function in views.py


在运行时确定带有upload_to的Django FileField

问题:在运行时确定带有upload_to的Django FileField

我正在尝试设置我的上传文件,以便如果用户joe上传文件,则文件将转到MEDIA_ROOT / joe,而不是让每个人的文件都转到MEDIA_ROOT。问题是我不知道如何在模型中定义它。这是当前的外观:

class Content(models.Model):
    name = models.CharField(max_length=200)
    user = models.ForeignKey(User)
    file = models.FileField(upload_to='.')

所以我想要的不是“。” 作为upload_to,将其作为用户名。

我知道从Django 1.0开始,您可以定义自己的函数来处理upload_to,但是该函数也不知道谁将成为谁,所以我有点迷失了。

谢谢您的帮助!

I’m trying to set up my uploads so that if user joe uploads a file it goes to MEDIA_ROOT/joe as opposed to having everyone’s files go to MEDIA_ROOT. The problem is I don’t know how to define this in the model. Here is how it currently looks:

class Content(models.Model):
    name = models.CharField(max_length=200)
    user = models.ForeignKey(User)
    file = models.FileField(upload_to='.')

So what I want is instead of ‘.’ as the upload_to, have it be the user’s name.

I understand that as of Django 1.0 you can define your own function to handle the upload_to but that function has no idea of who the user will be either so I’m a bit lost.

Thanks for the help!


回答 0

您可能已经阅读了文档,所以这里有一个简单的示例可以使之有意义:

def content_file_name(instance, filename):
    return '/'.join(['content', instance.user.username, filename])

class Content(models.Model):
    name = models.CharField(max_length=200)
    user = models.ForeignKey(User)
    file = models.FileField(upload_to=content_file_name)

如您所见,您甚至不需要使用给定的文件名-如果愿意,您也可以覆盖您可调用的upload_to中的文件名。

You’ve probably read the documentation, so here’s an easy example to make it make sense:

def content_file_name(instance, filename):
    return '/'.join(['content', instance.user.username, filename])

class Content(models.Model):
    name = models.CharField(max_length=200)
    user = models.ForeignKey(User)
    file = models.FileField(upload_to=content_file_name)

As you can see, you don’t even need to use the filename given – you could override that in your upload_to callable too if you liked.


回答 1

这确实有帮助。为了简洁起见,决定在我的情况下使用lambda:

file = models.FileField(
    upload_to=lambda instance, filename: '/'.join(['mymodel', str(instance.pk), filename]),
)

This really helped. For a bit more brevity’s sake, decided to use lambda in my case:

file = models.FileField(
    upload_to=lambda instance, filename: '/'.join(['mymodel', str(instance.pk), filename]),
)

回答 2

关于使用“实例”对象的pk值的注释。根据文档:

在大多数情况下,此对象尚未保存到数据库,因此,如果使用默认的AutoField,则它的主键字段可能尚未具有值。

因此,使用pk的有效性取决于特定模型的定义。

A note on using the ‘instance’ object’s pk value. According to the documentation:

In most cases, this object will not have been saved to the database yet, so if it uses the default AutoField, it might not yet have a value for its primary key field.

Therefore the validity of using pk depends on how your particular model is defined.


回答 3

如果您在迁移时遇到问题,则可能应该使用@deconstructible装饰器。

import datetime
import os
import unicodedata

from django.core.files.storage import default_storage
from django.utils.deconstruct import deconstructible
from django.utils.encoding import force_text, force_str


@deconstructible
class UploadToPath(object):
    def __init__(self, upload_to):
        self.upload_to = upload_to

    def __call__(self, instance, filename):
        return self.generate_filename(filename)

    def get_directory_name(self):
        return os.path.normpath(force_text(datetime.datetime.now().strftime(force_str(self.upload_to))))

    def get_filename(self, filename):
        filename = default_storage.get_valid_name(os.path.basename(filename))
        filename = force_text(filename)
        filename = unicodedata.normalize('NFKD', filename).encode('ascii', 'ignore').decode('ascii')
        return os.path.normpath(filename)

    def generate_filename(self, filename):
        return os.path.join(self.get_directory_name(), self.get_filename(filename))

用法:

class MyModel(models.Model):
    file = models.FileField(upload_to=UploadToPath('files/%Y/%m/%d'), max_length=255)

If you have problems with migrations you probably should be using @deconstructible decorator.

import datetime
import os
import unicodedata

from django.core.files.storage import default_storage
from django.utils.deconstruct import deconstructible
from django.utils.encoding import force_text, force_str


@deconstructible
class UploadToPath(object):
    def __init__(self, upload_to):
        self.upload_to = upload_to

    def __call__(self, instance, filename):
        return self.generate_filename(filename)

    def get_directory_name(self):
        return os.path.normpath(force_text(datetime.datetime.now().strftime(force_str(self.upload_to))))

    def get_filename(self, filename):
        filename = default_storage.get_valid_name(os.path.basename(filename))
        filename = force_text(filename)
        filename = unicodedata.normalize('NFKD', filename).encode('ascii', 'ignore').decode('ascii')
        return os.path.normpath(filename)

    def generate_filename(self, filename):
        return os.path.join(self.get_directory_name(), self.get_filename(filename))

Usage:

class MyModel(models.Model):
    file = models.FileField(upload_to=UploadToPath('files/%Y/%m/%d'), max_length=255)

如何复制virtualenv

问题:如何复制virtualenv

我有一个现有的virtualenv,其中包含很多软件包,但是旧版本的Django。

我想要做的就是复制此环境,因此我有另一个环境,它们的软件包完全相同,但是 Django的更新版本。我怎样才能做到这一点?

I have an existing virtualenv with a lot of packages but an old version of Django.

What I want to do is duplicate this environment so I have another environment with the exact same packages but a newer version of Django. How can I do this?


回答 0

最简单的方法是使用pip生成需求文件。需求文件基本上是一个文件,其中包含要安装(或在pip生成文件的情况下已经安装)所有python软件包的列表,以及它们的版本。

要生成需求文件,请进入原始的virtualenv,然后运行:

pip freeze > requirements.txt

这将为您生成requirements.txt文件。如果您在喜欢的文本编辑器中打开该文件,则会看到类似以下内容的内容:

Django==1.3
Fabric==1.0.1
etc...

现在,编辑这行Django==x.xDjango==1.3(或任何版本要在新的virtualenv安装)。

最后,激活新的 virtualenv并运行:

pip install -r requirements.txt

然后pip会自动下载并安装您requirements.txt文件中列出的所有python模块,无论您使用的是哪个版本!

The easiest way is to use pip to generate a requirements file. A requirements file is basically a file that contains a list of all the python packages you want to install (or have already installed in case of file generated by pip), and what versions they’re at.

To generate a requirements file, go into your original virtualenv, and run:

pip freeze > requirements.txt

This will generate the requirements.txt file for you. If you open that file up in your favorite text editor, you’ll see something like:

Django==1.3
Fabric==1.0.1
etc...

Now, edit the line that says Django==x.x to say Django==1.3 (or whatever version you want to install in your new virtualenv).

Lastly, activate your new virtualenv, and run:

pip install -r requirements.txt

And pip will automatically download and install all the python modules listed in your requirements.txt file, at whatever versions you specified!


回答 1

另一种选择是使用virtualenv-clone包:

用于克隆不可重定位的virtualenv的脚本。

Another option is to use virtualenv-clone package:

A script for cloning a non-relocatable virtualenv.


回答 2

virtualenvwrapper提供复制虚拟环境命令

cpvirtualenv ENVNAME [TARGETENVNAME]

virtualenvwrapper provides a command to duplicate virtualenv

cpvirtualenv ENVNAME [TARGETENVNAME]

回答 3

如果您正在使用Anaconda,则可以运行:

conda create --name myclone --clone myenv

这将复制myenv到名为的新创建的环境myclone

If you are using Anaconda you can just run:

conda create --name myclone --clone myenv

This will copy myenv to the newly created environment called myclone.


回答 4

最简单的选择是使用virtualenv-clone软件包。

要复制venv1venv2,请按照以下步骤操作:

  1. 安装virtualenv-clone在任一venv1或虚拟的虚拟环境venv_dummy。创建venv_dummy

    python -m virtualenv venv_dummy
    source venv_dummy/bin/activate
  2. 要安装virtualenv-clone

    (venv_dummy): pip install virtualenv-clone
  3. 复制venv1venv2

    (venv_dummy): virtualenv-clone venv1/ venv2/

Easiest option is using virtualenv-clone package.

To duplicate venv1 to venv2, follow these steps:

  1. Install virtualenv-clone in either venv1 or a dummy virtual environment venv_dummy. To create venv_dummy:

    python -m virtualenv venv_dummy
    source venv_dummy/bin/activate
    
  2. To install virtualenv-clone:

    (venv_dummy): pip install virtualenv-clone
    
  3. To duplicate venv1 to venv2:

    (venv_dummy): virtualenv-clone venv1/ venv2/
    

回答 5

您能不能简单地:

  • 将现有的虚拟环境目录复制到新目录
  • 更新到新的Django?

Can you not simply:

  • Copy the existing virtual env directory to a new one
  • Update to the new Django?

我应该在.gitignore文件中添加Django迁移文件吗?

问题:我应该在.gitignore文件中添加Django迁移文件吗?

我应该在文件中添加Django迁移.gitignore文件吗?

由于迁移冲突,我最近遇到了很多git问题,并且想知道是否应该将迁移文件标记为“忽略”。

如果是这样,我将如何添加我在应用程序中拥有的所有迁移并将它们添加到.gitignore文件中?

Should I be adding the Django migration files in the .gitignore file?

I’ve recently been getting a lot of git issues due to migration conflicts and was wondering if I should be marking migration files as ignore.

If so, how would I go about adding all of the migrations that I have in my apps, and adding them to the .gitignore file?


回答 0

引用Django迁移文档

每个应用程序的迁移文件都位于该应用程序内的“迁移”目录中,并被设计为提交至其代码库并作为其代码库的一部分进行分发。您应该在开发计算机上制作一次,然后在同事的计算机,登台计算机以及最终的生产计算机上运行相同的迁移。

如果遵循此过程,则迁移文件中不会出现任何合并冲突。

合并版本控制分支时,您仍然可能会遇到基于同一父级迁移的多个迁移的情况,例如,如果不同的开发人员同时引入了迁移。解决这种情况的一种方法是引入_merge_migration_。通常这可以通过以下命令自动完成

./manage.py makemigrations --merge

这将引入一个新的迁移,该迁移取决于当前的所有head迁移。当然,这仅在磁头迁移之间没有冲突时才有效,在这种情况下,您将必须手动解决问题。


鉴于这里有人建议您不要将迁移提交到版本控制,因此我想详细说明为什么您应该这样做。

首先,您需要记录应用于生产系统的迁移。如果将更改部署到生产中并想迁移数据库,则需要描述当前状态。您可以为应用到每个生产数据库的迁移创建单独的备份,但这似乎不必要。

其次,迁移通常包含自定义的手写代码。并非总是可以使用自动生成它们./manage.py makemigrations

第三,迁移应包含在代码审查中。它们是对您的生产系统的重大更改,很多事情都可能出错。

简而言之,如果您关心生产数据,请检查您向版本控制的迁移。

Quoting from the Django migrations documentation:

The migration files for each app live in a “migrations” directory inside of that app, and are designed to be committed to, and distributed as part of, its codebase. You should be making them once on your development machine and then running the same migrations on your colleagues’ machines, your staging machines, and eventually your production machines.

If you follow this process, you shouldn’t be getting any merge conflicts in the migration files.

When merging version control branches, you still may encounter a situation where you have multiple migrations based on the same parent migration, e.g. if to different developers introduced a migration concurrently. One way of resolving this situation is to introduce a _merge_migration_. Often this can be done automatically with the command

./manage.py makemigrations --merge

which will introduce a new migration that depends on all current head migrations. Of course this only works when there is no conflict between the head migrations, in which case you will have to resolve the problem manually.


Given that some people here suggested that you shouldn’t commit your migrations to version control, I’d like to expand on the reasons why you actually should do so.

First, you need a record of the migrations applied to your production systems. If you deploy changes to production and want to migrate the database, you need a description of the current state. You can create a separate backup of the migrations applied to each production database, but this seems unnecessarily cumbersome.

Second, migrations often contain custom, handwritten code. It’s not always possible to automatically generate them with ./manage.py makemigrations.

Third, migrations should be included in code review. They are significant changes to your production system, and there are lots of things that can go wrong with them.

So in short, if you care about your production data, please check your migrations into version control.


回答 1

您可以按照以下过程进行操作。

您可以在makemigrations本地运行,这将创建迁移文件。提交此新的迁移文件以回购。

我认为您根本不应该makemigrations投入生产。您可以migrate在生产环境中运行,并且会看到从您从本地提交的迁移文件中应用了迁移。这样您可以避免所有冲突。

在本地环境中,要创建迁移文件,

python manage.py makemigrations 
python manage.py migrate

现在提交这些新创建的文件,如下所示。

git add app/migrations/...
git commit -m 'add migration files' app/migrations/...

在生产环境中,仅运行以下命令。

python manage.py migrate

You can follow the below process.

You can run makemigrations locally and this creates the migration file. Commit this new migration file to repo.

In my opinion you should not run makemigrations in production at all. You can run migrate in production and you will see the migrations are applied from the migration file that you committed from local. This way you can avoid all conflicts.

IN LOCAL ENV, to create the migration files,

python manage.py makemigrations 
python manage.py migrate

Now commit these newly created files, something like below.

git add app/migrations/...
git commit -m 'add migration files' app/migrations/...

IN PRODUCTION ENV, run only the below command.

python manage.py migrate

回答 2

引用2018年文档Django 2.0。(两个单独的命令= makemigrationsmigrate

之所以有单独的命令来进行和应用迁移,是因为您会将迁移提交到版本控制系统,并随应用程序一起交付;它们不仅使您的开发更加容易,而且还可以被其他开发人员和生产环境使用。

https://docs.djangoproject.com/en/2.0/intro/tutorial02/

Quote from the 2018 docs, Django 2.0. (two separate commands = makemigrations and migrate)

The reason that there are separate commands to make and apply migrations is because you’ll commit migrations to your version control system and ship them with your app; they not only make your development easier, they’re also useable by other developers and in production.

https://docs.djangoproject.com/en/2.0/intro/tutorial02/


回答 3

TL; DR:提交迁移,解决迁移冲突,调整git工作流程。

感觉就像您需要调整git工作流程,而不是忽略冲突。

理想情况下,每个新功能都在不同的分支中开发,并与拉取请求合并回去。

如果存在冲突,则无法合并PR,因此需要合并其功能的人员需要解决冲突,包括迁移。这可能需要不同团队之间的协调。

提交迁移文件很重要!如果发生冲突,Django甚至可以帮助您解决那些冲突 ;)

TL;DR: commit migrations, resolve migration conflicts, adjust your git workflow.

Feels like you’d need to adjust your git workflow, instead of ignoring conflicts.

Ideally, every new feature is developed in a different branch, and merged back with a pull request.

PRs cannot be merged if there’s a conflict, therefore who needs to merge his feature needs to resolve the conflict, migrations included. This might need coordination between different teams.

It is important though to commit migration files! If a conflict arises, Django might even help you solve those conflicts ;)


回答 4

我无法想象为什么会出现冲突,除非您以某种方式编辑迁移?通常情况下,这很糟糕-如果有人错过了一些中间提交,那么他们就不会从正确的版本升级,并且他们的数据库副本也会被破坏。

我遵循的过程非常简单-每当您更改应用程序的模型时,您也会提交迁移,然后迁移不会改变 -如果您需要模型中的其他内容,则可以更改模型并提交新的迁移以及您的更改。

在未开发项目中,您通常可以删除迁移,并在发布时从0001_开始重新迁移,但是如果您具有生产代码,则不能(尽管可以将迁移压缩为一个)。

I can’t imagine why you would be getting conflicts, unless you’re editing the migrations somehow? That usually ends badly – if someone misses some intermediate commits then they won’t be upgrading from the correct version, and their copy of the database will be corrupted.

The process that I follow is pretty simple – whenever you change the models for an app, you also commit a migration, and then that migration doesn’t change – if you need something different in the model, then you change the model and commit a new migration alongside your changes.

In greenfield projects, you can often delete the migrations and start over from scratch with a 0001_ migration when you release, but if you have production code, then you can’t (though you can squash migrations down into one).


回答 5

通常使用的解决方案是,在将任何东西合并到母版之前,开发人员必须拉动任何远程更改。如果迁移版本存在冲突,则他应将其本地迁移(远程迁移已由其他开发人员运行,并且有可能在生产环境中)重命名为N + 1。

在开发过程中,不提交迁移就可以了(尽管不要添加忽略,只是不要添加忽略add)。但是一旦投入生产,就需要使用它们,以使模式与模型更改保持同步。

然后,您需要编辑文件,并将其更改dependencies为最新的远程版本。

这适用于Django迁移以及其他类似应用程序(sqlalchemy + alembic,RoR等)。

The solution usually used, is that, before anything is merged into master, the developer must pull any remote changes. If there’s a conflict in migration versions, he should rename his local migration (the remote one has been run by other devs, and, potentially, in production), to N+1.

During development it might be okay to just not-commit migrations (don’t add an ignore though, just don’t add them). But once you’ve gone into production, you’ll need them in order to keep the schema in sync with model changes.

You then need to edit the file, and change the dependencies to the latest remote version.

This works for Django migrations, as well as other similar apps (sqlalchemy+alembic, RoR, etc).


回答 6

在git中有一堆迁移文件很麻烦。迁移文件夹中只有一个文件,您不应忽略。该文件是init .py文件,如果忽略它,python将不再在目录内寻找子模块,因此任何导入模块的尝试都会失败。所以问题应该怎么忽略所有迁移文件,但初始化的.py?解决方案是:将’0 * .py’添加到.gitignore文件中,即可完美完成工作。

希望这对某人有帮助。

Having a bunch of migration files in git is messy. There is only one file in migration folder that you should not ignore. That file is init.py file, If you ignore it, python will no longer look for submodules inside the directory, so any attempts to import the modules will fail. So the question should be how to ignore all migration files but init.py? The solution is: Add ‘0*.py’ to .gitignore files and it does the job perfectly.

Hope this helps someone.


回答 7

如果您具有用于开发,登台和生产环境的单独的数据库,则忽略迁移。对于开发人员。目的您可以使用本地sqlite DB并在本地进行迁移。我建议您另外创建四个分支:

  1. 主-清除新代码而不进行迁移。没有人连接到该分支。仅用于代码审查

  2. 开发-日常开发。接受推/拉。每个开发人员都在使用sqlite DB

  3. Cloud_DEV_env-远程云/服务器DEV环境。只拉。将迁移保留在本地计算机上,用于代码部署和Dev数据库的远程迁移

  4. Cloud_STAG_env-远程云/服务器STAG环境。只拉。将迁移保留在本地计算机上,该迁移用于Stag数据库的代码部署和远程迁移

  5. Cloud_PROD_env-远程云/服务器DEV环境。只拉。将迁移保留在本地计算机上,该迁移用于Prod数据库的代码部署和远程迁移

注意:2、3、4-迁移可以保存在存储库中,但是应该有合并合并拉取请求的严格规则,因此我们决定找一个负责部署的人员,所以唯一拥有所有迁移文件的人-我们的部署-嗯 每当我们对模型进行任何更改时,他都会保留远程数据库迁移。

Gitignore the migrations, if You have separate DBs for Development, Staging and Production environment. For dev. purposes You can use local sqlite DB and play with migrations locally. I would recommend You to create four additional branches:

  1. Master – Clean fresh code without migrations. Nobody is connected to this branch. Used for code reviews only

  2. Development – daily development. Push/pull accepted. Each developer is working on sqlite DB

  3. Cloud_DEV_env – remote cloud/server DEV environment. Pull only. Keep migrations locally on machine, which is used for the code deployment and remote migrations of Dev database

  4. Cloud_STAG_env – remote cloud/server STAG environment. Pull only. Keep migrations locally on machine, which is used for the code deployment and remote migrations of Stag database

  5. Cloud_PROD_env – remote cloud/server DEV environment. Pull only. Keep migrations locally on machine, which is used for the code deployment and remote migrations of Prod database

Notes: 2, 3, 4 – migrations can be kept in repos but there should be strict rules of pull requests merging, so we decided to find a person, responsible for deployments, so the only guy who has all the migration files – our deploy-er. He keeps the remote DB migrations each time we have any changes in Models.


回答 8

简短答案 我建议排除回购中的迁移。代码合并后,只需运行即可./manage.py makemigrations

长答案 我不认为您应该将迁移文件放入存储库中。它将破坏其他人的开发环境以及其他产品和阶段环境中的迁移状态。(有关示例,请参见Sugar Tang的评论)。

以我的观点,Django迁移的目的是找到先前模型状态和新模型状态之间的差距,然后序列化该差距。如果您的模型在代码合并后发生更改,则可以简单makemigrations地找出差距。当您可以自动实现相同且无错误的迁移时,为什么要手动仔细合并其他迁移?Django文档说,

它们*(迁移)*被设计为自动的

; 请保持这种方式。要手动合并迁移,您必须完全了解其他更改和更改的任何依存关系。这会产生很多开销,而且容易出错。因此,跟踪模型文件就足够了。

这是工作流程中的一个好话题。我愿意接受其他选择。

Short answer I propose excluding migrations in the repo. After code merge, just run ./manage.py makemigrations and you are all set.

Long answer I don’t think you should put migrations files into repo. It will spoil the migration states in other person’s dev environment and other prod and stage environment. (refer to Sugar Tang’s comment for examples).

In my point of view, the purpose of Django migrations is to find gaps between previous model states and new model states, and then serialise the gap. If your model changes after code merge, you can simple do makemigrations to find out the gap. Why do you want to manually and carefully merge other migrations when you can achieve the same automatically and bug free? Django documentation says,

They*(migrations)*’re designed to be mostly automatic

; please keep it that way. To merge migrations manually, you have to fully understand what others have changed and any dependence of the changes. That’s a lot of overhead and error prone. So tracking models file is sufficient.

It is a good topic on the workflow. I am open to other options.


将Django表单字段更改为隐藏字段

问题:将Django表单字段更改为隐藏字段

我有一个带的Django表单,与RegexField正常的文本输入字段非常相似。

我认为,在某些情况下,我想对用户隐藏它,并尝试使表单尽可能相似。将这个领域变成一个HiddenInput领域的最好方法是什么?

我知道我可以使用以下方法在字段上设置属性:

form['fieldname'].field.widget.attr['readonly'] = 'readonly'

我可以通过以下方式设置所需的初始值:

form.initial['fieldname'] = 'mydesiredvalue'

但是,这不会更改小部件的形式。

什么是使此字段成为<input type="hidden">字段的最佳/最“ django-y” /最不“ hacky”的方法?

I have a Django form with a RegexField, which is very similar to a normal text input field.

In my view, under certain conditions I want to hide it from the user, and trying to keep the form as similar as possible. What’s the best way to turn this field into a HiddenInput field?

I know I can set attributes on the field with:

form['fieldname'].field.widget.attr['readonly'] = 'readonly'

And I can set the desired initial value with:

form.initial['fieldname'] = 'mydesiredvalue'

However, that won’t change the form of the widget.

What’s the best / most “django-y” / least “hacky” way to make this field a <input type="hidden"> field?


回答 0

如果您具有自定义模板并查看,则可以排除该字段并用于{{ modelform.instance.field }}获取值。

您也可以在视图中使用:

form.fields['field_name'].widget = forms.HiddenInput()

但我不确定它是否会保护发布后的保存方法。

希望能帮助到你。

If you have a custom template and view you may exclude the field and use {{ modelform.instance.field }} to get the value.

also you may prefer to use in the view:

form.fields['field_name'].widget = forms.HiddenInput()

but I’m not sure it will protect save method on post.

Hope it helps.


回答 1

这也可能有用: {{ form.field.as_hidden }}

This may also be useful: {{ form.field.as_hidden }}


回答 2

一个对我有用的选项,将字段的原始形式定义为:

forms.CharField(widget = forms.HiddenInput(), required = False)

那么当您在新的类中覆盖它时,它将保留它的位置。

an option that worked for me, define the field in the original form as:

forms.CharField(widget = forms.HiddenInput(), required = False)

then when you override it in the new Class it will keep it’s place.


回答 3

首先,如果您不希望用户修改数据,则仅排除该字段似乎更干净。将其包含为隐藏字段只会增加更多数据以通过有线方式发送,并在您不希望恶意用户修改时邀请它们进行修改。如果确实有理由包括该字段但将其隐藏,则可以将关键字arg传递给modelform的构造函数。可能是这样的:

class MyModelForm(forms.ModelForm):
    class Meta:
        model = MyModel
    def __init__(self, *args, **kwargs):
        from django.forms.widgets import HiddenInput
        hide_condition = kwargs.pop('hide_condition',None)
        super(MyModelForm, self).__init__(*args, **kwargs)
        if hide_condition:
            self.fields['fieldname'].widget = HiddenInput()
            # or alternately:  del self.fields['fieldname']  to remove it from the form altogether.

然后在您看来:

form = MyModelForm(hide_condition=True)

在视图中,我更喜欢这种方法来修改模型形式的内部,但这只是一个问题。

Firstly, if you don’t want the user to modify the data, then it seems cleaner to simply exclude the field. Including it as a hidden field just adds more data to send over the wire and invites a malicious user to modify it when you don’t want them to. If you do have a good reason to include the field but hide it, you can pass a keyword arg to the modelform’s constructor. Something like this perhaps:

class MyModelForm(forms.ModelForm):
    class Meta:
        model = MyModel
    def __init__(self, *args, **kwargs):
        from django.forms.widgets import HiddenInput
        hide_condition = kwargs.pop('hide_condition',None)
        super(MyModelForm, self).__init__(*args, **kwargs)
        if hide_condition:
            self.fields['fieldname'].widget = HiddenInput()
            # or alternately:  del self.fields['fieldname']  to remove it from the form altogether.

Then in your view:

form = MyModelForm(hide_condition=True)

I prefer this approach to modifying the modelform’s internals in the view, but it’s a matter of taste.


回答 4

对于正常形式,您可以

class MyModelForm(forms.ModelForm):
    slug = forms.CharField(widget=forms.HiddenInput())

如果您有模型表格,则可以执行以下操作

class MyModelForm(forms.ModelForm):
    class Meta:
        model = TagStatus
        fields = ('slug', 'ext')
        widgets = {'slug': forms.HiddenInput()}

您也可以覆盖__init__方法

class Myform(forms.Form):
    def __init__(self, *args, **kwargs):
        super(Myform, self).__init__(*args, **kwargs)
        self.fields['slug'].widget = forms.HiddenInput()

For normal form you can do

class MyModelForm(forms.ModelForm):
    slug = forms.CharField(widget=forms.HiddenInput())

If you have model form you can do the following

class MyModelForm(forms.ModelForm):
    class Meta:
        model = TagStatus
        fields = ('slug', 'ext')
        widgets = {'slug': forms.HiddenInput()}

You can also override __init__ method

class Myform(forms.Form):
    def __init__(self, *args, **kwargs):
        super(Myform, self).__init__(*args, **kwargs)
        self.fields['slug'].widget = forms.HiddenInput()

回答 5

如果要始终隐藏该字段,请使用以下命令:

class MyForm(forms.Form):
    hidden_input = forms.CharField(widget=forms.HiddenInput(), initial="value")

If you want the field to always be hidden, use the following:

class MyForm(forms.Form):
    hidden_input = forms.CharField(widget=forms.HiddenInput(), initial="value")

回答 6

您可以只使用css:

#id_fieldname, label[for="id_fieldname"] {
  position: absolute;
  display: none
}

这将使该字段及其标签不可见。

You can just use css :

#id_fieldname, label[for="id_fieldname"] {
  position: absolute;
  display: none
}

This will make the field and its label invisible.


如何在Django模板的词典中遍历词典?

问题:如何在Django模板的词典中遍历词典?

我的字典看起来像这样(字典中的字典):

{'0': {
    'chosen_unit': <Unit: Kg>,
    'cost': Decimal('10.0000'),
    'unit__name_abbrev': u'G',
    'supplier__supplier': u"Steve's Meat Locker",
    'price': Decimal('5.00'),
    'supplier__address': u'No\r\naddress here',
    'chosen_unit_amount': u'2',
    'city__name': u'Joburg, Central',
    'supplier__phone_number': u'02299944444',
    'supplier__website': None,
    'supplier__price_list': u'',
    'supplier__email': u'ss.sss@ssssss.com',
    'unit__name': u'Gram',
    'name': u'Rump Bone',
}}

现在,我只是想在模板上显示信息,但是我很挣扎。我的模板代码如下:

{% if landing_dict.ingredients %}
  <hr>
  {% for ingredient in landing_dict.ingredients %}
    {{ ingredient }}
  {% endfor %}
  <a href="/">Print {{ landing_dict.recipe_name }}</a>
{% else %}
  Please search for an ingredient below
{% endif %}

它只是在模板上显示“ 0”?

我也尝试过:

{% for ingredient in landing_dict.ingredients %}
  {{ ingredient.cost }}
{% endfor %}

这甚至不显示结果。

我认为也许我需要更深一层地迭代,所以尝试了一下:

{% if landing_dict.ingredients %}
  <hr>
  {% for ingredient in landing_dict.ingredients %}
    {% for field in ingredient %}
      {{ field }}
    {% endfor %}
  {% endfor %}
  <a href="/">Print {{ landing_dict.recipe_name }}</a>
{% else %}
  Please search for an ingredient below
{% endif %}

但这不会显示任何内容。

我究竟做错了什么?

My dictionary looks like this(Dictionary within a dictionary):

{'0': {
    'chosen_unit': <Unit: Kg>,
    'cost': Decimal('10.0000'),
    'unit__name_abbrev': u'G',
    'supplier__supplier': u"Steve's Meat Locker",
    'price': Decimal('5.00'),
    'supplier__address': u'No\r\naddress here',
    'chosen_unit_amount': u'2',
    'city__name': u'Joburg, Central',
    'supplier__phone_number': u'02299944444',
    'supplier__website': None,
    'supplier__price_list': u'',
    'supplier__email': u'ss.sss@ssssss.com',
    'unit__name': u'Gram',
    'name': u'Rump Bone',
}}

Now I’m just trying to display the information on my template but I’m struggling. My code for the template looks like:

{% if landing_dict.ingredients %}
  <hr>
  {% for ingredient in landing_dict.ingredients %}
    {{ ingredient }}
  {% endfor %}
  <a href="/">Print {{ landing_dict.recipe_name }}</a>
{% else %}
  Please search for an ingredient below
{% endif %}

It just shows me ‘0’ on my template?

I also tried:

{% for ingredient in landing_dict.ingredients %}
  {{ ingredient.cost }}
{% endfor %}

This doesn’t even display a result.

I thought perhaps I need to iterate one level deeper so tried this:

{% if landing_dict.ingredients %}
  <hr>
  {% for ingredient in landing_dict.ingredients %}
    {% for field in ingredient %}
      {{ field }}
    {% endfor %}
  {% endfor %}
  <a href="/">Print {{ landing_dict.recipe_name }}</a>
{% else %}
  Please search for an ingredient below
{% endif %}

But this doesn’t display anything.

What am I doing wrong?


回答 0

可以说您的数据是-

data = {'a': [ [1, 2] ], 'b': [ [3, 4] ],'c':[ [5,6]] }

您可以使用该data.items()方法来获取字典元素。请注意,在Django模板中,我们不放置()。另外提到的一些用户values[0]不起作用,如果是这种情况,请尝试values.items

<table>
    <tr>
        <td>a</td>
        <td>b</td>
        <td>c</td>
    </tr>

    {% for key, values in data.items %}
    <tr>
        <td>{{key}}</td>
        {% for v in values[0] %}
        <td>{{v}}</td>
        {% endfor %}
    </tr>
    {% endfor %}
</table>

相当确定您可以将此逻辑扩展到您的特定字典。


要以排序的顺序遍历dict键 -首先,我们在python中排序,然后在django模板中进行迭代和渲染。

return render_to_response('some_page.html', {'data': sorted(data.items())})

在模板文件中:

{% for key, value in data %}
    <tr>
        <td> Key: {{ key }} </td> 
        <td> Value: {{ value }} </td>
    </tr>
{% endfor %}

Lets say your data is –

data = {'a': [ [1, 2] ], 'b': [ [3, 4] ],'c':[ [5,6]] }

You can use the data.items() method to get the dictionary elements. Note, in django templates we do NOT put (). Also some users mentioned values[0] does not work, if that is the case then try values.items.

<table>
    <tr>
        <td>a</td>
        <td>b</td>
        <td>c</td>
    </tr>

    {% for key, values in data.items %}
    <tr>
        <td>{{key}}</td>
        {% for v in values[0] %}
        <td>{{v}}</td>
        {% endfor %}
    </tr>
    {% endfor %}
</table>

Am pretty sure you can extend this logic to your specific dict.


To iterate over dict keys in a sorted order – First we sort in python then iterate & render in django template.

return render_to_response('some_page.html', {'data': sorted(data.items())})

In template file:

{% for key, value in data %}
    <tr>
        <td> Key: {{ key }} </td> 
        <td> Value: {{ value }} </td>
    </tr>
{% endfor %}

回答 1

这个答案对我没有用,但是我自己找到了答案。但是,没有人发布我的问题。我懒得先问再回答,所以就把它放在这里。

这用于以下查询:

data = Leaderboard.objects.filter(id=custom_user.id).values(
    'value1',
    'value2',
    'value3')

在模板中:

{% for dictionary in data %}
  {% for key, value in dictionary.items %}
    <p>{{ key }} : {{ value }}</p>
  {% endfor %}
{% endfor %}

This answer didn’t work for me, but I found the answer myself. No one, however, has posted my question. I’m too lazy to ask it and then answer it, so will just put it here.

This is for the following query:

data = Leaderboard.objects.filter(id=custom_user.id).values(
    'value1',
    'value2',
    'value3')

In template:

{% for dictionary in data %}
  {% for key, value in dictionary.items %}
    <p>{{ key }} : {{ value }}</p>
  {% endfor %}
{% endfor %}

回答 2

如果将变量data(字典类型)作为上下文传递给模板,则代码应为:

{% for key, value in data.items %}
    <p>{{ key }} : {{ value }}</p> 
{% endfor %}

If you pass a variable data (dictionary type) as context to a template, then you code should be:

{% for key, value in data.items %}
    <p>{{ key }} : {{ value }}</p> 
{% endfor %}

django更改默认运行服务器端口

问题:django更改默认运行服务器端口

我想在manage.py runserver侦听器中指定可侦听的默认端口config.ini。是否有比sys.argv在内部解析manage.py并插入配置的端口更容易的修复方法?

目标是运行时./manage.py runserver不必每次都指定地址和端口,而要从中获取参数config.ini

I would like to make the default port that manage.py runserver listens on specifiable in an extraneous config.ini. Is there an easier fix than parsing sys.argv inside manage.py and inserting the configured port?

The goal is to run ./manage.py runserver without having to specify address and port every time but having it take the arguments from the config.ini.


回答 0

使用以下命令创建一个bash脚本:

#!/bin/bash
exec ./manage.py runserver 0.0.0.0:<your_port>

将其保存为runserver并与manage.py放在同一目录中

chmod +x runserver

并运行为

./runserver

create a bash script with the following:

#!/bin/bash
exec ./manage.py runserver 0.0.0.0:<your_port>

save it as runserver in the same dir as manage.py

chmod +x runserver

and run it as

./runserver

回答 1

实际上,在开发Django服务器中更改(仅)端口的最简单方法是:

python manage.py runserver 7000

应该在http://127.0.0.1:7000/上运行开发服务器的服务器

Actually the easiest way to change (only) port in development Django server is just like:

python manage.py runserver 7000

that should run development server on http://127.0.0.1:7000/


回答 2

从Django 1.9开始,我发现的最简单的解决方案(基于Quentin Stafford-Fraser的解决方案)是manage.py在调用runserver命令之前添加几行以动态修改默认端口号:

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings.dev")

    import django
    django.setup()

    # Override default port for `runserver` command
    from django.core.management.commands.runserver import Command as runserver
    runserver.default_port = "8080"

    from django.core.management import execute_from_command_line

    execute_from_command_line(sys.argv)

As of Django 1.9, the simplest solution I have found (based on Quentin Stafford-Fraser’s solution) is to add a few lines to manage.py which dynamically modify the default port number before invoking the runserver command:

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings.dev")

    import django
    django.setup()

    # Override default port for `runserver` command
    from django.core.management.commands.runserver import Command as runserver
    runserver.default_port = "8080"

    from django.core.management import execute_from_command_line

    execute_from_command_line(sys.argv)

回答 3

运行django时,以下所有命令都可以更改端口:

python manage.py runserver 127.0.0.1:7000

python manage.py runserver 7000

python manage.py runserver 0:7000

All of the following commands are possible to change the port while running django:

python manage.py runserver 127.0.0.1:7000

python manage.py runserver 7000

python manage.py runserver 0:7000

回答 4

创建的子类django.core.management.commands.runserver.Command并覆盖default_port成员。将文件另存为自己的管理命令,例如<app-name>/management/commands/runserver.py

from django.conf import settings
from django.core.management.commands import runserver

class Command(runserver.Command):
    default_port = settings.RUNSERVER_PORT

我在此处加载默认端口表单设置(依次读取其他配置文件),但是您也可以直接从其他文件中读取它。

Create a subclass of django.core.management.commands.runserver.Command and overwrite the default_port member. Save the file as a management command of your own, e.g. under <app-name>/management/commands/runserver.py:

from django.conf import settings
from django.core.management.commands import runserver

class Command(runserver.Command):
    default_port = settings.RUNSERVER_PORT

I’m loading the default port form settings here (which in turn reads other configuration files), but you could just as well read it from some other file directly.


回答 5

我们创建了一个新的“ runserver”管理命令,该命令是标准包装的薄包装,但更改了默认端口。大致来说,您创建management/commands/runserver.py并放入了以下内容:

# Override the value of the constant coded into django...
import django.core.management.commands.runserver as runserver
runserver.DEFAULT_PORT="8001"

# ...print out a warning...
# (This gets output twice because runserver fires up two threads (one for autoreload).
#  We're living with it for now :-)
import os
dir_path = os.path.splitext(os.path.relpath(__file__))[0]
python_path = dir_path.replace(os.sep, ".")
print "Using %s with default port %s" % (python_path, runserver.DEFAULT_PORT)

# ...and then just import its standard Command class.
# Then manage.py runserver behaves normally in all other regards.
from django.core.management.commands.runserver import Command

We created a new ‘runserver’ management command which is a thin wrapper around the standard one but changes the default port. Roughly, you create management/commands/runserver.py and put in something like this:

# Override the value of the constant coded into django...
import django.core.management.commands.runserver as runserver
runserver.DEFAULT_PORT="8001"

# ...print out a warning...
# (This gets output twice because runserver fires up two threads (one for autoreload).
#  We're living with it for now :-)
import os
dir_path = os.path.splitext(os.path.relpath(__file__))[0]
python_path = dir_path.replace(os.sep, ".")
print "Using %s with default port %s" % (python_path, runserver.DEFAULT_PORT)

# ...and then just import its standard Command class.
# Then manage.py runserver behaves normally in all other regards.
from django.core.management.commands.runserver import Command

回答 6

在Pycharm中,您只需将端口添加到参数中

In Pycharm you can simply add the port to the parameters


回答 7

我在这里参加聚会很晚,但是如果您使用PyCharm这样的IDE,则在“运行”菜单下的“编辑配置”中有一个选项(“运行”>“编辑配置”),您可以在其中指定默认端口。当然,这仅在通过PyCharm进行调试/测试时才有意义。

I’m very late to the party here, but if you use an IDE like PyCharm, there’s an option in ‘Edit Configurations’ under the ‘Run’ menu (Run > Edit Configurations) where you can specify a default port. This of course is relevant only if you are debugging/testing through PyCharm.


回答 8

如果您想更改默认配置,请按照以下步骤操作:

  1. 打开终端类型命令

     $ /usr/local/lib/python<2/3>.x/dist-packages/django/core/management/commands
  2. 现在以超级用户身份在nano编辑器中打开runserver.py文件

     $ sudo nano runserver.py
  3. 找到“ default_port”变量,您将看到默认端口号为“ 8000”。现在,您可以将其更改为所需的任何内容。

  4. 现在退出并使用“ CTRL + X和Y保存文件”保存文件

注意:将<2/3> .x替换为可用的python版本

If you wish to change the default configurations then follow this steps:

  1. Open terminal type command

     $ /usr/local/lib/python<2/3>.x/dist-packages/django/core/management/commands
    
  2. Now open runserver.py file in nano editor as superuser

     $ sudo nano runserver.py
    
  3. find the ‘default_port’ variable then you will see the default port no is ‘8000’. Now you can change it to whatever you want.

  4. Now exit and save the file using “CTRL + X and Y to save the file”

Note: Replace <2/3>.x with your usable version of python


回答 9

  1. 在您的.bashrc中创建环境变量

    导出RUNSERVER_PORT = 8010

  2. 建立别名

    别名runserver =’django-admin runserver $ RUNSERVER_PORT’

我正在使用zsh和virtualenvs包装器。我将导出放入项目的postactivate脚本中,并为每个项目分配端口。

workon someproject
runserver
  1. Create enviroment variable in your .bashrc

    export RUNSERVER_PORT=8010

  2. Create alias

    alias runserver=’django-admin runserver $RUNSERVER_PORT’

Im using zsh and virtualenvs wrapper. I put export in projects postactivate script and asign port for every project.

workon someproject
runserver

回答 10

这是旧文章,但对那些感兴趣的人来说:

如果要更改默认端口号,以便在运行“ runserver”命令时从首选端口开始,请执行以下操作:

  1. 找到您的python安装。(您可以安装多个python,也可以安装虚拟环境版本,因此请确保找到正确的版本)
  2. 在python文件夹内找到site-packages文件夹。在其中,您将找到django安装
  3. 打开django文件夹->核心->管理->命令
  4. 在命令文件夹内,使用文本编辑器打开runserver.py脚本
  5. 找到DEFAULT_PORT字段。默认情况下等于8000。更改为您喜欢的任何内容 DEFAULT_PORT = "8080"
  6. 重新启动服务器:python manage.py runserver并查看它是否使用了您设置的端口号

它适用于python 2.7,但也应适用于新版本的python。祝好运

This is an old post but for those who are interested:

If you want to change the default port number so when you run the “runserver” command you start with your preferred port do this:

  1. Find your python installation. (you can have multiple pythons installed and you can have your virtual environment version as well so make sure you find the right one)
  2. Inside the python folder locate the site-packages folder. Inside that you will find your django installation
  3. Open the django folder-> core -> management -> commands
  4. Inside the commands folder open up the runserver.py script with a text editor
  5. Find the DEFAULT_PORT field. it is equal to 8000 by default. Change it to whatever you like DEFAULT_PORT = "8080"
  6. Restart your server: python manage.py runserver and see that it uses your set port number

It works with python 2.7 but it should work with newer versions of python as well. Good luck


回答 11

我在同一个问题上挣扎,找到了一个解决方案。我想它可以帮助您。运行时python manage.py runserver,它将在默认ip地址中使用127.0.0.1,在python环境中配置默认​​端口8000。在您的python设置中,转到<your python env>\Lib\site-packages\django\core\management\commands\runserver.py并设置1。2 default_port = '<your_port>'
.在def handle下找到并设置
if not options.get('addrport'): self.addr = '0.0.0.0' self.port = self.default_port

现在,如果您运行“ python manage.py runserver”,则它将默认在“ 0.0.0.0”上运行:

享受编码…..

I was struggling with the same problem and found one solution. I guess it can help you. when you run python manage.py runserver, it will take 127.0.0.1 as default ip address and 8000 as default port number which can be configured in your python environment. In your python setting, go to <your python env>\Lib\site-packages\django\core\management\commands\runserver.py and set 1. default_port = '<your_port>'
2. find this under def handle and set
if not options.get('addrport'): self.addr = '0.0.0.0' self.port = self.default_port

Now if you run “python manage.py runserver” it will run by default on “0.0.0.0:

Enjoy coding …..


Django:如何管理开发和生产设置?

问题:Django:如何管理开发和生产设置?

我一直在开发一个基本的应用程序。现在在部署阶段,很明显,我需要本地设置和生产设置。

很高兴知道以下内容:

  • 如何最好地处理开发和生产设置。
  • 如何仅在开发环境中保留django-debug-toolbar之类的应用程序。
  • 开发和部署设置的其他任何技巧和最佳做法。

I have been developing a basic app. Now at the deployment stage it has become clear I have need for both a local settings and production settings.

It would be great to know the following:

  • How best to deal with development and production settings.
  • How to keep apps such as django-debug-toolbar only in a development environment.
  • Any other tips and best practices for development and deployment settings.

回答 0

DJANGO_SETTINGS_MODULE环境变量,其设置文件Django的控件将加载。

因此,您可以为各自的环境创建单独的配置文件(请注意,它们当然可以import *来自单独的“共享设置”文件),并用于DJANGO_SETTINGS_MODULE控制使用哪个文件。

这是如何做:

如Django文档中所述:

DJANGO_SETTINGS_MODULE的值应采用Python路径语法,例如mysite.settings。请注意,设置模块应位于Python导入搜索路径上。

所以,让我们假设你创建myapp/production_settings.pymyapp/test_settings.py在源存储库。

在这种情况下,您将分别设置DJANGO_SETTINGS_MODULE=myapp.production_settings使用前者和DJANGO_SETTINGS_MODULE=myapp.test_settings后者。


从现在开始,问题归结为设置DJANGO_SETTINGS_MODULE环境变量。

设置DJANGO_SETTINGS_MODULE使用脚本或shell

然后,您可以使用引导脚本或流程管理器来加载正确的设置(通过设置环境),或者仅在启动Django:之前从您的Shell中运行它export DJANGO_SETTINGS_MODULE=myapp.production_settings

请注意,您可以随时从Shell运行此导出-它不需要存在于您的.bashrc容器中。

DJANGO_SETTINGS_MODULE使用流程管理器进行设置

如果您不喜欢编写用于设置环境的引导脚本(并且有很好的理由!),我建议您使用流程管理器:


最后,请注意,您可以利用PYTHONPATH变量将设置存储在完全不同的位置(例如,在生产服务器上,将其存储在中/etc/)。这允许将配置与应用程序文件分开。您可能想要或不想要它,这取决于您的应用程序的结构。

The DJANGO_SETTINGS_MODULE environment variable controls which settings file Django will load.

You therefore create separate configuration files for your respective environments (note that they can of course both import * from a separate, “shared settings” file), and use DJANGO_SETTINGS_MODULE to control which one to use.

Here’s how:

As noted in the Django documentation:

The value of DJANGO_SETTINGS_MODULE should be in Python path syntax, e.g. mysite.settings. Note that the settings module should be on the Python import search path.

So, let’s assume you created myapp/production_settings.py and myapp/test_settings.py in your source repository.

In that case, you’d respectively set DJANGO_SETTINGS_MODULE=myapp.production_settings to use the former and DJANGO_SETTINGS_MODULE=myapp.test_settings to use the latter.


From here on out, the problem boils down to setting the DJANGO_SETTINGS_MODULE environment variable.

Setting DJANGO_SETTINGS_MODULE using a script or a shell

You can then use a bootstrap script or a process manager to load the correct settings (by setting the environment), or just run it from your shell before starting Django: export DJANGO_SETTINGS_MODULE=myapp.production_settings.

Note that you can run this export at any time from a shell — it does not need to live in your .bashrc or anything.

Setting DJANGO_SETTINGS_MODULE using a Process Manager

If you’re not fond of writing a bootstrap script that sets the environment (and there are very good reasons to feel that way!), I would recommend using a process manager:


Finally, note that you can take advantage of the PYTHONPATH variable to store the settings in a completely different location (e.g. on a production server, storing them in /etc/). This allows for separating configuration from application files. You may or may not want that, it depends on how your app is structured.


回答 1

默认情况下,使用生产设置,但settings_dev.py在与文件相同的文件夹中创建一个名为的settings.py文件。在此处添加替代,例如DEBUG=True

在将用于开发的计算机上,将此添加到您的~/.bashrc文件中:

export DJANGO_DEVELOPMENT=true

settings.py文件底部,添加以下内容。

# Override production variables if DJANGO_DEVELOPMENT env variable is set
if os.environ.get('DJANGO_DEVELOPMENT'):
    from settings_dev import *  # or specific overrides

(请注意,*通常应避免在Python 中导入)

默认情况下,生产服务器将不覆盖任何内容。做完了!

与其他答案相比,该答案更简单,因为它不需要更新PYTHONPATH或设置DJANGO_SETTINGS_MODULE,而每次只允许您处理一个django项目。

By default use production settings, but create a file called settings_dev.py in the same folder as your settings.py file. Add overrides there, such as DEBUG=True.

On the computer that will be used for development, add this to your ~/.bashrc file:

export DJANGO_DEVELOPMENT=true

At the bottom of your settings.py file, add the following.

# Override production variables if DJANGO_DEVELOPMENT env variable is set
if os.environ.get('DJANGO_DEVELOPMENT'):
    from settings_dev import *  # or specific overrides

(Note that importing * should generally be avoided in Python)

By default the production servers will not override anything. Done!

Compared to the other answers, this one is simpler because it doesn’t require updating PYTHONPATH, or setting DJANGO_SETTINGS_MODULE which only allows you to work on one django project at a time.


回答 2

通常每个环境有一个设置文件,还有一个共享设置文件:

/myproject/
  settings.production.py
  settings.development.py
  shared_settings.py

我的每个环境文件都有:

try:
    from shared_settings import *
except ImportError:
    pass

这使我可以在必要时覆盖共享设置(通过在该节下面添加修改)。

然后,通过将其链接到settings.py来选择要使用的设置文件:

ln -s settings.development.py settings.py

I usually have one settings file per environment, and a shared settings file:

/myproject/
  settings.production.py
  settings.development.py
  shared_settings.py

Each of my environment files has:

try:
    from shared_settings import *
except ImportError:
    pass

This allows me to override shared settings if necessary (by adding the modifications below that stanza).

I then select which settings files to use by linking it in to settings.py:

ln -s settings.development.py settings.py

回答 3

这是我通过6个简单步骤完成的操作:

  1. 在项目目录中创建一个文件夹,并将其命名settings

    项目结构:

    myproject/
           myapp1/
           myapp2/              
           myproject/
                  settings/
  2. 创建内部4个Python文件settings目录,即__init__.pybase.pydev.pyprod.py

    设置文件:

    settings/
         __init__.py
         base.py
         prod.py
         dev.py 
  3. 打开__init__.py并填写以下内容:

    初始化 .py:

    from .base import *
    # you need to set "myproject = 'prod'" as an environment variable
    # in your OS (on which your website is hosted)
    if os.environ['myproject'] == 'prod':
       from .prod import *
    else:
       from .dev import *
  4. 打开base.py并填写所有常用设置(将在生产和开发中使用)。例如:

    base.py:

    import os
    ...
    INSTALLED_APPS = [...]
    MIDDLEWARE = [...]
    TEMPLATES = [{...}]
    ...
    STATIC_URL = '/static/'
    STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
    MEDIA_ROOT = os.path.join(BASE_DIR, '/path/')
    MEDIA_URL = '/path/'
  5. 打开dev.py并包含特定于开发的内容,例如:

    dev.py:

    DEBUG = True
    ALLOWED_HOSTS = ['localhost']
    ...
  6. 打开prod.py并包含特定于生产的内容,例如:

    prod.py:

    DEBUG = False
    ALLOWED_HOSTS = ['www.example.com']
    LOGGING = [...]
    ...

This is how I do it in 6 easy steps:

  1. Create a folder inside your project directory and name it settings.

    Project structure:

    myproject/
           myapp1/
           myapp2/              
           myproject/
                  settings/
    
  2. Create four python files inside of the settings directory namely __init__.py, base.py, dev.py and prod.py

    Settings files:

    settings/
         __init__.py
         base.py
         prod.py
         dev.py 
    
  3. Open __init__.py and fill it with the following content:

    init.py:

    from .base import *
    # you need to set "myproject = 'prod'" as an environment variable
    # in your OS (on which your website is hosted)
    if os.environ['myproject'] == 'prod':
       from .prod import *
    else:
       from .dev import *
    
  4. Open base.py and fill it with all the common settings (that will be used in both production as well as development.) for example:

    base.py:

    import os
    ...
    INSTALLED_APPS = [...]
    MIDDLEWARE = [...]
    TEMPLATES = [{...}]
    ...
    STATIC_URL = '/static/'
    STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
    MEDIA_ROOT = os.path.join(BASE_DIR, '/path/')
    MEDIA_URL = '/path/'
    
  5. Open dev.py and include that stuff which is development specific for example:

    dev.py:

    DEBUG = True
    ALLOWED_HOSTS = ['localhost']
    ...
    
  6. Open prod.py and include that stuff which is production specific for example:

    prod.py:

    DEBUG = False
    ALLOWED_HOSTS = ['www.example.com']
    LOGGING = [...]
    ...
    

回答 4

创建多个settings*.py文件,推断出每个环境需要更改的变量。然后在主settings.py文件的末尾:

try:
  from settings_dev import *
except ImportError:
  pass

settings_*为每个阶段保留单独的文件。

settings_dev.py文件顶部,添加以下内容:

import sys
globals().update(vars(sys.modules['settings']))

导入需要修改的变量。

Wiki条目提供有关如何拆分设置的更多想法。

Create multiple settings*.py files, extrapolating the variables that need to change per environment. Then at the end of your master settings.py file:

try:
  from settings_dev import *
except ImportError:
  pass

You keep the separate settings_* files for each stage.

At the top of your settings_dev.py file, add this:

import sys
globals().update(vars(sys.modules['settings']))

To import variables that you need to modify.

This wiki entry has more ideas on how to split your settings.


回答 5

我使用了很棒的django-configuration,所有设置都存储在我的计算机中settings.py

from configurations import Configuration

class Base(Configuration):
    # all the base settings here...
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    ...

class Develop(Base):
    # development settings here...
    DEBUG = True 
    ...

class Production(Base):
    # production settings here...
    DEBUG = False

要配置Django项目,我只需遵循docs即可

I use the awesome django-configurations, and all the settings are stored in my settings.py:

from configurations import Configuration

class Base(Configuration):
    # all the base settings here...
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    ...

class Develop(Base):
    # development settings here...
    DEBUG = True 
    ...

class Production(Base):
    # production settings here...
    DEBUG = False

To configure the Django project I just followed the docs.


回答 6

这是我们使用的方法:

  • 一个settings将设置分成多个文件以增强可读性的模块;
  • 一个.env.json文件,用于存储我们要从git存储库中排除或特定于环境的凭据和参数;
  • 一个env.py文件来读取.env.json文件

考虑以下结构:

...
.env.json           # the file containing all specific credentials and parameters
.gitignore          # the .gitignore file to exclude `.env.json`
project_name/       # project dir (the one which django-admin.py creates)
  accounts/         # project's apps
    __init__.py
    ...
  ...
  env.py            # the file to load credentials
  settings/
    __init__.py     # main settings file
    database.py     # database conf
    storage.py      # storage conf
    ...
venv                # virtualenv
...

.env.json喜欢:

{
    "debug": false,
    "allowed_hosts": ["mydomain.com"],
    "django_secret_key": "my_very_long_secret_key",
    "db_password": "my_db_password",
    "db_name": "my_db_name",
    "db_user": "my_db_user",
    "db_host": "my_db_host",
}

project_name/env.py

<!-- language: lang-python -->
import json
import os


def get_credentials():
    env_file_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    with open(os.path.join(env_file_dir, '.env.json'), 'r') as f:
        creds = json.loads(f.read())
    return creds


credentials = get_credentials()

我们可以进行以下设置:

<!-- language: lang-py -->
# project_name/settings/__init__.py
from project_name.env import credentials
from project_name.settings.database import *
from project_name.settings.storage import *
...

SECRET_KEY = credentials.get('django_secret_key')

DEBUG = credentials.get('debug')

ALLOWED_HOSTS = credentials.get('allowed_hosts', [])

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    ...
]

if DEBUG:
    INSTALLED_APPS += ['debug_toolbar']

...

# project_name/settings/database.py
from project_name.env import credentials

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': credentials.get('db_name', ''),
        'USER': credentials.get('db_user', ''),
        'HOST': credentials.get('db_host', ''),
        'PASSWORD': credentials.get('db_password', ''),
        'PORT': '5432',
    }
}

该解决方案的好处是:

  • 用于本地开发的用户专用凭证和配置,而无需修改git存储库;
  • 针对特定环境的配置,例如,您可以具有三个不同的环境,其中具有三个不同的环境,.env.json例如dev,stagging和production;
  • 凭证不在存储库中

希望对您有所帮助,请告诉我您是否对此解决方案有所了解。

Here is the approach we use :

  • a settings module to split settings into multiple files for readability ;
  • a .env.json file to store credentials and parameters that we want excluded from our git repository, or that are environment specific ;
  • an env.py file to read the .env.json file

Considering the following structure :

...
.env.json           # the file containing all specific credentials and parameters
.gitignore          # the .gitignore file to exclude `.env.json`
project_name/       # project dir (the one which django-admin.py creates)
  accounts/         # project's apps
    __init__.py
    ...
  ...
  env.py            # the file to load credentials
  settings/
    __init__.py     # main settings file
    database.py     # database conf
    storage.py      # storage conf
    ...
venv                # virtualenv
...

With .env.json like :

{
    "debug": false,
    "allowed_hosts": ["mydomain.com"],
    "django_secret_key": "my_very_long_secret_key",
    "db_password": "my_db_password",
    "db_name": "my_db_name",
    "db_user": "my_db_user",
    "db_host": "my_db_host",
}

And project_name/env.py :

<!-- language: lang-python -->
import json
import os


def get_credentials():
    env_file_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    with open(os.path.join(env_file_dir, '.env.json'), 'r') as f:
        creds = json.loads(f.read())
    return creds


credentials = get_credentials()

We can have the following settings:

<!-- language: lang-py -->
# project_name/settings/__init__.py
from project_name.env import credentials
from project_name.settings.database import *
from project_name.settings.storage import *
...

SECRET_KEY = credentials.get('django_secret_key')

DEBUG = credentials.get('debug')

ALLOWED_HOSTS = credentials.get('allowed_hosts', [])

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    ...
]

if DEBUG:
    INSTALLED_APPS += ['debug_toolbar']

...

# project_name/settings/database.py
from project_name.env import credentials

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': credentials.get('db_name', ''),
        'USER': credentials.get('db_user', ''),
        'HOST': credentials.get('db_host', ''),
        'PASSWORD': credentials.get('db_password', ''),
        'PORT': '5432',
    }
}

the benefits of this solution are :

  • user specific credentials and configurations for local development without modifying the git repository ;
  • environment specific configuration, you can have for example three different environments with three different .env.json like dev, stagging and production ;
  • credentials are not in the repository

I hope this helps, just let me know if you see any caveats with this solution.


回答 7

我使用以下文件结构:

project/
   ...
   settings/
   settings/common.py
   settings/local.py
   settings/prod.py
   settings/__init__.py -> local.py

所以,__init__.py是(在Windows LN在UNIX或mklink)的链接,local.py或者可以是prod.py这样的配置仍然是在project.settings模块清洁和有组织的,如果你想使用一个特定的配置,你可以使用环境变量DJANGO_SETTINGS_MODULEproject.settings.prod,如果你需要在生产环境中运行命令。

在文件prod.pylocal.py

from .shared import *

DATABASE = {
    ...
}

并且该shared.py文件在没有特定配置的情况下保持全局状态。

I use the folloring file structure:

project/
   ...
   settings/
   settings/common.py
   settings/local.py
   settings/prod.py
   settings/__init__.py -> local.py

So __init__.py is a link (ln in unix or mklink in windows) to local.py or can be to prod.py so the configuration is still in the project.settings module is clean and organized, and if you want to use a particular config you can use the environment variable DJANGO_SETTINGS_MODULE to project.settings.prod if you need to run a command for production environment.

In the files prod.py and local.py:

from .shared import *

DATABASE = {
    ...
}

and the shared.py file keeps as global without specific configs.


回答 8

建立CS01的答案:

如果您在使用环境变量时遇到问题,请将其值设置为字符串(例如,我做了DJANGO_DEVELOPMENT="true")。

我还更改了cs01的文件工作流程,如下所示:

#settings.py
import os
if os.environ.get('DJANGO_DEVELOPMENT') is not None:
    from settings_dev import * 
else:
    from settings_production import *
#settings_dev.py
development settings go here
#settings_production.py
production settings go here

这样,Django无需在运行适当的设置文件之前通读整个设置文件。如果您的生产文件仅需要生产服务器上的内容,则此解决方案非常有用。

注意:在Python 3中,导入的文件需要.附加一个附件(例如from .settings_dev import *

building off cs01’s answer:

if you’re having problems with the environment variable, set its value to a string (e.g. I did DJANGO_DEVELOPMENT="true").

I also changed cs01’s file workflow as follows:

#settings.py
import os
if os.environ.get('DJANGO_DEVELOPMENT') is not None:
    from settings_dev import * 
else:
    from settings_production import *
#settings_dev.py
development settings go here
#settings_production.py
production settings go here

This way, Django doesn’t have to read through the entirety of a settings file before running the appropriate settings file. This solution comes in handy if your production file needs stuff that’s only on your production server.

Note: in Python 3, imported files need to have a . appended (e.g. from .settings_dev import *)


回答 9

如果要保留1个设置文件,并且您的开发操作系统与生产操作系统不同,则可以将其放在settings.py的底部:

from sys import platform
if platform == "linux" or platform == "linux2":
    # linux
    # some special setting here for when I'm on my prod server
elif platform == "darwin":
    # OS X
    # some special setting here for when I'm developing on my mac
elif platform == "win32":
    # Windows...
    # some special setting here for when I'm developing on my pc

阅读更多:如何检查Python中的操作系统?

If you want to keep 1 settings file, and your development operating system is different than your production operating system, you can put this at the bottom of your settings.py:

from sys import platform
if platform == "linux" or platform == "linux2":
    # linux
    # some special setting here for when I'm on my prod server
elif platform == "darwin":
    # OS X
    # some special setting here for when I'm developing on my mac
elif platform == "win32":
    # Windows...
    # some special setting here for when I'm developing on my pc

Read more: How do I check the operating system in Python?


回答 10

这似乎已经得到了回答,但是我将其与版本控制结合使用的方法如下:

在与我也添加到.gitignore的本地开发环境上的设置相同的目录中设置一个env.py文件:

env.py:

#!usr/bin/python

DJANGO_ENV = True
ALLOWED_HOSTS = ['127.0.0.1', 'dev.mywebsite.com']

.gitignore:

mywebsite/env.py

settings.py:

if os.path.exists(os.getcwd() + '/env.py'):
    #env.py is excluded using the .gitignore file - when moving to production we can automatically set debug mode to off:
    from env import *
else:
    DJANGO_ENV = False

DEBUG = DJANGO_ENV

我只是发现它有效并且更加优雅-使用env.py可以很容易地看到我们的本地环境变量,并且我们可以在没有多个settings.py文件或类似文件的情况下处理所有这些问题。这种方法允许使用各种我们不想在生产服务器上设置的局部环境变量。通过版本控制使用.gitignore,我们还保持所有内容无缝集成。

This seems to have been answered, however a method which I use as combined with version control is the following:

Setup a env.py file in the same directory as settings on my local development environment that I also add to .gitignore:

env.py:

#!usr/bin/python

DJANGO_ENV = True
ALLOWED_HOSTS = ['127.0.0.1', 'dev.mywebsite.com']

.gitignore:

mywebsite/env.py

settings.py:

if os.path.exists(os.getcwd() + '/env.py'):
    #env.py is excluded using the .gitignore file - when moving to production we can automatically set debug mode to off:
    from env import *
else:
    DJANGO_ENV = False

DEBUG = DJANGO_ENV

I just find this works and is far more elegant – with env.py it is easy to see our local environment variables and we can handle all of this without multiple settings.py files or the likes. This methods allows for all sorts of local environment variables to be used that we wouldn’t want set on our production server. Utilising the .gitignore via version control we are also keeping everything seamlessly integrated.


回答 11

使用settings.py进行生产。在同一目录中创建settings_dev.py替代。

# settings_dev.py

from .settings import * 

DEBUG = False

在开发机器上,使用以下命令运行Django应用:

DJANGO_SETTINGS_MODULE=<your_app_name>.settings_dev python3 manage.py runserver

在生产机器上运行,就好像您只是拥有settings.py而已。

优点

  1. settings.py (用于生产)完全不知道存在任何其他环境。
  2. 要查看prod和dev之间的区别,您只需查看一个位置- settings_dev.py。无需配置收集散落settings_prod.pysettings_dev.pysettings_shared.py
  3. 如果在解决生产问题后有人将设置添加到您的产品配置中,您可以放心,该设置也会出现在您的开发配置中(除非被显式覆盖)。因此,不同配置文件之间的差异将被最小化。

Use settings.py for production. In the same directory create settings_dev.py for overrides.

# settings_dev.py

from .settings import * 

DEBUG = False

On a dev machine run your Django app with:

DJANGO_SETTINGS_MODULE=<your_app_name>.settings_dev python3 manage.py runserver

On a prod machine run as if you just had settings.py and nothing else.

ADVANTAGES

  1. settings.py (used for production) is completely agnostic to the fact that any other environments even exist.
  2. To see the difference between prod and dev you just look into a single location – settings_dev.py. No need to gather configurations scattered across settings_prod.py, settings_dev.py and settings_shared.py.
  3. If someone adds a setting to your prod config after troubleshooting a production issue you can rest assured that it will appear in your dev config as well (unless explicitly overridden). Thus the divergence between different config files will be minimized.

回答 12

对于设置文件的问题,我选择复制

Project
   |---__init__.py   [ write code to copy setting file from subdir to current dir]
   |---settings.py  (do not commit this file to git)
   |---setting1_dir
   |         |--  settings.py
   |---setting2_dir
   |         |--  settings.py

当您运行django时,将运行__init__py。这时,settings.py in setting1_dir将更换settings.py in Project

如何选择不同的环境?

  • __init__.py直接修改。
  • 制作一个bash文件进行修改__init__.py
  • 在linux中修改env,然后__init__.py读取此变量。

为什么要用这种方式?

因为我不喜欢同一目录中的太多文件,所以太多的文件会使其他合作伙伴感到困惑,并且对于IDE来说不是很好(IDE无法找到我们使用的文件)

如果您不想看到所有这些详细信息,可以将项目分为两部分。

  1. 制作像Spring Initializr这样的小工具,仅用于设置您的项目。(像复制文件一样)
  2. 您的项目代码

For the problem of setting files, I choose to copy

Project
   |---__init__.py   [ write code to copy setting file from subdir to current dir]
   |---settings.py  (do not commit this file to git)
   |---setting1_dir
   |         |--  settings.py
   |---setting2_dir
   |         |--  settings.py

When you run django, __init__py will be ran. At this time , settings.py in setting1_dir will replace settings.py in Project.

How to choose different env?

  • modify __init__.py directly.
  • make a bash file to modify __init__.py.
  • modify env in linux, and then let __init__.py read this variable.

Why use to this way?

Because I don’t like so many files in the same directory, too many files will confuse other partners and not very well for IDE.(IDE cannot find what file we use)

If you do not want to see all these details, you can divide project into two part.

  1. make your small tool like Spring Initializr, just for setup your project.(do sth like copy file)
  2. your project code

回答 13

我正在使用不同的app.yaml文件来更改Google Cloud App Engine中环境之间的配置。

您可以使用此命令在终端命令中创建代理连接:

./cloud_sql_proxy -instances=<INSTANCE_CONNECTION_NAME>=tcp:1433

https://cloud.google.com/sql/docs/sqlserver/connect-admin-proxy#macos-64-bit

档案:app.yaml

# [START django_app]
service: development
runtime: python37

env_variables:
  DJANGO_DB_HOST: '/cloudsql/myproject:myregion:myinstance'
  DJANGO_DEBUG: True

handlers:
# This configures Google App Engine to serve the files in the app's static
# directory.
- url: /static
  static_dir: static/

# This handler routes all requests not caught above to your main app. It is
# required when static routes are defined, but can be omitted (along with
# the entire handlers section) when there are no static files defined.
- url: /.*
  script: auto
# [END django_app]

I’m using different app.yaml file to change configuration between environments in google cloud app engine.

You can use this to create a proxy connection in your terminal command:

./cloud_sql_proxy -instances=<INSTANCE_CONNECTION_NAME>=tcp:1433

https://cloud.google.com/sql/docs/sqlserver/connect-admin-proxy#macos-64-bit

File: app.yaml

# [START django_app]
service: development
runtime: python37

env_variables:
  DJANGO_DB_HOST: '/cloudsql/myproject:myregion:myinstance'
  DJANGO_DEBUG: True

handlers:
# This configures Google App Engine to serve the files in the app's static
# directory.
- url: /static
  static_dir: static/

# This handler routes all requests not caught above to your main app. It is
# required when static routes are defined, but can be omitted (along with
# the entire handlers section) when there are no static files defined.
- url: /.*
  script: auto
# [END django_app]

回答 14

这是我的解决方案,具有不同的开发,测试和生产环境

import socket

[...]

DEV_PC = 'PC059'
host_name = socket.gethostname()

if host_name == DEV_PC:
   #do something
   pass
elif [...]

This is my solution, with different environements for dev, test and prod

import socket

[...]

DEV_PC = 'PC059'
host_name = socket.gethostname()

if host_name == DEV_PC:
   #do something
   pass
elif [...]