标签归档:Django

Django DB设置“配置不正确”错误

问题:Django DB设置“配置不正确”错误

Django(1.5)对我来说很好用,但是当我启动Python解释器(Python 3)进行检查时,尝试导入时会遇到最奇怪的错误from django.contrib.auth.models import User

Traceback (most recent call last):
  File "/usr/local/lib/python3.2/dist-packages/django/conf/__init__.py", line 36, in _setup
    settings_module = os.environ[ENVIRONMENT_VARIABLE]
  File "/usr/lib/python3.2/os.py", line 450, in __getitem__
    value = self._data[self.encodekey(key)]
KeyError: b'DJANGO_SETTINGS_MODULE'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.2/dist-packages/django/contrib/auth/models.py", line 8, in <module>
    from django.db import models
  File "/usr/local/lib/python3.2/dist-packages/django/db/__init__.py", line 11, in <module>
    if settings.DATABASES and DEFAULT_DB_ALIAS not in settings.DATABASES:
  File "/usr/local/lib/python3.2/dist-packages/django/conf/__init__.py", line 52, in __getattr__
    self._setup(name)
  File "/usr/local/lib/python3.2/dist-packages/django/conf/__init__.py", line 45, in _setup
    % (desc, ENVIRONMENT_VARIABLE))

django.core.exceptions.ImproperlyConfigured: Requested setting DATABASES, 
  but settings are not configured. You must either define the environment 
  variable DJANGO_SETTINGS_MODULE or call settings.configure() 
  before accessing settings.

当它在Python解释器之外可以正常工作时,如何对其进行不正确的配置?在我的Django设置中,DATABASES设置为:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'django_db', # Or path to database file if using sqlite3.
        # The following settings are not used with sqlite3:
        'USER': 'zamphatta',
        'PASSWORD': 'mypassword91',
        'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP.
        'PORT': '', # Set to empty string for default.
    }
}

…这是如何配置不正确的?

Django (1.5) is workin’ fine for me, but when I fire up the Python interpreter (Python 3) to check some things, I get the weirdest error when I try importing – from django.contrib.auth.models import User

Traceback (most recent call last):
  File "/usr/local/lib/python3.2/dist-packages/django/conf/__init__.py", line 36, in _setup
    settings_module = os.environ[ENVIRONMENT_VARIABLE]
  File "/usr/lib/python3.2/os.py", line 450, in __getitem__
    value = self._data[self.encodekey(key)]
KeyError: b'DJANGO_SETTINGS_MODULE'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.2/dist-packages/django/contrib/auth/models.py", line 8, in <module>
    from django.db import models
  File "/usr/local/lib/python3.2/dist-packages/django/db/__init__.py", line 11, in <module>
    if settings.DATABASES and DEFAULT_DB_ALIAS not in settings.DATABASES:
  File "/usr/local/lib/python3.2/dist-packages/django/conf/__init__.py", line 52, in __getattr__
    self._setup(name)
  File "/usr/local/lib/python3.2/dist-packages/django/conf/__init__.py", line 45, in _setup
    % (desc, ENVIRONMENT_VARIABLE))

django.core.exceptions.ImproperlyConfigured: Requested setting DATABASES, 
  but settings are not configured. You must either define the environment 
  variable DJANGO_SETTINGS_MODULE or call settings.configure() 
  before accessing settings.

How could it be improperly configured, when it works fine outside the Python interpreter? In my Django settings, the DATABASES settings are:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'django_db', # Or path to database file if using sqlite3.
        # The following settings are not used with sqlite3:
        'USER': 'zamphatta',
        'PASSWORD': 'mypassword91',
        'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP.
        'PORT': '', # Set to empty string for default.
    }
}

…how is this improperly configured?


回答 0

您不能只启动Python并检查内容,Django不知道您要处理哪个项目。您必须执行以下操作之一:

  • python manage.py shell
  • 使用django-admin.py shell --settings=mysite.settings(或您使用的任何设置模块)
  • DJANGO_SETTINGS_MODULE操作系统中的环境变量设置为mysite.settings
  • (在Django 1.6中已删除)setup_environ在python解释器中使用:

    from django.core.management import setup_environ
    from mysite import settings
    
    setup_environ(settings)
    

自然,第一种方法是最简单的。

You can’t just fire up Python and check things, Django doesn’t know what project you want to work on. You have to do one of these things:

  • Use python manage.py shell
  • Use django-admin.py shell --settings=mysite.settings (or whatever settings module you use)
  • Set DJANGO_SETTINGS_MODULE environment variable in your OS to mysite.settings
  • (This is removed in Django 1.6) Use setup_environ in the python interpreter:

    from django.core.management import setup_environ
    from mysite import settings
    
    setup_environ(settings)
    

Naturally, the first way is the easiest.


回答 1

在您的python shell / ipython中执行以下操作:

from django.conf import settings

settings.configure()

In your python shell/ipython do:

from django.conf import settings

settings.configure()

回答 2

在2017年使用django 1.11.5和python 3.6(从注释中也可以使用python 2.7):

import django
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
django.setup()

.py其中你把这个代码应该是在mysite(父之一)

In 2017 with django 1.11.5 and python 3.6 (from the comment this also works with Python 2.7):

import django
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
django.setup()

The .py in which you put this code should be in mysite (the parent one)


回答 3

在Django 1.9上,我尝试django-admin runserver并得到了相同的错误,但是当我使用时python manage.py runserver,得到了预期的结果。这可能会解决很多人的这个错误!

On Django 1.9, I tried django-admin runserver and got the same error, but when I used python manage.py runserver I got the intended result. This may solve this error for a lot of people!


回答 4

就我而言,尝试通过PyCharm运行Django测试时遇到了这个问题。我认为这是因为PyCharm不会加载初始Django项目设置,即manage.py shell最初运行的设置。可以将它们添加到测试脚本的开头,也可以使用来运行测试manage.py test

版本:

  • Python 3.5(在virtualenv中)
  • PyCharm 2016.3.2专业版
  • Django 1.10

In my case, I got this when trying to run Django tests through PyCharm. I think it is because PyCharm does not load the initial Django project settings, i.e. those that manage.py shell runs initially. One can add them to the start of the testing script or just run the tests using manage.py test.

Versions:

  • Python 3.5 (in virtualenv)
  • PyCharm 2016.3.2 Professional
  • Django 1.10

回答 5

就我自己而言,在python2.7.11上运行的django 1.10.1中,我试图使用django-admin runserver而不是manage.py runserver在我的项目目录中启动服务器。

in my own case in django 1.10.1 running on python2.7.11, I was trying to start the server using django-admin runserver instead of manage.py runserver in my project directory.


回答 6

对于使用IntelliJ的人,通过这些设置,我可以从外壳程序(在Windows上)进行查询。

For people using IntelliJ, with these settings I was able to query from the shell (on windows).


如何在Django中设置时区?

问题:如何在Django中设置时区?

在我的django项目的settings.py文件中,我有这行:

TIME_ZONE = 'UTC'

但是我希望我的应用程序在UTC + 2时区运行,所以我将其更改为

TIME_ZONE = 'UTC+2'

它给出了错误ValueError: Incorrect timezone setting: UTC+2。正确的做法是什么?

谢谢!

In my django project’s settings.py file, I have this line :

TIME_ZONE = 'UTC'

But I want my app to run in UTC+2 timezone, so I changed it to

TIME_ZONE = 'UTC+2'

It gives the error ValueError: Incorrect timezone setting: UTC+2. What is the correct way of doing this?

Thanks!


回答 0

以下是有效时区的列表:

http://en.wikipedia.org/wiki/List_of_tz_database_time_zones

您可以使用

TIME_ZONE = 'Europe/Istanbul'

适用于UTC + 02:00

Here is the list of valid timezones:

http://en.wikipedia.org/wiki/List_of_tz_database_time_zones

You can use

TIME_ZONE = 'Europe/Istanbul'

for UTC+02:00


回答 1

要从tz数据库获取一组所有有效的时区名称(id),可以在Python中使用pytzmodule

>>> import pytz # $ pip install pytz
>>> pytz.all_timezones_set
LazySet({'Africa/Abidjan',
         'Africa/Accra',
         'Africa/Addis_Ababa',
         'Africa/Algiers',
         'Africa/Asmara',
         'Africa/Asmera',
         ...
         'UTC',
         'Universal',
         'W-SU',
         'WET',
         'Zulu'})

To get a set of all valid timezone names (ids) from the tz database, you could use pytz module in Python:

>>> import pytz # $ pip install pytz
>>> pytz.all_timezones_set
LazySet({'Africa/Abidjan',
         'Africa/Accra',
         'Africa/Addis_Ababa',
         'Africa/Algiers',
         'Africa/Asmara',
         'Africa/Asmera',
         ...
         'UTC',
         'Universal',
         'W-SU',
         'WET',
         'Zulu'})

回答 2

tzinfo数据库中选择一个有效的时区。他们往往采取的形式如Africa/GaborneUS/Eastern

找到一个与您最近的城市相匹配的城市,或者一个与您的时区相匹配的城市,然后将您的值设置TIME_ZONE为match。

Choose a valid timezone from the tzinfo database. They tend to take the form e.g. Africa/Gaborne and US/Eastern

Find the one which matches the city nearest you, or the one which has your timezone, then set your value of TIME_ZONE to match.


回答 3

有效的timeZone值基于Linux和其他Unix系统使用的tz(时区)数据库。值是形式为“ Area / Location ”的字符串(xsd:string),其中:

区域是大陆或海洋的名称。当前区域包括:

  • 非洲
  • 美国(北美和南美)
  • 南极洲
  • 北极
  • 亚洲
  • 大西洋
  • 澳大利亚
  • 欧洲
  • Etc(行政区域。例如,“ Etc / UTC”代表协调世界时。)
  • 印第安人
  • 太平洋地区

位置是城市,岛屿或其他区域名称。

区域名称和输出缩写遵循POSIX(便携式操作系统接口)UNIX约定,该约定使用格林威治以西的正号(+)和格林威治以东的负号(-),这与通常预期的相反。例如,“ Etc / GMT + 4”对应于UTC(格林威治以西)之后4小时,而不是UTC(格林尼治东部)协调世界时之前4小时。

这是所有有效时区的列表

您可以按以下方式在settings.py中更改时区

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'Asia/Kolkata'

USE_I18N = True

USE_L10N = True

USE_TZ = True

Valid timeZone values are based on the tz (timezone) database used by Linux and other Unix systems. The values are strings (xsd:string) in the form “Area/Location,” in which:

Area is a continent or ocean name. Area currently includes:

  • Africa
  • America (both North America and South America)
  • Antarctica
  • Arctic
  • Asia
  • Atlantic
  • Australia
  • Europe
  • Etc (administrative zone. For example, “Etc/UTC” represents Coordinated Universal Time.)
  • Indian
  • Pacific

Location is the city, island, or other regional name.

The zone names and output abbreviations adhere to POSIX (portable operating system interface) UNIX conventions, which uses positive (+) signs west of Greenwich and negative (-) signs east of Greenwich, which is the opposite of what is generally expected. For example, “Etc/GMT+4” corresponds to 4 hours behind UTC (that is, west of Greenwich) rather than 4 hours ahead of UTC (Coordinated Universal Time) (east of Greenwich).

Here is a list all valid timezones

You can change time zone in your settings.py as follows

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'Asia/Kolkata'

USE_I18N = True

USE_L10N = True

USE_TZ = True

回答 4

我发现了这个问题,希望将Django项目settings.py文件中的时区更改为英国。

在jfs解决方案中使用tz数据库,我找到了答案:

    TIME_ZONE = 'Europe/London'

I found this question looking to change the timezone in my Django project’s settings.py file to the United Kingdom.

Using the tz database in jfs’ solution I found the answer:

    TIME_ZONE = 'Europe/London'

回答 5

  1. 将TIME_ZONE更改为您的本地时区,并在“ setting.py”中将USE_TZ保持为True:

    TIME_ZONE =’亚洲/上海’

    USE_I18N =真

    USE_L10N =真

    USE_TZ =真

  2. 这会将datetime对象作为UTC写入并存储到后端数据库。

  3. 然后,使用template标记将前端模板中的UTC时间转换为:

                <td> 
                    {% load tz %}
                    {% get_current_timezone as tz %}
                    {% timezone tz %}
                        {{ message.log_date | time:'H:i:s' }}
                    {% endtimezone %} 
                </td>

或简洁地使用模板过滤器

                <td> 
                    {% load tz %}
                    {{ message.log_date | localtime | time:'H:i:s' }}
                </td>
  1. 您可以在官方文档中查看更多详细信息:默认时区和当前时区

    启用时区支持后,Django将日期时间信息存储在数据库中的UTC中,在内部使用可识别时区的日期时间对象,并将其以模板和形式转换为最终用户的时区。

  1. Change the TIME_ZONE to your local time zone, and keep USE_TZ as True in ‘setting.py’:

    TIME_ZONE = ‘Asia/Shanghai’

    USE_I18N = True

    USE_L10N = True

    USE_TZ = True

  2. This will write and store the datetime object as UTC to the backend database.

  3. Then use template tag to convert the UTC time in your frontend template as such:

                <td> 
                    {% load tz %}
                    {% get_current_timezone as tz %}
                    {% timezone tz %}
                        {{ message.log_date | time:'H:i:s' }}
                    {% endtimezone %} 
                </td>
    

or use the template filters concisely:

                <td> 
                    {% load tz %}
                    {{ message.log_date | localtime | time:'H:i:s' }}
                </td>
  1. You could check more details in the official doc: Default time zone and current time zone

    When support for time zones is enabled, Django stores datetime information in UTC in the database, uses time-zone-aware datetime objects internally, and translates them to the end user’s time zone in templates and forms.


回答 6

通用解决方案,基于Django的TZ名称支持:

UTC-2 = 'Etc/GMT+2'
UTC-1 = 'Etc/GMT+1'
UTC = 'Etc/GMT+0'
UTC+1 = 'Etc/GMT-1'
UTC+2 = 'Etc/GMT-2'

+/-特意切换。

Universal solution, based on Django’s TZ name support:

UTC-2 = 'Etc/GMT+2'
UTC-1 = 'Etc/GMT+1'
UTC = 'Etc/GMT+0'
UTC+1 = 'Etc/GMT-1'
UTC+2 = 'Etc/GMT-2'

+/- is intentionally switched.


回答 7

  1. 从以下位置下载最新的pytz文件(pytz-2019.3.tar.gz):

    https://pypi.org/simple/pytz/
  2. 复制并将其解压缩到您site_packages项目的目录中

  3. 在cmd中,转到解压缩的文件夹并运行:

    python setup.py install
  4. TIME_ZONE = 'Etc/GMT+2' 或国家名称

  1. download latest pytz file (pytz-2019.3.tar.gz) from:

    https://pypi.org/simple/pytz/
    
  2. copy and extract it to site_packages directory on yor project

  3. in cmd go to the extracted folder and run:

    python setup.py install
    
  4. TIME_ZONE = 'Etc/GMT+2' or country name


将用户添加到Django中的组

问题:将用户添加到Django中的组

如何通过组名将用户添加到django中的组?

我可以做这个:

user.groups.add(1) # add by id

我将如何做这样的事情:

user.groups.add(name='groupname') # add by name

How would I add a user to a group in django by the group’s name?

I can do this:

user.groups.add(1) # add by id

How would I do something like this:

user.groups.add(name='groupname') # add by name

回答 0

使用具有组名称的“组模型”查找组,然后将用户添加到user_set

from django.contrib.auth.models import Group
my_group = Group.objects.get(name='my_group_name') 
my_group.user_set.add(your_user)

Find the group using Group model with the name of the group, then add the user to the user_set

from django.contrib.auth.models import Group
my_group = Group.objects.get(name='my_group_name') 
my_group.user_set.add(your_user)

回答 1

这是在现代版本的Django(在Django 1.7中测试)中如何执行此操作:

from django.contrib.auth.models import Group
group = Group.objects.get(name='groupname')
user.groups.add(group)

Here’s how to do this in modern versions of Django (tested in Django 1.7):

from django.contrib.auth.models import Group
group = Group.objects.get(name='groupname')
user.groups.add(group)

如何为具有多对多字段的Django模型创建对象?

问题:如何为具有多对多字段的Django模型创建对象?

我的模特:

class Sample(models.Model):
    users = models.ManyToManyField(User)

我想同时保存user1并保存user2在该模型中:

user1 = User.objects.get(pk=1)
user2 = User.objects.get(pk=2)
sample_object = Sample(users=user1, users=user2)
sample_object.save()

我知道这是错误的,但是我敢肯定,您会明白我的意思。你会怎么做?

My model:

class Sample(models.Model):
    users = models.ManyToManyField(User)

I want to save both user1 and user2 in that model:

user1 = User.objects.get(pk=1)
user2 = User.objects.get(pk=2)
sample_object = Sample(users=user1, users=user2)
sample_object.save()

I know that’s wrong, but I’m sure you get what I want to do. How would you do it ?


回答 0

您不能从未保存的对象创建m2m关系。如果有pk,请尝试以下操作:

sample_object = Sample()
sample_object.save()
sample_object.users.add(1,2)

更新:阅读了saverio的答案后,我决定对这个问题进行更深入的研究。这是我的发现。

这是我最初的建议。它可以工作,但不是最佳选择。(注意:我使用Bar的是s和a Foo而不是Users和a Sample,但是您知道了。)

bar1 = Bar.objects.get(pk=1)
bar2 = Bar.objects.get(pk=2)
foo = Foo()
foo.save()
foo.bars.add(bar1)
foo.bars.add(bar2)

它总共产生7个查询:

SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 1
SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 2
INSERT INTO "app_foo" ("name") VALUES ()
SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1  AND "app_foo_bars"."bar_id" IN (1))
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 1)
SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1  AND "app_foo_bars"."bar_id" IN (2))
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 2)

我相信我们可以做得更好。您可以将多个对象传递给该add()方法:

bar1 = Bar.objects.get(pk=1)
bar2 = Bar.objects.get(pk=2)
foo = Foo()
foo.save()
foo.bars.add(bar1, bar2)

如我们所见,传递多个对象可以节省一个SELECT

SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 1
SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 2
INSERT INTO "app_foo" ("name") VALUES ()
SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1  AND "app_foo_bars"."bar_id" IN (1, 2))
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 1)
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 2)

我不知道您还可以分配对象列表:

bar1 = Bar.objects.get(pk=1)
bar2 = Bar.objects.get(pk=2)
foo = Foo()
foo.save()
foo.bars = [bar1, bar2]

不幸的是,这又增加了一个SELECT

SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 1
SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 2
INSERT INTO "app_foo" ("name") VALUES ()
SELECT "app_foo_bars"."id", "app_foo_bars"."foo_id", "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE "app_foo_bars"."foo_id" = 1
SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1  AND "app_foo_bars"."bar_id" IN (1, 2))
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 1)
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 2)

让我们尝试分配一个pks 列表,如saverio建议的那样:

foo = Foo()
foo.save()
foo.bars = [1,2]

由于不获取两个Bars,因此保存了两个SELECT语句,总共有5个:

INSERT INTO "app_foo" ("name") VALUES ()
SELECT "app_foo_bars"."id", "app_foo_bars"."foo_id", "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE "app_foo_bars"."foo_id" = 1
SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1  AND "app_foo_bars"."bar_id" IN (1, 2))
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 1)
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 2)

最终获胜者是:

foo = Foo()
foo.save()
foo.bars.add(1,2)

路过pks到add()让我们一共有4个查询:

INSERT INTO "app_foo" ("name") VALUES ()
SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1  AND "app_foo_bars"."bar_id" IN (1, 2))
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 1)
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 2)

You cannot create m2m relations from unsaved objects. If you have the pks, try this:

sample_object = Sample()
sample_object.save()
sample_object.users.add(1,2)

Update: After reading the saverio’s answer, I decided to investigate the issue a bit more in depth. Here are my findings.

This was my original suggestion. It works, but isn’t optimal. (Note: I’m using Bars and a Foo instead of Users and a Sample, but you get the idea).

bar1 = Bar.objects.get(pk=1)
bar2 = Bar.objects.get(pk=2)
foo = Foo()
foo.save()
foo.bars.add(bar1)
foo.bars.add(bar2)

It generates a whopping total of 7 queries:

SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 1
SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 2
INSERT INTO "app_foo" ("name") VALUES ()
SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1  AND "app_foo_bars"."bar_id" IN (1))
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 1)
SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1  AND "app_foo_bars"."bar_id" IN (2))
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 2)

I’m sure we can do better. You can pass multiple objects to the add() method:

bar1 = Bar.objects.get(pk=1)
bar2 = Bar.objects.get(pk=2)
foo = Foo()
foo.save()
foo.bars.add(bar1, bar2)

As we can see, passing multiple objects saves one SELECT:

SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 1
SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 2
INSERT INTO "app_foo" ("name") VALUES ()
SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1  AND "app_foo_bars"."bar_id" IN (1, 2))
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 1)
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 2)

I wasn’t aware that you can also assign a list of objects:

bar1 = Bar.objects.get(pk=1)
bar2 = Bar.objects.get(pk=2)
foo = Foo()
foo.save()
foo.bars = [bar1, bar2]

Unfortunately, that creates one additional SELECT:

SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 1
SELECT "app_bar"."id", "app_bar"."name" FROM "app_bar" WHERE "app_bar"."id" = 2
INSERT INTO "app_foo" ("name") VALUES ()
SELECT "app_foo_bars"."id", "app_foo_bars"."foo_id", "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE "app_foo_bars"."foo_id" = 1
SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1  AND "app_foo_bars"."bar_id" IN (1, 2))
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 1)
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 2)

Let’s try to assign a list of pks, as saverio suggested:

foo = Foo()
foo.save()
foo.bars = [1,2]

As we don’t fetch the two Bars, we save two SELECT statements, resulting in a total of 5:

INSERT INTO "app_foo" ("name") VALUES ()
SELECT "app_foo_bars"."id", "app_foo_bars"."foo_id", "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE "app_foo_bars"."foo_id" = 1
SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1  AND "app_foo_bars"."bar_id" IN (1, 2))
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 1)
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 2)

And the winner is:

foo = Foo()
foo.save()
foo.bars.add(1,2)

Passing pks to add() gives us a total of 4 queries:

INSERT INTO "app_foo" ("name") VALUES ()
SELECT "app_foo_bars"."bar_id" FROM "app_foo_bars" WHERE ("app_foo_bars"."foo_id" = 1  AND "app_foo_bars"."bar_id" IN (1, 2))
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 1)
INSERT INTO "app_foo_bars" ("foo_id", "bar_id") VALUES (1, 2)

回答 1

对于将来的访问者,您可以使用django 1.4中新的bulk_create2个查询中创建一个对象及其所有m2m对象。请注意,仅当您不需要对带有save()方法或信号的数据进行任何预处理或后处理时,此方法才可用。您插入的正是数据库中的内容

您无需在字段上指定“直通”模型即可执行此操作。为了完整起见,下面的示例创建了一个空白的Users模型来模仿原始海报的要求。

from django.db import models

class Users(models.Model):
    pass

class Sample(models.Model):
    users = models.ManyToManyField(Users)

现在,在Shell或其他代码中,创建2个用户,创建一个示例对象,然后将用户批量添加到该示例对象中。

Users().save()
Users().save()

# Access the through model directly
ThroughModel = Sample.users.through

users = Users.objects.filter(pk__in=[1,2])

sample_object = Sample()
sample_object.save()

ThroughModel.objects.bulk_create([
    ThroughModel(users_id=users[0].pk, sample_id=sample_object.pk),
    ThroughModel(users_id=users[1].pk, sample_id=sample_object.pk)
])

For future visitors, you can create an object and all of its m2m objects in 2 queries using the new bulk_create in django 1.4. Note that this is only usable if you don’t require any pre or post-processing on the data with save() methods or signals. What you insert is exactly what will be in the DB

You can do this without specifying a “through” model on the field. For completeness, the example below creates a blank Users model to mimic what the original poster was asking.

from django.db import models

class Users(models.Model):
    pass

class Sample(models.Model):
    users = models.ManyToManyField(Users)

Now, in a shell or other code, create 2 users, create a sample object, and bulk add the users to that sample object.

Users().save()
Users().save()

# Access the through model directly
ThroughModel = Sample.users.through

users = Users.objects.filter(pk__in=[1,2])

sample_object = Sample()
sample_object.save()

ThroughModel.objects.bulk_create([
    ThroughModel(users_id=users[0].pk, sample_id=sample_object.pk),
    ThroughModel(users_id=users[1].pk, sample_id=sample_object.pk)
])

回答 2

Django 1.9
一个简单的例子:

sample_object = Sample()
sample_object.save()

list_of_users = DestinationRate.objects.all()
sample_object.users.set(list_of_users)

Django 1.9
A quick example:

sample_object = Sample()
sample_object.save()

list_of_users = DestinationRate.objects.all()
sample_object.users.set(list_of_users)

回答 3

RelatedObjectManagers与Model中的字段是不同的“属性”。实现您想要的最简单的方法是

sample_object = Sample.objects.create()
sample_object.users = [1, 2]

这与分配用户列表相同,而没有其他查询和模型构建。

如果查询的数量让您感到困扰(而不是简单),那么最佳解决方案将需要三个查询:

sample_object = Sample.objects.create()
sample_id = sample_object.id
sample_object.users.through.objects.create(user_id=1, sample_id=sample_id)
sample_object.users.through.objects.create(user_id=2, sample_id=sample_id)

这将起作用,因为我们已经知道“用户”列表为空,因此我们可以轻松创建。

RelatedObjectManagers are different “attributes” than fields in a Model. The simplest way to achieve what you are looking for is

sample_object = Sample.objects.create()
sample_object.users = [1, 2]

That’s the same as assigning a User list, without the additional queries and the model building.

If the number of queries is what bothers you (instead of simplicity), then the optimal solution requires three queries:

sample_object = Sample.objects.create()
sample_id = sample_object.id
sample_object.users.through.objects.create(user_id=1, sample_id=sample_id)
sample_object.users.through.objects.create(user_id=2, sample_id=sample_id)

This will work because we already know that the ‘users’ list is empty, so we can create mindlessly.


回答 4

您可以通过以下方式替换相关对象集(Django 1.9中的新增功能):

new_list = [user1, user2, user3]
sample_object.related_set.set(new_list)

You could replace the set of related objects in this way (new in Django 1.9):

new_list = [user1, user2, user3]
sample_object.related_set.set(new_list)

回答 5

如果有人想做David Marbles,请回答自我引用ManyToMany字段。直通模型的ID称为:“ to_’model_name_id”和“ from_’model_name’_id”。

如果这样不起作用,您可以检查Django连接。

If someone is looking to do David Marbles answer on a self referring ManyToMany field. The ids of the through model are called: “to_’model_name_id” and “from_’model_name’_id”.

If that doesn’t work you can check the django connection.


Django-makemigrations-未检测到更改

问题:Django-makemigrations-未检测到更改

我试图使用makemigrations命令在现有应用程序中创建迁移,但输出“未检测到更改”。

通常,我使用startapp命令创建新应用,但在创建该应用时并未将其用于该应用。

调试后,我发现它没有创建迁移,因为migrations应用程序中缺少软件包/文件夹。

如果不存在该文件夹,还是创建丢失的文件夹,会更好吗?

I was trying to create migrations within an existing app using the makemigrations command but it outputs “No changes detected”.

Usually I create new apps using the startapp command but did not use it for this app when I created it.

After debugging, I found that it is not creating migration because the migrations package/folder is missing from an app.

Would it be better if it creates the folder if it is not there or am I missing something?


回答 0

要为应用创建初始迁移,请运行makemigrations并指定应用名称。将创建迁移文件夹。

./manage.py makemigrations <myapp>

您的应用必须首先包含INSTALLED_APPS(在settings.py内部)。

To create initial migrations for an app, run makemigrations and specify the app name. The migrations folder will be created.

./manage.py makemigrations <myapp>

Your app must be included in INSTALLED_APPS first (inside settings.py).


回答 1

我的问题(以及解决方案)与上述问题有所不同。

我没有使用models.py文件,而是创建了一个models目录并在my_model.py其中创建了文件,并在其中放置了模型。Django找不到我的模型,因此它写道没有要应用的迁移。

我的解决方案是:在my_app/models/__init__.py文件中添加以下行: from .my_model import MyModel

My problem (and so solution) was yet different from those described above.

I wasn’t using models.py file, but created a models directory and created the my_model.py file there, where I put my model. Django couldn’t find my model so it wrote that there are no migrations to apply.

My solution was: in the my_app/models/__init__.py file I added this line: from .my_model import MyModel


回答 2

django在makemigrations命令执行期间未检测到要迁移的内容有多种可能的原因。

  1. 迁移文件夹您的应用程序中需要一个迁移软件包。
  2. INSTALLED_APPS您需要在INSTALLED_APPS.dict中指定您的应用
  3. 详尽度 从运行makemigrations -v 3冗长开始。这可能会为这个问题提供一些启示。
  4. 完整路径INSTALLED_APPS建议指定完整的模块应用程序配置路径“apply.apps.MyAppConfig”
  5. –settings,您可能需要确保设置了正确的设置文件:manage.py makemigrations --settings mysite.settings
  6. 指定应用程序名称可以显式地放入应用程序名称manage.py makemigrations myapp-不仅可以缩小应用程序的迁移范围,而且可以帮助您隔离问题。
  7. 模型元检查你有合适的app_label模型中的元

  8. 调试django调试django核心脚本。makemigrations命令非常简单。这是在pycharm中执行的方法。相应地改变你的脚本定义(例如:makemigrations --traceback myapp

多个数据库:

  • DB路由器时使用Django DB路由器,路由器类(您的自定义类路由器)工作需要实现的allow_syncdb方法。

makemigrations总是为模型更改创建迁移,但是如果allow_migrate()返回False,

There are multiple possible reasons for django not detecting what to migrate during the makemigrations command.

  1. migration folder You need a migrations package in your app.
  2. INSTALLED_APPS You need your app to be specified in the INSTALLED_APPS .dict
  3. Verbosity start by running makemigrations -v 3 for verbosity. This might shed some light on the problem.
  4. Full path In INSTALLED_APPS it is recommended to specify the full module app config path ‘apply.apps.MyAppConfig’
  5. –settings you might want to make sure the correct settings file is set: manage.py makemigrations --settings mysite.settings
  6. specify app name explicitly put the app name in manage.py makemigrations myapp – that narrows down the migrations for the app alone and helps you isolate the problem.
  7. model meta check you have the right app_label in your model meta

  8. Debug django debug django core script. makemigrations command is pretty much straight forward. Here’s how to do it in pycharm. change your script definition accordingly (ex: makemigrations --traceback myapp)

Multiple databases:

  • Db Router when working with django db router, the router class (your custom router class) needs to implement the allow_syncdb method.

makemigrations always creates migrations for model changes, but if allow_migrate() returns False,


回答 3

我已经读过许多关于这个问题的答案,通常说它们只是makemigrations以其他方式运行。但是对我来说,问题出在Meta模型的子类中。

我有一个应用程序配置说label = <app name>(在apps.py文件中models.pyviews.py等等)。如果您的元类碰巧没有与应用程序标签相同的标签(例如,因为您将一个太大的应用程序拆分为多个应用程序),则不会检测到任何更改(也不会显示任何有用的错误消息)。因此,在我的模型课中,我现在有:

class ModelClassName(models.Model):

    class Meta:
        app_label = '<app name>' # <-- this label was wrong before.

    field_name = models.FloatField()
    ...

在此处运行Django 1.10。

I’ve read many answers to this question often stating to simply run makemigrations in some other ways. But to me, the problem was in the Meta subclass of models.

I have an app config that says label = <app name> (in the apps.py file, beside models.py, views.py etc). If by any chance your meta class doesn’t have the same label as the app label (for instance because you are splitting one too big app into multiple ones), no changes are detected (and no helpful error message whatsoever). So in my model class I have now:

class ModelClassName(models.Model):

    class Meta:
        app_label = '<app name>' # <-- this label was wrong before.

    field_name = models.FloatField()
    ...

Running Django 1.10 here.


回答 4

这是一个评论,但可能应该是一个答案。

确保您的应用程序名称位于settings.py中,INSTALLED_APPS否则无论执行什么操作都不会运行迁移。

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'blog',
]

然后运行:

./manage.py makemigrations blog

It is a comment but should probably be an answer.

Make sure that your app name is in settings.py INSTALLED_APPS otherwise no matter what you do it will not run the migrations.

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'blog',
]

Then run:

./manage.py makemigrations blog

回答 5

我还有另一个这里未描述的问题,这让我发疯。

class MyModel(models.Model):
    name = models.CharField(max_length=64, null=True)  # works
    language_code = models.CharField(max_length=2, default='en')  # works
    is_dumb = models.BooleanField(default=False),  # doesn't work

在复制和粘贴的一行中,我有一个尾随的“,”。is_dumb所在的行不会使用’./manage.py makemigrations’创建模型迁移,但也不会引发错误。删除“后,”它按预期方式工作。

因此,在复制粘贴时请多加注意:-)

I had another problem not described here, which drove me nuts.

class MyModel(models.Model):
    name = models.CharField(max_length=64, null=True)  # works
    language_code = models.CharField(max_length=2, default='en')  # works
    is_dumb = models.BooleanField(default=False),  # doesn't work

I had a trailing ‘,’ in one line perhaps from copy&paste. The line with is_dumb doesn’t created a model migration with ‘./manage.py makemigrations’ but also didn’t throw an error. After removing the ‘,’ it worked as expected.

So be careful when you do copy&paste :-)


回答 6

有时./manage.py makemigrations有优于./manage.py makemigrations <myapp>因为它可以处理应用程序之间的某些冲突。

这些场合默默发生,花了几个小时swearing才能理解恐惧的真正含义No changes detected消息。

因此,使用以下命令是一个更好的选择:

./manage.py makemigrations <myapp1> <myapp2> ... <myappN>

There are sometimes when ./manage.py makemigrations is superior to ./manage.py makemigrations <myapp> because it can handle certain conflicts between apps.

Those occasions occur silently and it takes several hours of swearing to understand the real meaning of the dreaded No changes detected message.

Therefore, it is a far better choice to make use of the following command:

./manage.py makemigrations <myapp1> <myapp2> ... <myappN>


回答 7

我从django外部复制了一个表,默认将Meta类设置为“ managed = false”。例如:

class Rssemailsubscription(models.Model):
    id = models.CharField(primary_key=True, max_length=36)
    ...
    area = models.FloatField('Area (Sq. KM)', null=True)

    class Meta:
        managed = False
        db_table = 'RSSEmailSubscription'

通过将managed更改为True,makemigrations开始接受更改。

I had copied a table in from outside of django and the Meta class defaulted to “managed = false”. For example:

class Rssemailsubscription(models.Model):
    id = models.CharField(primary_key=True, max_length=36)
    ...
    area = models.FloatField('Area (Sq. KM)', null=True)

    class Meta:
        managed = False
        db_table = 'RSSEmailSubscription'

By changing manged to True, makemigrations started picking up changes.


回答 8

  1. 确保您的应用在settings.py中的installed_apps中被提及
  2. 确保您的模型类扩展了模型。
  1. Make sure your app is mentioned in installed_apps in settings.py
  2. Make sure you model class extends models.Model

回答 9

我这样做来解决了这个问题:

  1. 擦除“ db.sqlite3”文件。这里的问题是您当前的数据库将被删除,因此您将不得不重新制作它。
  2. 在已编辑的应用程序的迁移文件夹中,删除上次更新的文件。请记住,第一个创建的文件是:“ 0001_initial.py”。例如:我创建了一个新类,并通过“ makemigrations”和“ migrate”过程进行了注册,现在创建了一个名为“ 0002_auto_etc.py”的新文件;删除它。
  3. 转到pycache ”文件夹(位于migrations文件夹内),然后删除文件“ 0002_auto_etc.pyc”。
  4. 最后,转到控制台并使用“ python manage.py makemigrations”和“ python manage.py migration”。

I solved that problem by doing this:

  1. Erase the “db.sqlite3” file. The issue here is that your current data base will be erased, so you will have to remake it again.
  2. Inside the migrations folder of your edited app, erase the last updated file. Remember that the first created file is: “0001_initial.py”. For example: I made a new class and register it by the “makemigrations” and “migrate” procedure, now a new file called “0002_auto_etc.py” was created; erase it.
  3. Go to the “pycache” folder (inside the migrations folder) and erase the file “0002_auto_etc.pyc”.
  4. Finally, go to the console and use “python manage.py makemigrations” and “python manage.py migrate”.

回答 10

我忘了提出正确的论点:

class LineInOffice(models.Model):   # here
    addressOfOffice = models.CharField("Корхоная жош",max_length= 200)   #and here
    ...

在models.py中,然后就开始消除烦人的

在应用程序“ myApp”中未检测到更改

I forgot to put correct arguments:

class LineInOffice(models.Model):   # here
    addressOfOffice = models.CharField("Корхоная жош",max_length= 200)   #and here
    ...

in models.py and then it started to drop that annoying

No changes detected in app ‘myApp ‘


回答 11

另一个可能的原因是,如果您在其他文件中(而不是在程序包中)定义了某些模型,而在其他任何地方都没有引用过。

对我来说,简单地增加from .graph_model import *,以admin.py(其中graph_model.py为新文件)解决了这一问题。

Another possible reason is if you had some models defined in another file (not in a package) and haven’t referenced that anywhere else.

For me, simply adding from .graph_model import * to admin.py (where graph_model.py was the new file) fixed the problem.


回答 12

我的问题比上面的答案要简单得多,并且可能是一个更普遍的原因,只要您的项目已经建立并可以运行。在我的一个已经使用了很长时间的应用程序中,迁移似乎很困难,因此,我急着做了以下事情:

rm -r */migrations/*
rm db.sqlite3
python3 manage.py makemigrations
No changes detected

哇?

我错误地还删除了所有__init__.py文件:(-进入后,一切又恢复正常了:

touch ads1/migrations/__init__.py

对于我的每个应用程序,都可以makemigrations再次使用。

事实证明,我已经手动通过复制另一个创建了一个新的应用程序,忘了把__init__.pymigrations文件夹和confinved我,一切都是靠不住的-我的领先使得它与更坏rm -r如上所述。

希望这可以帮助某人在几个小时内发誓“未检测到更改”错误。

My problem was much simpler than the above answers and probably a far more common reason as long as your project is already set up and working. In one of my applications that had been working for a long time, migrations seemed wonky, so in a hurry, I did the following:

rm -r */migrations/*
rm db.sqlite3
python3 manage.py makemigrations
No changes detected

Whaat??

I had mistakenly also removed all the __init__.py files :( – Everything was working again after I went in and:

touch ads1/migrations/__init__.py

For each of my applications then the makemigrations worked again.

It turns out that I had manually created a new application by copying another and forgot to put the __init__.py in the migrations folder and that confinved me that everything was wonky – leading my making it worse with an rm -r as described above.

Hope this helps someone from swearing at the “No changes detected” error for a few hours.


回答 13

解决方案是您必须将您的应用程序包含在INSTALLED_APPS中。

我错过了,发现了同样的问题。

指定我的应用名称后,迁移成功

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'boards',
]

请注意,我最后提到的木板是我的应用名称。

The solution is you have to include your app in INSTALLED_APPS.

I missed it and I found this same issue.

after specifying my app name migration became successful

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'boards',
]

please note I mentioned boards in last, which is my app name.


回答 14

INSTALLED_APPS = [

'blog.apps.BlogConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',

]

确保“ blog.apps.BlogConfig”(此设置包含在settings.py中,以便进行应用迁移)

然后运行python3 manage.py makemigrations博客或您的应用名称

INSTALLED_APPS = [

'blog.apps.BlogConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',

]

make sure ‘blog.apps.BlogConfig’, (this is included in your settings.py in order to make your app migrations)

then run python3 manage.py makemigrations blog or your app name


回答 15

您可能还会遇到的一个非常愚蠢的问题是class Meta在模型中定义两个。在这种情况下,运行时不会应用对第一个所做的任何更改makemigrations

class Product(models.Model):
    somefield = models.CharField(max_length=255)
    someotherfield = models.CharField(max_length=255)

    class Meta:
        indexes = [models.Index(fields=["somefield"], name="somefield_idx")]

    def somefunc(self):
        pass

    # Many lines...

    class Meta:
        indexes = [models.Index(fields=["someotherfield"], name="someotherfield_idx")]

A very dumb issue you can have as well is to define two class Meta in your model. In that case, any change to the first one won’t be applied when running makemigrations.

class Product(models.Model):
    somefield = models.CharField(max_length=255)
    someotherfield = models.CharField(max_length=255)

    class Meta:
        indexes = [models.Index(fields=["somefield"], name="somefield_idx")]

    def somefunc(self):
        pass

    # Many lines...

    class Meta:
        indexes = [models.Index(fields=["someotherfield"], name="someotherfield_idx")]

回答 16

我知道这是一个老问题,但是我整天都在同一个问题上作斗争,而我的解决方案很简单。

我的目录结构类似于…

apps/
   app/
      __init__.py
      app_sub1/
           __init__.py
           models.py
      app_sub2/
           __init__.py
           models.py
      app_sub3/
           __init__.py
           models.py
   app2/
      __init__.py
      app2_sub1/
           __init__.py
           models.py
      app2_sub2/
           __init__.py
           models.py
      app2_sub3/
           __init__.py
           models.py
    main_app/
      __init__.py
      models.py

而且由于直到我遇到问题的所有其他模型都被导入到其他地方,最后又从main_app那里导入了INSTALLED_APPS,所以我很幸运,他们都可以使用。

但是由于我只添加了一个appINSTALLED_APPS而不是app_sub*当我最终添加了一个其他未导入的新模型文件时添加的,因此Django完全忽略了它。

我的解决方法是像这样将models.py文件添加到每个文件的基本目录中app

apps/
   app/
      __init__.py
      models.py <<<<<<<<<<--------------------------
      app_sub1/
           __init__.py
           models.py
      app_sub2/
           __init__.py
           models.py
      app_sub3/
           __init__.py
           models.py
   app2/
      __init__.py
      models.py <<<<<<<<<<--------------------------
      app2_sub1/
           __init__.py
           models.py
      app2_sub2/
           __init__.py
           models.py
      app2_sub3/
           __init__.py
           models.py
    main_app/
      __init__.py
      models.py

然后添加from apps.app.app_sub1 import *等等到每个app关卡models.py文件中。

Bleh …这花了我很长时间才弄清楚,我在任何地方都找不到解决方案…我什至转到了Google搜索结果的第2页。

希望这对某人有帮助!

I know this is an old question but I fought with this same issue all day and my solution was a simple one.

I had my directory structure something along the lines of…

apps/
   app/
      __init__.py
      app_sub1/
           __init__.py
           models.py
      app_sub2/
           __init__.py
           models.py
      app_sub3/
           __init__.py
           models.py
   app2/
      __init__.py
      app2_sub1/
           __init__.py
           models.py
      app2_sub2/
           __init__.py
           models.py
      app2_sub3/
           __init__.py
           models.py
    main_app/
      __init__.py
      models.py

And since all the other models up until the one I had a problem with were being imported somewhere else that ended up importing from main_app which was registered in the INSTALLED_APPS, I just got lucky that they all worked.

But since I only added each app to INSTALLED_APPS and not the app_sub* when I finally added a new models file that wasn’t imported ANYWHERE else, Django totally ignored it.

My fix was adding a models.py file to the base directory of each app like this…

apps/
   app/
      __init__.py
      models.py <<<<<<<<<<--------------------------
      app_sub1/
           __init__.py
           models.py
      app_sub2/
           __init__.py
           models.py
      app_sub3/
           __init__.py
           models.py
   app2/
      __init__.py
      models.py <<<<<<<<<<--------------------------
      app2_sub1/
           __init__.py
           models.py
      app2_sub2/
           __init__.py
           models.py
      app2_sub3/
           __init__.py
           models.py
    main_app/
      __init__.py
      models.py

and then add from apps.app.app_sub1 import * and so on to each of the app level models.py files.

Bleh… this took me SO long to figure out and I couldn’t find the solution anywhere… I even went to page 2 of the google results.

Hope this helps someone!


回答 17

根据官方文档中的“迁移”部分,我在django 3.0中遇到了类似的问题,运行它足以更新我的表结构:

python manage.py makemigrations
python manage.py migrate

但是输出始终是相同的:执行“ makemigrations”脚本后,模型“未检测到更改”。我要在数据库上更新的模型在models.py上出现语法错误:

field_model : models.CharField(max_length=255, ...)

代替:

field_model = models.CharField(max_length=255, ...)

解决了这个愚蠢的错误,使用这些命令可以顺利进行迁移。也许这可以帮助某人。

I had a similar issue with django 3.0, according migrations section in the official documentation, running this was enough to update my table structure:

python manage.py makemigrations
python manage.py migrate

But the output was always the same: ‘no change detected’ about my models after I executed ‘makemigrations’ script. I had a syntax error on models.py at the model I wanted to update on db:

field_model : models.CharField(max_length=255, ...)

instead of:

field_model = models.CharField(max_length=255, ...)

Solving this stupid mistake, with those command the migration was done without problems. Maybe this helps someone.


回答 18

您应该添加polls.apps.PollsConfigINSTALLED_APPSsetting.py

You should add polls.apps.PollsConfig to INSTALLED_APPS in setting.py


回答 19

就我而言,我忘记插入类参数

错误:

class AccountInformation():

正确

class AccountInformation(models.Model):

In my case i forgot to insert the class arguments

Wrong:

class AccountInformation():

Correct

class AccountInformation(models.Model):

回答 20

就我而言,我首先向模型添加了一个字段,而Django说没有任何变化。

比起我决定更改模型的“表名”,makemigrations起作用了。比起将表名改回默认值,新字段也在那里。

django迁移系统中有一个“ bug”,有时看不到新字段。可能与日期字段有关。

In my case, I first added a field to the model, and Django said there’re no changes.

Than I decided to change the “table name” of the model, makemigrations worked. Than I changed table name back to default, and the new field was also there.

There is a “bug” in django migration system, sometimes it doesn’t see the new field. Might be related with date field.


回答 21

可能的原因可能是删除了现有的db文件和migrations文件夹,您可以使用python manage.py makemigrations <app_name>来工作。我曾经遇到过类似的问题。

The possible reason could be deletion of the existing db file and migrations folder you can use python manage.py makemigrations <app_name> this should work. I once faced a similar problem.


回答 22

另一种边缘情况和解决方案:

我添加了一个布尔字段,并同时添加了一个引用该属性的@property,其名称相同(doh)。注释了该属性,并且迁移看到并添加了新字段。重命名该属性,一切都很好。

One more edge case and solution:

I added a boolean field, and at the same time added an @property referencing it, with the same name (doh). Commented the property and migration sees and adds the new field. Renamed the property and all is good.


回答 23

如果您拥有managed = True模型内部元数据,则需要将其删除并进行迁移。然后再次运行迁移,它将检测到新更新。

If you have the managed = True in yout model Meta, you need to remove it and do a migration. Then run the migrations again, it will detect the new updates.


回答 24

将新模型添加到django api应用程序并运行python manage.py makemigrations该工具时,未检测到任何新模型。

奇怪的是,旧模型确实被选中了makemigrations,但这是因为它们在urlpatterns链中并且该工具以某种方式检测到了它们。因此,请注意该行为。

问题是因为与models包相对应的目录结构具有子包,并且所有__init__.py文件均为空。他们必须在每个子文件夹和模型中 显式导入所有必需的类,以__init__.py供Django使用该makemigrations工具将其提取。

models
  ├── __init__.py          <--- empty
  ├── patient
     ├── __init__.py      <--- empty
     ├── breed.py
     └── ...
  ├── timeline
     ├── __init__.py      <-- empty
     ├── event.py
     └── ...

When adding new models to the django api application and running the python manage.py makemigrations the tool did not detect any new models.

The strange thing was that the old models did got picked by makemigrations, but this was because they were referenced in the urlpatterns chain and the tool somehow detected them. So keep an eye on that behavior.

The problem was because the directory structure corresponding to the models package had subpackages and all the __init__.py files were empty. They must explicitly import all the required classes in each subfolder and in the models __init__.py for Django to pick them up with the makemigrations tool.

models
  ├── __init__.py          <--- empty
  ├── patient
  │   ├── __init__.py      <--- empty
  │   ├── breed.py
  │   └── ...
  ├── timeline
  │   ├── __init__.py      <-- empty
  │   ├── event.py
  │   └── ...

回答 25

尝试在admin.py中注册模型,这是一个示例:-admin.site.register(YourModelHere)

您可以执行以下操作:1. 1. admin.site.register(YourModelHere)#在admin.py中2.重新加载页面并重试3.按下CTRL-S并保存4.可能有错误,特别是检查模型.py和admin.py5。或者,在结束时,只需重新启动服务器即可。

Try registering your model in admin.py, here’s an example:- admin.site.register(YourModelHere)

You can do the following things:- 1. admin.site.register(YourModelHere) # In admin.py 2. Reload the page and try again 3. Hit CTRL-S and save 4. There might be an error, specially check models.py and admin.py 5. Or, at the end of it all just restart the server


回答 26

这可能希望对其他人有所帮助,因为我最终花了数小时试图将其消除。

如果你有一个函数模型由同一个名字,这将删除值。事后看来很明显,但仍然如此。

因此,如果您有这样的事情:

class Foobar(models.Model):
    [...]
    something = models.BooleanField(default=False)

    [...]
    def something(self):
        return [some logic]

在这种情况下,该功能将覆盖上面的设置,使其对变为“不可见” makemigrations

This might hopefully help someone else, as I ended up spending hours trying to chase this down.

If you have a function within your model by the same name, this will remove the value. Pretty obvious in hindsight, but nonetheless.

So, if you have something like this:

class Foobar(models.Model):
    [...]
    something = models.BooleanField(default=False)

    [...]
    def something(self):
        return [some logic]

In that case, the function will override the setting above, making it “invisible” to makemigrations.


回答 27

您可以做的最好的事情是,删除现有数据库。就我而言,我使用的是phpMyAdmin SQL数据库,因此我手动删除了上面创建的数据库。

删除后: 我在PhpMyAdmin中创建数据库,并且不添加任何表。

再次运行以下命令:

python manage.py makemigrations

python manage.py migrate

这些命令之后:您可以看到django在数据库中自动创建了其他必要的表(大约有10个表)。

python manage.py makemigrations <app_name>

python manage.py migrate

最后:在上述命令之后,您创建的所有模型(表)都将直接导入数据库。

希望这会有所帮助。

The Best Thing You can do is, Delete the existing database. In my case, I were using phpMyAdmin SQL database, so I manually delete the created database overthere.

After Deleting: I create database in PhpMyAdmin, and doesn,t add any tables.

Again run the following Commands:

python manage.py makemigrations

python manage.py migrate

After These Commands: You can see django has automatically created other necessary tables in Database(Approx there are 10 tables).

python manage.py makemigrations <app_name>

python manage.py migrate

And Lastly: After above commands all the model(table) you have created are directly imported to the database.

Hope this will help.


回答 28

我对此错误的问题是,我包括了:

class Meta:
   abstract = True

我要为其创建的内部模型。

My problem with this error, was that I had included:

class Meta:
   abstract = True

Inside model that I wanted to creation migrate for.


回答 29

创建一个名为的新应用时,我遇到了另一个问题deals。我想在该应用中分离模型,所以我有2个名为deals.py和的模型文件dealers.py。运行时,python manage.py makemigrations我得到了:No changes detected

我继续前进,并将__init__.py其放在我的模型文件所在的同一目录(交易和经销商)中

from .deals import *
from .dealers import *

然后makemigrations命令起作用了。

原来,如果您不打算在任何地方导入模型,或者模型文件名不是 models.py不会检测到模型。

我遇到的另一个问题是我在settings.py以下位置编写应用程序的方式:

我有:

apps.deals

它应该已经包含了根项目文件夹:

cars.apps.deals

I had a different issue while creating a new app called deals. I wanted to separate the models inside that app so I had 2 model files named deals.py and dealers.py. When running python manage.py makemigrations I got: No changes detected.

I went ahead and inside the __init__.py which lives on the same directory where my model files lived (deals and dealer) I did

from .deals import *
from .dealers import *

And then the makemigrations command worked.

Turns out that if you are not importing the models anywhere OR your models file name isn’t models.py then the models wont be detected.

Another issue that happened to me is the way I wrote the app in settings.py:

I had:

apps.deals

It should’ve been including the root project folder:

cars.apps.deals

OSError:[Errno 2]在Django中使用python子进程时,没有此类文件或目录

问题:OSError:[Errno 2]在Django中使用python子进程时,没有此类文件或目录

我正在尝试运行一个程序以使用Python代码在subprocess.call()其中进行一些系统调用,从而引发以下错误:

Traceback (most recent call last):
      File "<console>", line 1, in <module>
      File "/usr/lib/python2.7/subprocess.py", line 493, in call
      return Popen(*popenargs, **kwargs).wait()
      File "/usr/lib/python2.7/subprocess.py", line 679, in __init__
errread, errwrite)
      File "/usr/lib/python2.7/subprocess.py", line 1249, in _execute_child
      raise child_exception
      OSError: [Errno 2] No such file or directory

我的实际Python代码如下:

url = "/media/videos/3cf02324-43e5-4996-bbdf-6377df448ae4.mp4"
real_path = "/home/chanceapp/webapps/chanceapp/chanceapp"+url
fake_crop_path = "/home/chanceapp/webapps/chanceapp/chanceapp/fake1"+url
fake_rotate_path = "/home/chanceapp/webapps/chanceapp.chanceapp/fake2"+url
crop = "ffmpeg -i %s -vf "%(real_path)+"crop=400:400:0:0 "+ "-strict -2 %s"%(fake_crop_path)
rotate = "ffmpeg -i %s -vf "%(fake_crop_path)+"transpose=1 "+"%s"%(fake_rotate_path)
move_rotated = "mv"+" %s"%(fake_rotate_path)+" %s"%(real_path)
delete_cropped = "rm "+"%s"%(fake_crop_path)
#system calls:
subprocess.call(crop)

我可以获取有关如何解决此问题的一些建议吗?

I am trying to run a program to make some system calls inside Python code using subprocess.call() which throws the following error:

Traceback (most recent call last):
      File "<console>", line 1, in <module>
      File "/usr/lib/python2.7/subprocess.py", line 493, in call
      return Popen(*popenargs, **kwargs).wait()
      File "/usr/lib/python2.7/subprocess.py", line 679, in __init__
errread, errwrite)
      File "/usr/lib/python2.7/subprocess.py", line 1249, in _execute_child
      raise child_exception
      OSError: [Errno 2] No such file or directory

My actual Python code is as follows:

url = "/media/videos/3cf02324-43e5-4996-bbdf-6377df448ae4.mp4"
real_path = "/home/chanceapp/webapps/chanceapp/chanceapp"+url
fake_crop_path = "/home/chanceapp/webapps/chanceapp/chanceapp/fake1"+url
fake_rotate_path = "/home/chanceapp/webapps/chanceapp.chanceapp/fake2"+url
crop = "ffmpeg -i %s -vf "%(real_path)+"crop=400:400:0:0 "+ "-strict -2 %s"%(fake_crop_path)
rotate = "ffmpeg -i %s -vf "%(fake_crop_path)+"transpose=1 "+"%s"%(fake_rotate_path)
move_rotated = "mv"+" %s"%(fake_rotate_path)+" %s"%(real_path)
delete_cropped = "rm "+"%s"%(fake_crop_path)
#system calls:
subprocess.call(crop)

Can I get some relevant advice on how to solve this?


回答 0

使用shell=True,如果你传递一个字符串subprocess.call

文档

如果传递单个字符串,则shell必须为True,否则该字符串必须简单地命名要执行的程序而无需指定任何参数。

subprocess.call(crop, shell=True)

要么:

import shlex
subprocess.call(shlex.split(crop))

Use shell=True if you’re passing a string to subprocess.call.

From docs:

If passing a single string, either shell must be True or else the string must simply name the program to be executed without specifying any arguments.

subprocess.call(crop, shell=True)

or:

import shlex
subprocess.call(shlex.split(crop))

回答 1

无法投票,因此我将重新发布@jfs评论,因为我认为它应该更明显。

@AnneTheAgile:shell = True不是必需的。此外,除非有必要,否则不要使用它(请参阅@valid的注释)。您应该将每个命令行参数作为一个单独的列表项传递,例如,使用[‘command’,’arg 1’,’arg 2’]代替“ command’arg 1”arg 2’”。– jfs 2015年3月3日10:02

Can’t upvote so I’ll repost @jfs comment cause I think it should be more visible.

@AnneTheAgile: shell=True is not required. Moreover you should not use it unless it is necessary (see @ valid’s comment). You should pass each command-line argument as a separate list item instead e.g., use [‘command’, ‘arg 1’, ‘arg 2’] instead of “command ‘arg 1’ ‘arg 2′”. – jfs Mar 3 ’15 at 10:02


回答 2

No such file or directory 如果您尝试将文件参数添加到 Popen双引号中,。

例如:

call_args = ['mv', '"path/to/file with spaces.txt"', 'somewhere']

在这种情况下,您需要删除双引号。

call_args = ['mv', 'path/to/file with spaces.txt', 'somewhere']

No such file or directory can be also raised if you are trying to put a file argument to Popen with double-quotes.

For example:

call_args = ['mv', '"path/to/file with spaces.txt"', 'somewhere']

In this case, you need to remove double-quotes.

call_args = ['mv', 'path/to/file with spaces.txt', 'somewhere']

减少Django的内存使用量。低挂水果?

问题:减少Django的内存使用量。低挂水果?

我的内存使用量随着时间的推移而增加,并且重新启动Django对用户而言并不友好。

我不确定如何分析内存使用情况,但是一些有关如何开始测量的提示将很有用。

我感觉有些简单的步骤可以带来很大的收益。确保将“调试”设置为“假”是显而易见的。

有人可以建议别人吗?在低流量的网站上缓存会带来多少改善?

在这种情况下,我使用mod_python在Apache 2.x下运行。我听说mod_wsgi较为精简,但在此阶段进行切换将非常棘手,除非我知道收益会很大。

编辑:感谢到目前为止的提示。关于如何发现内存用尽的任何建议?是否有任何有关Python内存分析的指南?

同样如前所述,有些事情会使切换到mod_wsgi变得很棘手,因此我想对在朝这个方向努力之前所能获得的收益有所了解。

编辑:卡尔在这里发布了更详细的回复,值得一读:Django部署:减少Apache的开销

编辑: Graham Dumpleton的文章是我在MPM和mod_wsgi相关的东西上找到的最好的文章。我很失望,但是没人能提供有关调试应用程序本身的内存使用情况的任何信息。

最终编辑:好吧,我一直在与Webfaction讨论这个问题,看他们是否可以协助重新编译Apache,这就是他们的话:

“我真的认为切换到MPM Worker + mod_wsgi设置不会给您带来太大的好处。我估计您可能可以节省20MB左右,但可能不超过20MB。”

所以!这使我回到了最初的问题(我仍然不明智)。如何确定问题所在?这是一个众所周知的准则,如果不进行测试以查看需要优化的地方就不会进行优化,但是关于测量Python内存使用情况的教程的方式很少,而针对Django的教程则完全没有。

感谢大家的帮助,但我认为这个问题仍然悬而未决!

另一个最终编辑;-)

我在django-users列表上问了这个,并得到了一些非常有帮助的回复

老实说,有史以来最后一次更新!

这是刚刚发布。可能是迄今为止最好的解决方案:使用Pympler分析Django对象的大小和内存使用情况

My memory usage increases over time and restarting Django is not kind to users.

I am unsure how to go about profiling the memory usage but some tips on how to start measuring would be useful.

I have a feeling that there are some simple steps that could produce big gains. Ensuring ‘debug’ is set to ‘False’ is an obvious biggie.

Can anyone suggest others? How much improvement would caching on low-traffic sites?

In this case I’m running under Apache 2.x with mod_python. I’ve heard mod_wsgi is a bit leaner but it would be tricky to switch at this stage unless I know the gains would be significant.

Edit: Thanks for the tips so far. Any suggestions how to discover what’s using up the memory? Are there any guides to Python memory profiling?

Also as mentioned there’s a few things that will make it tricky to switch to mod_wsgi so I’d like to have some idea of the gains I could expect before ploughing forwards in that direction.

Edit: Carl posted a slightly more detailed reply here that is worth reading: Django Deployment: Cutting Apache’s Overhead

Edit: Graham Dumpleton’s article is the best I’ve found on the MPM and mod_wsgi related stuff. I am rather disappointed that no-one could provide any info on debugging the memory usage in the app itself though.

Final Edit: Well I have been discussing this with Webfaction to see if they could assist with recompiling Apache and this is their word on the matter:

“I really don’t think that you will get much of a benefit by switching to an MPM Worker + mod_wsgi setup. I estimate that you might be able to save around 20MB, but probably not much more than that.”

So! This brings me back to my original question (which I am still none the wiser about). How does one go about identifying where the problems lies? It’s a well known maxim that you don’t optimize without testing to see where you need to optimize but there is very little in the way of tutorials on measuring Python memory usage and none at all specific to Django.

Thanks for everyone’s assistance but I think this question is still open!

Another final edit ;-)

I asked this on the django-users list and got some very helpful replies

Honestly the last update ever!

This was just released. Could be the best solution yet: Profiling Django object size and memory usage with Pympler


回答 0

确保您没有保留对数据的全局引用。这样可以防止python垃圾回收器释放内存。

不要使用mod_python。它在apache中加载一个解释器。如果需要使用apache,请mod_wsgi改用。切换并不困难。这很容易。与django -dead相比,为djangomod_wsgi进行配置更容易mod_python

如果您可以从需求中删除apache,那对您的记忆会更好。spawning似乎是运行python Web应用程序的新的快速可扩展方式。

编辑:我看不到如何切换到mod_wsgi可能是“ 棘手的 ”。这应该是一个非常容易的任务。请详细说明您在使用交换机时遇到的问题。

Make sure you are not keeping global references to data. That prevents the python garbage collector from releasing the memory.

Don’t use mod_python. It loads an interpreter inside apache. If you need to use apache, use mod_wsgi instead. It is not tricky to switch. It is very easy. mod_wsgi is way easier to configure for django than brain-dead mod_python.

If you can remove apache from your requirements, that would be even better to your memory. spawning seems to be the new fast scalable way to run python web applications.

EDIT: I don’t see how switching to mod_wsgi could be “tricky“. It should be a very easy task. Please elaborate on the problem you are having with the switch.


回答 1

如果您在mod_wsgi下运行,并且由于它是WSGI兼容的,则大概是在生成的,您可以使用Dozer查看您的内存使用情况。

在mod_wsgi下,只需将其添加到WSGI脚本的底部:

from dozer import Dozer
application = Dozer(application)

然后将浏览器指向http:// domain / _dozer / index以查看所有内存分配的列表。

我还要添加对mod_wsgi的支持之声。与mod_python相比,它在性能和内存使用方面有很大的不同。Graham Dumpleton对mod_wsgi的支持非常出色,无论是在积极开发方面还是在帮助邮件列表中的人员优化安装方面均如此。curse.com上的David Cramer 发布了一些图表(不幸的是,现在似乎找不到),显示了在该高流量站点上切换到mod_wsgi后cpu和内存使用量的急剧下降。django开发人员中有几个已经切换。说真的,这很容易:)

If you are running under mod_wsgi, and presumably spawning since it is WSGI compliant, you can use Dozer to look at your memory usage.

Under mod_wsgi just add this at the bottom of your WSGI script:

from dozer import Dozer
application = Dozer(application)

Then point your browser at http://domain/_dozer/index to see a list of all your memory allocations.

I’ll also just add my voice of support for mod_wsgi. It makes a world of difference in terms of performance and memory usage over mod_python. Graham Dumpleton’s support for mod_wsgi is outstanding, both in terms of active development and in helping people on the mailing list to optimize their installations. David Cramer at curse.com has posted some charts (which I can’t seem to find now unfortunately) showing the drastic reduction in cpu and memory usage after they switched to mod_wsgi on that high traffic site. Several of the django devs have switched. Seriously, it’s a no-brainer :)


回答 2

这些是我知道的Python内存探查器解决方案(与Django无关):

免责声明:我与后者有一定关系。

各个项目的文档应使您了解如何使用这些工具来分析Python应用程序的内存行为。

以下是一个不错的“战争故事”,还提供了一些有用的指导:

These are the Python memory profiler solutions I’m aware of (not Django related):

Disclaimer: I have a stake in the latter.

The individual project’s documentation should give you an idea of how to use these tools to analyze memory behavior of Python applications.

The following is a nice “war story” that also gives some helpful pointers:


回答 3

此外,检查是否不使用任何已知的泄漏器。由于Unicode处理中的错误,MySQLdb会泄漏Django的大量内存。除此之外,Django Debug Toolbar可能会帮助您跟踪猪。

Additionally, check if you do not use any of known leakers. MySQLdb is known to leak enormous amounts of memory with Django due to bug in unicode handling. Other than that, Django Debug Toolbar might help you to track the hogs.


回答 4

除了不保留对大型数据对象的全局引用之外,还应尽可能避免将大型数据集加载到内存中。

在守护程序模式下切换到mod_wsgi,并使用Apache的worker mpm代替prefork。后面的步骤可以使您以更少的内存开销为更多的并发用户提供服务。

In addition to not keeping around global references to large data objects, try to avoid loading large datasets into memory at all wherever possible.

Switch to mod_wsgi in daemon mode, and use Apache’s worker mpm instead of prefork. This latter step can allow you to serve many more concurrent users with much less memory overhead.


回答 5

Webfaction实际上有一些技巧可以降低Django的内存使用量。

要点:

  • 确保将debug设置为false(您已经知道)。
  • 在您的Apache配置中使用“ ServerLimit”
  • 检查内存中没有大对象
  • 考虑在单独的进程或服务器中提供静态内容。
  • 在您的apache配置中使用“ MaxRequestsPerChild”
  • 找出并了解您正在使用多少内存

Webfaction actually has some tips for keeping django memory usage down.

The major points:

  • Make sure debug is set to false (you already know that).
  • Use “ServerLimit” in your apache config
  • Check that no big objects are being loaded in memory
  • Consider serving static content in a separate process or server.
  • Use “MaxRequestsPerChild” in your apache config
  • Find out and understand how much memory you’re using

回答 6

mod_wsgi的另一个优点:maximum-requestsWSGIDaemonProcess指令中设置一个参数,mod_wsgi会每隔很长时间就重新启动守护进程。对用户来说,应该没有可见的效果,除了第一次刷新新进程时页面加载缓慢之外,因为它将把Django和您的应用程序代码加载到内存中。

但是,即使确实有内存泄漏,也应避免进程过大,而不必中断对用户的服务。

Another plus for mod_wsgi: set a maximum-requests parameter in your WSGIDaemonProcess directive and mod_wsgi will restart the daemon process every so often. There should be no visible effect for the user, other than a slow page load the first time a fresh process is hit, as it’ll be loading Django and your application code into memory.

But even if you do have memory leaks, that should keep the process size from getting too large, without having to interrupt service to your users.


回答 7

这是我用于mod_wsgi的脚本(称为wsgi.py,并放在django项目的根目录中):

import os
import sys
import django.core.handlers.wsgi

from os import path

sys.stdout = open('/dev/null', 'a+')
sys.stderr = open('/dev/null', 'a+')

sys.path.append(path.join(path.dirname(__file__), '..'))

os.environ['DJANGO_SETTINGS_MODULE'] = 'myproject.settings'
application = django.core.handlers.wsgi.WSGIHandler()

根据需要调整myproject.settings和路径。我将所有输出重定向到/ dev / null,因为默认情况下mod_wsgi阻止打印。请改用日志记录。

对于apache:

<VirtualHost *>
   ServerName myhost.com

   ErrorLog /var/log/apache2/error-myhost.log
   CustomLog /var/log/apache2/access-myhost.log common

   DocumentRoot "/var/www"

   WSGIScriptAlias / /path/to/my/wsgi.py

</VirtualHost>

希望这至少应该可以帮助您设置mod_wsgi,以便您查看它是否有所作为。

Here is the script I use for mod_wsgi (called wsgi.py, and put in the root off my django project):

import os
import sys
import django.core.handlers.wsgi

from os import path

sys.stdout = open('/dev/null', 'a+')
sys.stderr = open('/dev/null', 'a+')

sys.path.append(path.join(path.dirname(__file__), '..'))

os.environ['DJANGO_SETTINGS_MODULE'] = 'myproject.settings'
application = django.core.handlers.wsgi.WSGIHandler()

Adjust myproject.settings and the path as needed. I redirect all output to /dev/null since mod_wsgi by default prevents printing. Use logging instead.

For apache:

<VirtualHost *>
   ServerName myhost.com

   ErrorLog /var/log/apache2/error-myhost.log
   CustomLog /var/log/apache2/access-myhost.log common

   DocumentRoot "/var/www"

   WSGIScriptAlias / /path/to/my/wsgi.py

</VirtualHost>

Hopefully this should at least help you set up mod_wsgi so you can see if it makes a difference.


回答 8

缓存:确保已将其刷新。它很容易将某些东西放到缓存中,但是由于缓存引用而永远不会被GC。

Swig’d代码:确保任何内存管理都正确完成,这真的很容易在python中丢失,尤其是在第三方库中

监视:如果可以,获取有关内存使用率和命中率的数据。通常,您会看到某种类型的请求与内存使用之间的关联。

Caches: make sure they’re being flushed. Its easy for something to land in a cache, but never be GC’d because of the cache reference.

Swig’d code: Make sure any memory management is being done correctly, its really easy to miss these in python, especially with third party libraries

Monitoring: If you can, get data about memory usage and hits. Usually you’ll see a correlation between a certain type of request and memory usage.


回答 9

我们偶然发现了Django中包含大型站点地图(10000个项)的错误。似乎Django在生成站点地图时正在尝试将它们全部加载到内存中:http : //code.djangoproject.com/ticket/11572-当Google对该网站进行访问时,有效地终止了Apache进程。

We stumbled over a bug in Django with big sitemaps (10.000 items). Seems Django is trying to load them all in memory when generating the sitemap: http://code.djangoproject.com/ticket/11572 – effectively kills the apache process when Google pays a visit to the site.


创建动态选择字段

问题:创建动态选择字段

我在尝试了解如何在Django中创建动态选择字段时遇到了一些麻烦。我有一个模型设置类似:

class rider(models.Model):
     user = models.ForeignKey(User)
     waypoint = models.ManyToManyField(Waypoint)

class Waypoint(models.Model):
     lat = models.FloatField()
     lng = models.FloatField()

我想做的是创建一个选择字段whos的值是与该骑手相关联的航点(将是登录的人)。

目前,我以如下形式覆盖init:

class waypointForm(forms.Form):
     def __init__(self, *args, **kwargs):
          super(joinTripForm, self).__init__(*args, **kwargs)
          self.fields['waypoints'] = forms.ChoiceField(choices=[ (o.id, str(o)) for o in Waypoint.objects.all()])

但是所有要做的就是列出所有路标,它们与任何特定的骑手都没有关联。有任何想法吗?谢谢。

I’m having some trouble trying to understand how to create a dynamic choice field in django. I have a model set up something like:

class rider(models.Model):
     user = models.ForeignKey(User)
     waypoint = models.ManyToManyField(Waypoint)

class Waypoint(models.Model):
     lat = models.FloatField()
     lng = models.FloatField()

What I’m trying to do is create a choice Field whos values are the waypoints associated with that rider (which would be the person logged in).

Currently I’m overriding init in my forms like so:

class waypointForm(forms.Form):
     def __init__(self, *args, **kwargs):
          super(joinTripForm, self).__init__(*args, **kwargs)
          self.fields['waypoints'] = forms.ChoiceField(choices=[ (o.id, str(o)) for o in Waypoint.objects.all()])

But all that does is list all the waypoints, they’re not associated with any particular rider. Any ideas? Thanks.


回答 0

您可以通过将用户传递给表单init来过滤航点

class waypointForm(forms.Form):
    def __init__(self, user, *args, **kwargs):
        super(waypointForm, self).__init__(*args, **kwargs)
        self.fields['waypoints'] = forms.ChoiceField(
            choices=[(o.id, str(o)) for o in Waypoint.objects.filter(user=user)]
        )

您在启动表单时的视线通过了用户

form = waypointForm(user)

在模型形式的情况下

class waypointForm(forms.ModelForm):
    def __init__(self, user, *args, **kwargs):
        super(waypointForm, self).__init__(*args, **kwargs)
        self.fields['waypoints'] = forms.ModelChoiceField(
            queryset=Waypoint.objects.filter(user=user)
        )

    class Meta:
        model = Waypoint

you can filter the waypoints by passing the user to the form init

class waypointForm(forms.Form):
    def __init__(self, user, *args, **kwargs):
        super(waypointForm, self).__init__(*args, **kwargs)
        self.fields['waypoints'] = forms.ChoiceField(
            choices=[(o.id, str(o)) for o in Waypoint.objects.filter(user=user)]
        )

from your view while initiating the form pass the user

form = waypointForm(user)

in case of model form

class waypointForm(forms.ModelForm):
    def __init__(self, user, *args, **kwargs):
        super(waypointForm, self).__init__(*args, **kwargs)
        self.fields['waypoints'] = forms.ModelChoiceField(
            queryset=Waypoint.objects.filter(user=user)
        )

    class Meta:
        model = Waypoint

回答 1

有针对您的问题的内置解决方案:ModelChoiceField

通常,ModelForm当您需要创建/更改数据库对象时,总是值得尝试使用。在95%的情况下都有效,并且比创建自己的实现要干净得多。

There’s built-in solution for your problem: ModelChoiceField.

Generally, it’s always worth trying to use ModelForm when you need to create/change database objects. Works in 95% of the cases and it’s much cleaner than creating your own implementation.


回答 2

问题是你什么时候做

def __init__(self, user, *args, **kwargs):
    super(waypointForm, self).__init__(*args, **kwargs)
    self.fields['waypoints'] = forms.ChoiceField(choices=[ (o.id, str(o)) for o in Waypoint.objects.filter(user=user)])

在更新请求中,先前的值将丢失!

the problem is when you do

def __init__(self, user, *args, **kwargs):
    super(waypointForm, self).__init__(*args, **kwargs)
    self.fields['waypoints'] = forms.ChoiceField(choices=[ (o.id, str(o)) for o in Waypoint.objects.filter(user=user)])

in a update request, the previous value will lost!


回答 3

在初始化骑乘者实例时将其传递给表单怎么样?

class WaypointForm(forms.Form):
    def __init__(self, rider, *args, **kwargs):
      super(joinTripForm, self).__init__(*args, **kwargs)
      qs = rider.Waypoint_set.all()
      self.fields['waypoints'] = forms.ChoiceField(choices=[(o.id, str(o)) for o in qs])

# In view:
rider = request.user
form = WaypointForm(rider) 

How about passing the rider instance to the form while initializing it?

class WaypointForm(forms.Form):
    def __init__(self, rider, *args, **kwargs):
      super(joinTripForm, self).__init__(*args, **kwargs)
      qs = rider.Waypoint_set.all()
      self.fields['waypoints'] = forms.ChoiceField(choices=[(o.id, str(o)) for o in qs])

# In view:
rider = request.user
form = WaypointForm(rider) 

回答 4

在正常选择字段下的工作解决方案下。我的问题是,每个用户都基于很少的条件有自己的CUSTOM选择字段选项。

class SupportForm(BaseForm):

    affiliated = ChoiceField(required=False, label='Fieldname', choices=[], widget=Select(attrs={'onchange': 'sysAdminCheck();'}))

    def __init__(self, *args, **kwargs):

        self.request = kwargs.pop('request', None)
        grid_id = get_user_from_request(self.request)
        for l in get_all_choices().filter(user=user_id):
            admin = 'y' if l in self.core else 'n'
            choice = (('%s_%s' % (l.name, admin)), ('%s' % l.name))
            self.affiliated_choices.append(choice)
        super(SupportForm, self).__init__(*args, **kwargs)
        self.fields['affiliated'].choices = self.affiliated_choice

Underneath working solution with normal choice field. my problem was that each user have their own CUSTOM choicefield options based on few conditions.

class SupportForm(BaseForm):

    affiliated = ChoiceField(required=False, label='Fieldname', choices=[], widget=Select(attrs={'onchange': 'sysAdminCheck();'}))

    def __init__(self, *args, **kwargs):

        self.request = kwargs.pop('request', None)
        grid_id = get_user_from_request(self.request)
        for l in get_all_choices().filter(user=user_id):
            admin = 'y' if l in self.core else 'n'
            choice = (('%s_%s' % (l.name, admin)), ('%s' % l.name))
            self.affiliated_choices.append(choice)
        super(SupportForm, self).__init__(*args, **kwargs)
        self.fields['affiliated'].choices = self.affiliated_choice

回答 5

正如Breedly和Liang指出的那样,Ashok的解决方案将阻止您在发布表单时获取选择值。

一种稍微不同但仍然不完善的解决方法是:

class waypointForm(forms.Form):
    def __init__(self, user, *args, **kwargs):
        self.base_fields['waypoints'].choices = self._do_the_choicy_thing()
        super(waypointForm, self).__init__(*args, **kwargs)

但是,这可能会导致一些并发问题。

As pointed by Breedly and Liang, Ashok’s solution will prevent you from getting the select value when posting the form.

One slightly different, but still imperfect, way to solve that would be:

class waypointForm(forms.Form):
    def __init__(self, user, *args, **kwargs):
        self.base_fields['waypoints'].choices = self._do_the_choicy_thing()
        super(waypointForm, self).__init__(*args, **kwargs)

This could cause some concurrence problems, though.


回答 6

您可以将字段声明为表单的一流属性,并且可以动态设置选项:

class WaypointForm(forms.Form):
    waypoints = forms.ChoiceField(choices=[])

    def __init__(self, user, *args, **kwargs):
        super().__init__(*args, **kwargs)
        waypoint_choices = [(o.id, str(o)) for o in Waypoint.objects.filter(user=user)]
        self.fields['waypoints'].choices = waypoint_choices

您也可以使用ModelChoiceField并以类似方式在init上设置queryset。

You can declare the field as a first-class attribute of your form and just set choices dynamically:

class WaypointForm(forms.Form):
    waypoints = forms.ChoiceField(choices=[])

    def __init__(self, user, *args, **kwargs):
        super().__init__(*args, **kwargs)
        waypoint_choices = [(o.id, str(o)) for o in Waypoint.objects.filter(user=user)]
        self.fields['waypoints'].choices = waypoint_choices

You can also use a ModelChoiceField and set the queryset on init in a similar manner.


回答 7

如果您需要django admin中的动态选择字段;这适用于Django> = 2.1。

class CarAdminForm(forms.ModelForm):
    class Meta:
        model = Car

    def __init__(self, *args, **kwargs):
        super(CarForm, self).__init__(*args, **kwargs)

        # Now you can make it dynamic.
        choices = (
            ('audi', 'Audi'),
            ('tesla', 'Tesla')
        )

        self.fields.get('car_field').choices = choices

    car_field = forms.ChoiceField(choices=[])

@admin.register(Car)
class CarAdmin(admin.ModelAdmin):
    form = CarAdminForm

希望这可以帮助。

If you need a dynamic choice field in django admin; This works for django >=2.1.

class CarAdminForm(forms.ModelForm):
    class Meta:
        model = Car

    def __init__(self, *args, **kwargs):
        super(CarForm, self).__init__(*args, **kwargs)

        # Now you can make it dynamic.
        choices = (
            ('audi', 'Audi'),
            ('tesla', 'Tesla')
        )

        self.fields.get('car_field').choices = choices

    car_field = forms.ChoiceField(choices=[])

@admin.register(Car)
class CarAdmin(admin.ModelAdmin):
    form = CarAdminForm

Hope this helps.


如何使用.yml文件更新现有的Conda环境

问题:如何使用.yml文件更新现有的Conda环境

如何用另一个.yml文件更新先前的conda环境。在具有多个需求文件(例如)的项目上工作时,这非常有用base.yml, local.yml, production.yml

例如,下面是一个base.yml包含conda-forge,conda和pip软件包的文件:

碱基

name: myenv
channels:
  - conda-forge
dependencies:
  - django=1.10.5
  - pip:
    - django-crispy-forms==1.6.1

实际环境是使用创建的 conda env create -f base.yml

稍后,需要将其他软件包添加到中base.yml。另一个文件,例如local.yml,需要导入这些更新。

先前完成此任务的尝试包括:

创建local.yml具有导入定义的文件:

channels:

dependencies:
  - pip:
    - boto3==1.4.4
imports:
  - requirements/base. 

然后运行命令: conda install -f local.yml

这是行不通的。有什么想法吗?

How can a pre-existing conda environment be updated with another .yml file. This is extremely helpful when working on projects that have multiple requirement files, i.e. base.yml, local.yml, production.yml, etc.

For example, below is a base.yml file has conda-forge, conda, and pip packages:

base.yml

name: myenv
channels:
  - conda-forge
dependencies:
  - django=1.10.5
  - pip:
    - django-crispy-forms==1.6.1

The actual environment is created with: conda env create -f base.yml.

Later on, additional packages need to be added to base.yml. Another file, say local.yml, needs to import those updates.

Previous attempts to accomplish this include:

creating a local.yml file with an import definition:

channels:

dependencies:
  - pip:
    - boto3==1.4.4
imports:
  - requirements/base. 

And then run the command: conda install -f local.yml.

This does not work. Any thoughts?


回答 0

尝试使用conda env update

conda activate myenv
conda env update --file local.yml

或无需激活环境(感谢@NumesSanguis):

conda env update --name myenv --file local.yml

Try using conda env update:

conda activate myenv
conda env update --file local.yml

Or without the need to activate the environment (thanks @NumesSanguis):

conda env update --name myenv --file local.yml

回答 1

建议的答案部分正确。您需要添加–prune选项,以卸载从environment.yml中删除的软件包。正确的命令:

conda env update -f local.yml --prune

The suggested answer is partially correct. You’ll need to add the –prune option to also uninstall packages that were removed from the environment.yml. Correct command:

conda env update -f local.yml --prune

回答 2

alkamid的答案是正确的,但是我发现如果环境已经处于活动状态,则Conda无法安装新的依赖项。停用环境首先可以解决此问题:

source deactivate;
conda env update -f whatever.yml;
source activate my_environment_name; # Must be AFTER the conda env update line!

alkamid’s answer is on the right lines, but I have found that Conda fails to install new dependencies if the environment is already active. Deactivating the environment first resolves this:

source deactivate;
conda env update -f whatever.yml;
source activate my_environment_name; # Must be AFTER the conda env update line!

如何将我的秘密密钥和密码安全地保存在版本控制系统中?

问题:如何将我的秘密密钥和密码安全地保存在版本控制系统中?

我在版本控制系统中保留了重要的设置,例如开发和生产服务器的主机名和端口。但是我知道,将秘密(例如私钥和数据库密码)保存在VCS存储库中是一种不好的做法

但是像其他设置一样,密码似乎应该进行版本控制。那么保持密码版本控制的正确方法什么?

我想这将涉及保持秘密,在自己的“秘密设置”文件,并有文件的加密和版本控制。但是什么技术呢?以及如何正确执行此操作?有没有更好的方法可以完全解决这个问题?


我通常会问这个问题,但是在我的特定实例中,我想使用gitgithub存储Django / Python站点的秘密密钥和密码。

同样,当我使用git推/拉时,理想的解决方案也会做一些神奇的事情-例如,如果加密的密码文件更改了运行的脚本,该脚本会要求输入密码并将其解密到位。


编辑:为清楚起见,我正在询问在哪里存储的生产秘密。

I keep important settings like the hostnames and ports of development and production servers in my version control system. But I know that it’s bad practice to keep secrets (like private keys and database passwords) in a VCS repository.

But passwords–like any other setting–seem like they should be versioned. So what is the proper way to keep passwords version controlled?

I imagine it would involve keeping the secrets in their own “secrets settings” file and having that file encrypted and version controlled. But what technologies? And how to do this properly? Is there a better way entirely to go about it?


I ask the question generally, but in my specific instance I would like to store secret keys and passwords for a Django/Python site using git and github.

Also, an ideal solution would do something magical when I push/pull with git–e.g., if the encrypted passwords file changes a script is run which asks for a password and decrypts it into place.


EDIT: For clarity, I am asking about where to store production secrets.

回答 0

您完全想在保持版本控制的同时加密敏感设置文件是正确的。正如您提到的,最好的解决方案是Git在推送某些敏感文件时透明地对其进行加密,以便在本地(即在具有证书的任何计算机上)可以使用设置文件,但Git或Dropbox或在VC下存储文件无法读取纯文本信息。

推/拉期间的透明加密/解密教程

这个要点https://gist.github.com/873637显示了有关如何将Git的smudge / clean过滤器驱动程序与openssl一起使用的教程,以透明方式加密推送的文件。您只需要进行一些初始设置即可。

工作原理摘要

您基本上将创建一个.gitencrypt包含3个bash脚本的文件夹,

clean_filter_openssl 
smudge_filter_openssl 
diff_filter_openssl 

Git用于解密,加密和支持Git差异。在这些脚本中定义了主密码和盐(已修复!),您必须确保.gitencrypt从未被实际推送。示例clean_filter_openssl脚本:

#!/bin/bash

SALT_FIXED=<your-salt> # 24 or less hex characters
PASS_FIXED=<your-passphrase>

openssl enc -base64 -aes-256-ecb -S $SALT_FIXED -k $PASS_FIXED

smudge_filter_open_ssl和类似diff_filter_oepnssl。参见要点。

您的带有敏感信息的仓库应该有一个.gitattribute文件(未加密并包含在仓库中),该文件引用.gitencrypt目录(该目录包含Git透明地加密/解密项目所需的所有内容),并且该文件存在于本地计算机上。

.gitattribute 内容:

* filter=openssl diff=openssl
[merge]
    renormalize = true

最后,您还需要将以下内容添加到.git/config文件中

[filter "openssl"]
    smudge = ~/.gitencrypt/smudge_filter_openssl
    clean = ~/.gitencrypt/clean_filter_openssl
[diff "openssl"]
    textconv = ~/.gitencrypt/diff_filter_openssl

现在,当您将包含敏感信息的存储库推送到远程存储库时,文件将被透明加密。当您从具有.gitencrypt目录(包含密码)的本地计算机中提取文件时,文件将被透明解密。

笔记

我应该注意,本教程没有描述仅加密敏感设置文件的方法。这将透明地加密推送到远程VC主机的整个存储库,并解密整个存储库,以便在本地对其进行完全解密。为了实现所需的行为,您可以将一个或多个项目的敏感文件放在一个sensitive_settings_repo中。如果您确实需要将敏感文件存储在同一存储库中,则可以研究这种透明加密技术如何与Git子模块http://git-scm.com/book/en/Git-Tools-Submodules一起使用。

如果攻击者可以访问许多加密的存储库/文件,则在理论上使用固定的密码短语可能会导致暴力破解漏洞。海事组织,这种可能性非常低。正如本教程底部提到的那样,不使用固定密码短语将导致不同机器上的本地回购版本始终显示“ git status”已发生更改。

You’re exactly right to want to encrypt your sensitive settings file while still maintaining the file in version control. As you mention, the best solution would be one in which Git will transparently encrypt certain sensitive files when you push them so that locally (i.e. on any machine which has your certificate) you can use the settings file, but Git or Dropbox or whoever is storing your files under VC does not have the ability to read the information in plaintext.

Tutorial on Transparent Encryption/Decryption during Push/Pull

This gist https://gist.github.com/873637 shows a tutorial on how to use the Git’s smudge/clean filter driver with openssl to transparently encrypt pushed files. You just need to do some initial setup.

Summary of How it Works

You’ll basically be creating a .gitencrypt folder containing 3 bash scripts,

clean_filter_openssl 
smudge_filter_openssl 
diff_filter_openssl 

which are used by Git for decryption, encryption, and supporting Git diff. A master passphrase and salt (fixed!) is defined inside these scripts and you MUST ensure that .gitencrypt is never actually pushed. Example clean_filter_openssl script:

#!/bin/bash

SALT_FIXED=<your-salt> # 24 or less hex characters
PASS_FIXED=<your-passphrase>

openssl enc -base64 -aes-256-ecb -S $SALT_FIXED -k $PASS_FIXED

Similar for smudge_filter_open_ssl and diff_filter_oepnssl. See Gist.

Your repo with sensitive information should have a .gitattribute file (unencrypted and included in repo) which references the .gitencrypt directory (which contains everything Git needs to encrypt/decrypt the project transparently) and which is present on your local machine.

.gitattribute contents:

* filter=openssl diff=openssl
[merge]
    renormalize = true

Finally, you will also need to add the following content to your .git/config file

[filter "openssl"]
    smudge = ~/.gitencrypt/smudge_filter_openssl
    clean = ~/.gitencrypt/clean_filter_openssl
[diff "openssl"]
    textconv = ~/.gitencrypt/diff_filter_openssl

Now, when you push the repository containing your sensitive information to a remote repository, the files will be transparently encrypted. When you pull from a local machine which has the .gitencrypt directory (containing your passphrase), the files will be transparently decrypted.

Notes

I should note that this tutorial does not describe a way to only encrypt your sensitive settings file. This will transparently encrypt the entire repository that is pushed to the remote VC host and decrypt the entire repository so it is entirely decrypted locally. To achieve the behavior you want, you could place sensitive files for one or many projects in one sensitive_settings_repo. You could investigate how this transparent encryption technique works with Git submodules http://git-scm.com/book/en/Git-Tools-Submodules if you really need the sensitive files to be in the same repository.

The use of a fixed passphrase could theoretically lead to brute-force vulnerabilities if attackers had access to many encrypted repos/files. IMO, the probability of this is very low. As a note at the bottom of this tutorial mentions, not using a fixed passphrase will result in local versions of a repo on different machines always showing that changes have occurred with ‘git status’.


回答 1

Heroku推动使用环境变量进行设置和密钥:

处理此类config var的传统方法是将它们放在源代码下-放在某种属性文件中。这是一个容易出错的过程,对于经常需要使用应用程序特定配置维护单独的(和私有的)分支的开源应用程序而言,这尤其复杂。

更好的解决方案是使用环境变量,并将键保留在代码之外。在传统主机上或在本地工作,您可以在bashrc中设置环境变量。在Heroku上,您使用config vars。

借助Foreman和.env文件,Heroku提供了令人羡慕的工具链来导出,导入和同步环境变量。


就个人而言,我认为将秘密密钥与代码一起保存是错误的。从根本上说,它与源代码管理不一致,因为密钥是针对代码外部的服务。一个好处是开发人员可以克隆HEAD并运行应用程序而无需进行任何设置。但是,假设开发人员检查了该代码的历史版本。他们的副本将包含去年的数据库密码,因此该应用程序将无法使用今天的数据库。

使用上面的Heroku方法,开发人员可以签出去年的应用程序,使用今天的密钥对其进行配置,然后针对当今的数据库成功运行它。

Heroku pushes the use of environment variables for settings and secret keys:

The traditional approach for handling such config vars is to put them under source – in a properties file of some sort. This is an error-prone process, and is especially complicated for open source apps which often have to maintain separate (and private) branches with app-specific configurations.

A better solution is to use environment variables, and keep the keys out of the code. On a traditional host or working locally you can set environment vars in your bashrc. On Heroku, you use config vars.

With Foreman and .env files Heroku provide an enviable toolchain to export, import and synchronise environment variables.


Personally, I believe it’s wrong to save secret keys alongside code. It’s fundamentally inconsistent with source control, because the keys are for services extrinsic to the the code. The one boon would be that a developer can clone HEAD and run the application without any setup. However, suppose a developer checks out a historic revision of the code. Their copy will include last year’s database password, so the application will fail against today’s database.

With the Heroku method above, a developer can checkout last year’s app, configure it with today’s keys, and run it successfully against today’s database.


回答 2

我认为最干净的方法是使用环境变量。例如,您不必处理.dist文件,生产环境中的项目状态将与本地计算机的状态相同。

我建议阅读“十二要素应用程序 ”的配置章节,如果您有兴趣的话,也阅读其他章节。

The cleanest way in my opinion is to use environment variables. You won’t have to deal with .dist files for example, and the project state on the production environment would be the same as your local machine’s.

I recommend reading The Twelve-Factor App‘s config chapter, the others too if you’re interested.


回答 3

一种选择是将项目绑定的凭据放入加密的容器(TrueCrypt或Keepass)中并推送。

从下面的评论中更新为答案:

有趣的问题顺便说一句。我刚刚发现了这一点:github.com/shadowhand/git-encrypt对于自动加密而言,它看起来很有希望

An option would be to put project-bound credentials into an encrypted container (TrueCrypt or Keepass) and push it.

Update as answer from my comment below:

Interesting question btw. I just found this: github.com/shadowhand/git-encrypt which looks very promising for automatic encryption


回答 4

我建议为此使用配置文件,而不要对其进行版本控制。

但是,您可以版本文件的示例。

我看不到共享开发设置的任何问题。根据定义,它不应包含任何有价值的数据。

I suggest using configuration files for that and to not version them.

You can however version examples of the files.

I don’t see any problem of sharing development settings. By definition it should contain no valuable data.


回答 5

BlackBox是由StackExchange最近发布的,虽然我尚未使用它,但它似乎可以完全解决问题并支持此问题中要求的功能。

https://github.com/StackExchange/blackbox的描述中:

将机密安全存储在VCS仓库中(即Git或Mercurial)。这些命令使您可以轻松地对存储库中的特定文件进行GPG加密,以便在存储库中对它们进行“静态加密”。但是,使用脚本可以轻松地在需要查看或编辑脚本时对其进行解密,并可以将其解密以用于生产。

BlackBox was recently released by StackExchange and while I have yet to use it, it seems to exactly address the problems and support the features requested in this question.

From the description on https://github.com/StackExchange/blackbox:

Safely store secrets in a VCS repo (i.e. Git or Mercurial). These commands make it easy for you to GPG encrypt specific files in a repo so they are “encrypted at rest” in your repository. However, the scripts make it easy to decrypt them when you need to view or edit them, and decrypt them for for use in production.


回答 6

自从问了这个问题之后,我就确定了一个解决方案,该解决方案是在与一小群人一起开发小型应用程序时使用的。

git-crypt

git-crypt使用GPG对文件名进行匹配的透明加密。例如,如果您添加到.gitattributes文件中…

*.secret.* filter=git-crypt diff=git-crypt

…然后,像这样的文件config.secret.json将始终通过加密方式推送到远程存储库,但在本地文件系统上保持未加密状态。

如果我想向您的存储库添加一个新的GPG密钥(一个人),可以解密受保护的文件,请运行git-crypt add-gpg-user <gpg_user_key>。这将创建一个新的提交。新用户将能够解密后续提交。

Since asking this question I have settled on a solution, which I use when developing small application with a small team of people.

git-crypt

git-crypt uses GPG to transparently encrypt files when their names match certain patterns. For intance, if you add to your .gitattributes file…

*.secret.* filter=git-crypt diff=git-crypt

…then a file like config.secret.json will always be pushed to remote repos with encryption, but remain unencrypted on your local file system.

If I want to add a new GPG key (a person) to your repo which can decrypt the protected files then run git-crypt add-gpg-user <gpg_user_key>. This creates a new commit. The new user will be able to decrypt subsequent commits.


回答 7

我通常会问这个问题,但是在我的特定实例中,我想使用git和github存储Django / Python站点的秘密密钥和密码。

不,只是不要,即使这是您的私人存储库,并且您从不打算共享它,也不要。

您应该创建一个local_settings.py,将其放在VCS上忽略,然后在settings.py中执行类似的操作

from local_settings import DATABASES, SECRET_KEY
DATABASES = DATABASES

SECRET_KEY = SECRET_KEY

如果您的机密设置用途广泛,我很想说您做错了

I ask the question generally, but in my specific instance I would like to store secret keys and passwords for a Django/Python site using git and github.

No, just don’t, even if it’s your private repo and you never intend to share it, don’t.

You should create a local_settings.py put it on VCS ignore and in your settings.py do something like

from local_settings import DATABASES, SECRET_KEY
DATABASES = DATABASES

SECRET_KEY = SECRET_KEY

If your secrets settings are that versatile, I am eager to say you’re doing something wrong


回答 8

编辑:我假设您想跟踪以前的密码版本-例如,对于防止密码重用等的脚本。

我认为GnuPG是最好的方法-已经在一个与git相关的项目(git-annex)中用于加密存储在云服务上的存储库内容。GnuPG(gnu pgp)提供了非常强大的基于密钥的加密。

  1. 您将密钥保留在本地计算机上。
  2. 您将’mypassword’添加到忽略的文件。
  3. 在pre-commit挂钩上,您将mypassword文件加密为git跟踪的mypassword.gpg文件,并将其添加到提交中。
  4. 在合并后钩子上,您只需将mypassword.gpg解密为mypassword。

现在,如果您的“ mypassword”文件未更改,则将使用相同的密文对其进行加密,并且不会将其添加到索引中(无冗余)。稍加修改mypassword会导致密文截然不同,并且登台区域中的mypassword.gpg与存储库中的密文有很大不同,因此将被添加到提交中。即使攻击者掌握了您的gpg密钥,他仍然需要暴力破解密码。如果攻击者可以使用密文访问远程存储库,则他可以比较一堆密文,但是它们的数量不足以给他带来任何不可忽视的优势。

稍后,您可以使用.gitattributes为您的密码退出git diff提供即时解密。

您也可以为不同类型的密码等设置单独的密钥。

EDIT: I assume you want to keep track of your previous passwords versions – say, for a script that would prevent password reusing etc.

I think GnuPG is the best way to go – it’s already used in one git-related project (git-annex) to encrypt repository contents stored on cloud services. GnuPG (gnu pgp) provides a very strong key-based encryption.

  1. You keep a key on your local machine.
  2. You add ‘mypassword’ to ignored files.
  3. On pre-commit hook you encrypt the mypassword file into the mypassword.gpg file tracked by git and add it to the commit.
  4. On post-merge hook you just decrypt mypassword.gpg into mypassword.

Now if your ‘mypassword’ file did not change then encrypting it will result with same ciphertext and it won’t be added to the index (no redundancy). Slightest modification of mypassword results in radically different ciphertext and mypassword.gpg in staging area differs a lot from the one in repository, thus will be added to the commit. Even if the attacker gets a hold of your gpg key he still needs to bruteforce the password. If the attacker gets an access to remote repository with ciphertext he can compare a bunch of ciphertexts, but their number won’t be sufficient to give him any non-negligible advantage.

Later on you can use .gitattributes to provide an on-the-fly decryption for quit git diff of your password.

Also you can have separate keys for different types of passwords etc.


回答 9

通常,我将密码分隔为配置文件。并使其成为dist。

/yourapp
    main.py
    default.cfg.dist

当我跑步时main.py,输入真实密码default.cfg该副本中。

ps。当您使用git或hg时。您可以忽略*.cfg要制作的文件.gitignore.hgignore

Usually, i seperate password as a config file. and make them dist.

/yourapp
    main.py
    default.cfg.dist

And when i run main.py, put the real password in default.cfg that copied.

ps. when you work with git or hg. you can ignore *.cfg files to make .gitignore or .hgignore


回答 10

提供一种方法来覆盖配置

这是管理您签入的配置的一组合理默认值的最佳方法,而无需完成配置或包含主机名和凭据之类的内容。有几种方法可以覆盖默认配置。

环境变量(如其他人已经提到的)是做到这一点的一种方法。

最好的方法是寻找一个覆盖默认配置值的外部配置文件。这使您可以通过诸如Chef,Puppet或Cfengine之类的配置管理系统来管理外部配置。配置管理是与代码库分开进行配置管理的标准答案,因此您无需发布即可在单个主机或一组主机上更新配置。

仅供参考:加密凭证并非总是最佳做法,尤其是在资源有限的地方。可能情况是,加密凭据不会为您带来额外的风险缓解,而只会增加不必要的复杂性。在做出决定之前,请确保您进行了正确的分析。

Provide a way to override the config

This is the best way to manage a set of sane defaults for the config you checkin without requiring the config be complete, or contain things like hostnames and credentials. There are a few ways to override default configs.

Environment variables (as others have already mentioned) are one way of doing it.

The best way is to look for an external config file that overrides the default config values. This allows you to manage the external configs via a configuration management system like Chef, Puppet or Cfengine. Configuration management is the standard answer for the management of configs separate from the codebase so you don’t have to do a release to update the config on a single host or a group of hosts.

FYI: Encrypting creds is not always a best practice, especially in a place with limited resources. It may be the case that encrypting creds will gain you no additional risk mitigation and simply add an unnecessary layer of complexity. Make sure you do the proper analysis before making a decision.


回答 11

使用例如GPG加密密码文件。将密钥添加到本地计算机和服务器上。解密文件并将其放在您的repo文件夹之外。

我使用homefolder中的passwords.conf。在每次部署中,此文件都会更新。

Encrypt the passwords file, using for example GPG. Add the keys on your local machine and on your server. Decrypt the file and put it outside your repo folders.

I use a passwords.conf, located in my homefolder. On every deploy this file gets updated.


回答 12

不可以,私钥和密码不属于版本控制。当大多数情况下并非所有人都应该有权访问这些服务时,没有理由让每个人都拥有对存储库的读取访问权的负担,因为他们知道生产中使用的敏感服务凭证。

从Django 1.4开始,您的Django项目现在附带了project.wsgi定义application对象的模块,这是开始强制使用a的理想场所project.local包含特定于站点的配置设置模块。

该设置模块从版本控制中被忽略,但是在将项目实例作为WSGI应用程序运行时(在生产环境中通常需要)它必须存在。它应该是这样的:

import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.local")

# This application object is used by the development server
# as well as any WSGI server configured to use this file.
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

现在,您可以拥有一个local.py可以配置所有者和组的模块,以便只有授权人员和Django进程才能读取文件的内容。

No, private keys and passwords do not fall under revision control. There is no reason to burden everyone with read access to your repository with knowing sensitive service credentials used in production, when most likely not all of them should have access to those services.

Starting with Django 1.4, your Django projects now ship with a project.wsgi module that defines the application object and it’s a perfect place to start enforcing the use of a project.local settings module that contains site-specific configurations.

This settings module is ignored from revision control, but it’s presence is required when running your project instance as a WSGI application, typical for production environments. This is how it should look like:

import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.local")

# This application object is used by the development server
# as well as any WSGI server configured to use this file.
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

Now you can have a local.py module who’s owner and group can be configured so that only authorized personnel and the Django processes can read the file’s contents.


回答 13

如果您需要VCS作为秘密,则至少应将其保存在与实际代码分开的第二个存储库中。因此,您可以授予团队成员访问源代码存储库的权限,而他们不会看到您的凭据。此外,将此存储库托管在其他位置(例如,在具有加密文件系统的您自己的服务器上,而不是在github上),并将其检出到生产系统中,可以使用git-submodule之类的东西。

If you need VCS for your secrets you should at least keep them in a second repository seperated from you actual code. So you can give your team members access to the source code repository and they won’t see your credentials. Furthermore host this repository somewhere else (eg. on your own server with an encrypted filesystem, not on github) and for checking it out to the production system you could use something like git-submodule.


回答 14

另一种方法可能是完全避免在版本控制系统中保存机密,而是使用诸如hashicorp的Vault之类的工具,该工具是具有密钥滚动和审核,具有API和嵌入式加密功能的秘密存储。

Another approach could be to completely avoid saving secrets in version control systems and instead use a tool like vault from hashicorp, a secret storage with key rolling and auditing, with an API and embedded encryption.


回答 15

这是我的工作:

  • 将所有秘密保留为$ HOME / .bashrc来源的$ HOME / .secrets(go-r权限)中的env vars(这样,如果您在某人面前打开.bashrc,他们将看不到这些秘密)
  • 配置文件作为模板存储在VCS中,例如config.properties存储为config.properties.tmpl
  • 模板文件包含机密的占位符,例如:

    my.password = ## MY_PASSWORD ##

  • 在应用程序部署中,将运行脚本,该脚本将模板文件转换为目标文件,并用环境变量的值替换占位符,例如将## MY_PASSWORD ##更改为$ MY_PASSWORD的值。

This is what I do:

  • Keep all secrets as env vars in $HOME/.secrets (go-r perms) that $HOME/.bashrc sources (this way if you open .bashrc in front of someone, they won’t see the secrets)
  • Configuration files are stored in VCS as templates, such as config.properties stored as config.properties.tmpl
  • The template files contain a placeholder for the secret, such as:

    my.password=##MY_PASSWORD##

  • On application deployment, script is ran that transforms the template file into the target file, replacing placeholders with values of environment variables, such as changing ##MY_PASSWORD## to the value of $MY_PASSWORD.


回答 16

如果您的系统提供了此功能,则可以使用EncFS。因此,您可以将加密的数据保留为存储库的子文件夹,同时为应用程序提供对已装入数据的解密视图。由于加密是透明的,因此在拉或推上不需要任何特殊操作。

但是,它将需要挂载EncFS文件夹,这可以由您的应用程序根据存储在版本化文件夹之外的其他位置的密码(例如,环境变量)来完成。

You could use EncFS if your system provides that. Thus you could keep your encrypted data as a subfolder of your repository, while providing your application a decrypted view to the data mounted aside. As the encryption is transparent, no special operations are needed on pull or push.

It would however need to mount the EncFS folders, which could be done by your application based on an password stored elsewhere outside the versioned folders (eg. environment variables).