标签归档:Django

Django的Meta类如何工作?

问题:Django的Meta类如何工作?

我正在使用Django,它允许人们使用来向类添加额外的参数class Meta

class FooModel(models.Model):
    ...
    class Meta:
        ...

我在Python文档中发现的唯一东西是:

class FooMetaClass(type):
    ...

class FooClass:
    __metaclass__ = FooMetaClass

但是,我认为这不是一回事。

I am using Django which allows people to add extra parameters to a class by using class Meta.

class FooModel(models.Model):
    ...
    class Meta:
        ...

The only thing I found in Python’s documentation was:

class FooMetaClass(type):
    ...

class FooClass:
    __metaclass__ = FooMetaClass

However, I don’t think this is the same thing.


回答 0

您在问有关两个不同问题的问题:

  1. MetaDjango模型中的内部类

    这只是一个类容器,在模型上附加了一些选项(元数据)。它定义了诸如可用权限,关联的数据库表名称,模型是否抽象,名称的单复数形式等内容。

    简短说明在这里:Django文档:模型:Meta选项

    可用的元选项列表在此处:Django文档:Model Meta options

    对于最新版本的Django:Django docs:Model Meta options

  2. Python中的元类

    最好的描述在这里:Python中的元类什么?

You are asking a question about two different things:

  1. Meta inner class in Django models:

    This is just a class container with some options (metadata) attached to the model. It defines such things as available permissions, associated database table name, whether the model is abstract or not, singular and plural versions of the name etc.

    Short explanation is here: Django docs: Models: Meta options

    List of available meta options is here: Django docs: Model Meta options

    For latest version of Django: Django docs: Model Meta options

  2. Metaclass in Python:

    The best description is here: What are metaclasses in Python?


回答 1

扩展上面的Tadeck的Django回答,在Django中使用’class Meta:’也是普通的Python。

内部类是在类实例之间共享数据的方便的命名空间(因此,名称为“ metadata”的元数据,但是您可以随意命名)。在Django中,它通常是只读的配置内容,没有什么可以阻止您对其进行更改:

In [1]: class Foo(object):
   ...:     class Meta:
   ...:         metaVal = 1
   ...:         
In [2]: f1 = Foo()
In [3]: f2 = Foo()
In [4]: f1.Meta.metaVal
Out[4]: 1
In [5]: f2.Meta.metaVal = 2
In [6]: f1.Meta.metaVal
Out[6]: 2
In [7]: Foo.Meta.metaVal
Out[7]: 2

您也可以直接在Django中探索它,例如:

In [1]: from django.contrib.auth.models import User
In [2]: User.Meta
Out[2]: django.contrib.auth.models.Meta
In [3]: User.Meta.__dict__
Out[3]: 
{'__doc__': None,
 '__module__': 'django.contrib.auth.models',
 'abstract': False,
 'verbose_name': <django.utils.functional.__proxy__ at 0x26a6610>,
 'verbose_name_plural': <django.utils.functional.__proxy__ at 0x26a6650>}

但是,在Django中,您更可能希望探索创建模型时由模型创建_metaOptions对象的属性metaclass。在这里,您将找到所有Django类“元”信息。在Django中,Meta仅用于将信息传递到创建_meta Options对象的过程中。

Extending on Tadeck’s Django answer above, the use of ‘class Meta:’ in Django is just normal Python too.

The internal class is a convenient namespace for shared data among the class instances (hence the name Meta for ‘metadata’ but you can call it anything you like). While in Django it’s generally read-only configuration stuff, there is nothing to stop you changing it:

In [1]: class Foo(object):
   ...:     class Meta:
   ...:         metaVal = 1
   ...:         
In [2]: f1 = Foo()
In [3]: f2 = Foo()
In [4]: f1.Meta.metaVal
Out[4]: 1
In [5]: f2.Meta.metaVal = 2
In [6]: f1.Meta.metaVal
Out[6]: 2
In [7]: Foo.Meta.metaVal
Out[7]: 2

You can explore it in Django directly too e.g:

In [1]: from django.contrib.auth.models import User
In [2]: User.Meta
Out[2]: django.contrib.auth.models.Meta
In [3]: User.Meta.__dict__
Out[3]: 
{'__doc__': None,
 '__module__': 'django.contrib.auth.models',
 'abstract': False,
 'verbose_name': <django.utils.functional.__proxy__ at 0x26a6610>,
 'verbose_name_plural': <django.utils.functional.__proxy__ at 0x26a6650>}

However, in Django you are more likely to want to explore the _meta attribute which is an Options object created by the model metaclass when a model is created. That is where you’ll find all of the Django class ‘meta’ information. In Django, Meta is just used to pass information into the process of creating the _meta Options object.


回答 2

Django的Model类专门处理具有名为Metawhich 的属性的类。这不是一般的Python。

Python元类完全不同。

Django’s Model class specifically handles having an attribute named Meta which is a class. It’s not a general Python thing.

Python metaclasses are completely different.


回答 3

声称Django模型Meta和元类“完全不同”的答案具有误导性。

Django模型类对象(也就是说,代表类定义本身的对象;是的,类也是对象)的构造实际上是由称为的元类控制的ModelBase,您可以在此处看到该代码:

https://github.com/django/django/blob/master/django/db/models/base.py#L61

要做的事情之一ModelBase就是_meta在每个Django模型上创建属性,该模型包含验证机制,字段详细信息,保存逻辑等。在此操作期间,将Meta在该过程中读取和使用模型的内部类中指定的内容。

因此,虽然是的,Meta但从某种意义上说,元类是不同的“事物”,但在Django模型构建的机制内,它们是密切相关的;了解它们如何协同工作将一次加深您的见解。

这可能是有用的信息来源,可以更好地了解Django模型如何使用元类。

https://code.djangoproject.com/wiki/DevModelCreation

如果您想更好地了解对象的总体工作原理,这也可能会有所帮助。

https://docs.python.org/3/reference/datamodel.html

Answers that claim Django model’s Meta and metaclasses are “completely different” are misleading answers.

The construction of Django model class objects, that is to say the object that stands for the class definition itself (yes, classes are also objects), are indeed controlled by a metaclass called ModelBase, and you can see that code here.

And one of the things that ModelBase does is to create the _meta attribute on every Django model which contains validation machinery, field details, save logic and so forth. During this operation, the stuff that is specified in the model’s inner Meta class is read and used within that process.

So, while yes, in a sense Meta and metaclasses are different ‘things’, within the mechanics of Django model construction they are intimately related; understanding how they work together will deepen your insight into both at once.

This might be a helpful source of information to better understand how Django models employ metaclasses.

https://code.djangoproject.com/wiki/DevModelCreation

And this might help too if you want to better understand how objects work in general.

https://docs.python.org/3/reference/datamodel.html


回答 4

内部元类文档django Model元数据的文档是“任何不是字段的东西”,例如排序选项(排序),数据库表名称(db_table)或人类可读的单数和复数名称(verbose_name和verbose_name_plural)。不需要任何操作,并且将Meta类添加到模型是完全可选的。 https://docs.djangoproject.com/en/dev/topics/db/models/#meta-options

Inner Meta Class Document This document of django Model metadata is “anything that’s not a field”, such as ordering options (ordering), database table name (db_table), or human-readable singular and plural names (verbose_name and verbose_name_plural). None are required, and adding class Meta to a model is completely optional. https://docs.djangoproject.com/en/dev/topics/db/models/#meta-options


回答 5

在Django中,它充当配置类,并将配置数据保存在一个地方!

In Django, it acts as a configuration class and keeps the configuration data in one place!!


django导入错误-没有名为core.management的模块

问题:django导入错误-没有名为core.management的模块

好的,我看到很多这些错误。我已经尝试了所有我想做的事情,但是还没有弄清楚。

我正在开发运行python 2.5和Django 1.3的开发服务器。在解压缩tar.gz下载文件后,使用python setup.py install安装了Django 1.3。

一切正常,我很少需要运行,manage.py但是正在尝试使用新的staticfiles应用程序,并且遇到了问题。

python manage.py collectstatic
Traceback (most recent call last):
  File "manage.py", line 2, in <module>
    from django.core.management import execute_manager
ImportError: No module named core.management

好的,所以我有PATH问题。

Django安装中,我再次检查site-packages目录。

python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"
/usr/lib/python2.5/site-packages

好的,让我们检查一下我拥有的东西,echo $ PYTHON_PATH为空,所以我将其设置为

export PYTHON_PATH=/usr/lib/python2.5/site-packages/django

仍然没有运气。让我们检查sys.path怎么说

>>> import sys
>>> print sys.path
['', '/usr/lib/python2.5', '/usr/lib/python2.5/plat-linux2', '/usr/lib/python2.5/lib-tk', '/usr/lib/python2.5/lib-dynload', '/usr/local/lib/python2.5/site-packages', '/usr/lib/python2.5/site-packages', '/usr/lib/python2.5/site-packages/PIL', '/usr/lib/python2.5/site-packages/django', '/var/lib/python-support/python2.5']

路径在那里,我什至用内容创建了/usr/lib/python2.5/site-packages/django.pth

cat /usr/lib/python2.5/site-packages/django.pth 
/usr/lib/python2.5/site-packages/django/

有人知道这里发生了什么吗?

我在通往的道路上发现了一个符号链接,但没有出现新的错误。

python manage.py collectstatic
Traceback (most recent call last):
  File "manage.py", line 14, in <module>
    execute_manager(settings)
  File "/usr/lib/python2.5/site-packages/django/core/management/__init__.py", line 438, in execute_manager
    utility.execute()
  File "/usr/lib/python2.5/site-packages/django/core/management/__init__.py", line 349, in execute
    version=get_version(),
  File "/usr/lib/python2.5/site-packages/django/__init__.py", line 12, in get_version
    from django.utils.version import get_svn_revision
ImportError: No module named utils.version

我还尝试创建一个新项目,以查看是否存在任何问题,并得到相同的utils.version错误。

侧面节点:#django的Unode帮助了我一点,在同一台计算机上设置了virtualenv并克服了错误,因此仍不确定此处的实际安装如何,但是似乎不在django项目中,而在django中/ python安装。

Ok, I see plenty of these errors around. I have tried everything I know to do and have yet to figure this out.

I am working on a development server running python 2.5 and Django 1.3. Django 1.3 was installed using python setup.py install after unpacking the tar.gz download.

All works well, I seldom have the need to run manage.py but am trying to use the new staticfiles app and am running into problems.

python manage.py collectstatic
Traceback (most recent call last):
  File "manage.py", line 2, in <module>
    from django.core.management import execute_manager
ImportError: No module named core.management

Ok, so I have PATH issue.

From Django install I double check my site-packages directory.

python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"
/usr/lib/python2.5/site-packages

Ok, let’s check out what I have, echo $PYTHON_PATH was empty, so I set it

export PYTHON_PATH=/usr/lib/python2.5/site-packages/django

Still no luck. Lets check what sys.path has to say

>>> import sys
>>> print sys.path
['', '/usr/lib/python2.5', '/usr/lib/python2.5/plat-linux2', '/usr/lib/python2.5/lib-tk', '/usr/lib/python2.5/lib-dynload', '/usr/local/lib/python2.5/site-packages', '/usr/lib/python2.5/site-packages', '/usr/lib/python2.5/site-packages/PIL', '/usr/lib/python2.5/site-packages/django', '/var/lib/python-support/python2.5']

path is there, I even created /usr/lib/python2.5/site-packages/django.pth with contents

cat /usr/lib/python2.5/site-packages/django.pth 
/usr/lib/python2.5/site-packages/django/

Anyone got an clues to what is going on here?

I found a symlink further up the path that was getting in the way, but no on to a new error.

python manage.py collectstatic
Traceback (most recent call last):
  File "manage.py", line 14, in <module>
    execute_manager(settings)
  File "/usr/lib/python2.5/site-packages/django/core/management/__init__.py", line 438, in execute_manager
    utility.execute()
  File "/usr/lib/python2.5/site-packages/django/core/management/__init__.py", line 349, in execute
    version=get_version(),
  File "/usr/lib/python2.5/site-packages/django/__init__.py", line 12, in get_version
    from django.utils.version import get_svn_revision
ImportError: No module named utils.version

I also tried creating a new project to see if there were any issues there and get the same utils.version error.

Side node: Unode from #django helped me a bit, set up virtualenv on same machine and got past the errors so still not sure what is up with this actual install here, but it seems to not be in the django projects but in the django/python install.


回答 0

如果像我一样,您正在virtualenv中运行django,并收到此错误,请查看您的manage.py。第一行应定义用于运行脚本的python可执行文件。这应该是您的virtualenv的python的路径,但这是/ usr / bin / python之类的错误,它不是相同的路径,并且将使用全局python环境(并且缺少软件包)。只需将路径更改为virtualenv中python可执行文件的路径即可。

您也可以用替换您的shebang线#!/usr/bin/env python。如果您首先激活了virtualenv,这应该使用适当的python环境和解释器(我假设您知道如何执行此操作)。

If, like me, you are running your django in a virtualenv, and getting this error, look at your manage.py. The first line should define the python executable used to run the script. This should be the path to your virtualenv’s python, but it is something wrong like /usr/bin/python, which is not the same path and will use the global python environment (and packages will be missing). Just change the path into the path to the python executable in your virtualenv.

You can also replace your shebang line with #!/usr/bin/env python. This should use the proper python environment and interpreter provided that you activate your virtualenv first (I assume you know how to do this).


回答 1

如果您在virtualenv中,则需要先激活它,然后才能运行./manage.py’command’

source path/to/your/virtualenv/bin/activate

如果您在.bash_profile或.bashrc中配置workon

workon yourvirtualenvname

*请不要编辑您的manage.py文件,可能不是正确的方法,并且可能会给您将来的错误

If you are in a virtualenv you need to activate it before you can run ./manage.py ‘command’

source path/to/your/virtualenv/bin/activate

if you config workon in .bash_profile or .bashrc

workon yourvirtualenvname

*please dont edit your manage.py file maybe works by isnt the correct way and could give you future errors


回答 2

我遇到了同样的问题,因为我以超级用户身份安装Django,因此不在我的virtualenv中。你不应该做sudo pip install Django

而是以这种方式安装它:

$ source ./bin/activate
$ pip install Django

I had the same problem because I was installing Django as a super user, thus not in my virtualenv. You should not do sudo pip install Django

Instead, install it this way:

$ source ./bin/activate
$ pip install Django

回答 3

请用pip重新安装django:

sudo pip install --upgrade django==1.3

(将1.3替换为您的Django版本)

Please, reinstall django with pip:

sudo pip install --upgrade django==1.3

(Replace 1.3 to your django version)


回答 4

众所周知,这是一个路径问题。

我的自定义软件包的基础与/ etc / profile中设置的目录共享一个名称。软件包位于Web服务器的其他位置。因此,我从$ PYTHONPATH中删除了令人反感的条目,并且一切顺利!

谢谢您的帮助。

As known this was a path issue.

the base of my custom packages shared a name with a directory set in a /etc/profile. The packages were in a different location however for the webserver. So I removed the offending entries from my $PYTHONPATH and was good to go!

Thanks for the help.


回答 5

此问题的另一个可能原因是,您的操作系统默认情况下运行python3。

您必须明确地执行以下操作: python2 manage.py

或您需要编辑的shebang manage.py,如下所示:

#!/usr/bin/env python2

或者,如果您使用的是python3:

#!/usr/bin/env python3

Another possible reason for this problem is that your OS runs python3 by default.

Either you have to explicitly do: python2 manage.py

or you need to edit the shebang of manage.py, like so:

#!/usr/bin/env python2

or if you are using python3:

#!/usr/bin/env python3

回答 6

而试图在运行嵌入式系统(当然使用Django的)我有这个错误树莓派2(并且不是一个VM

运行此:

 sudo pip install Django

搞定了!

  • 以防万一使用Raspbian / Jessie的人得到了这个

I had this error while trying to run an embedded system (using django of course) on a Raspberry Pi 2 (and not a VM)

Running this:

 sudo pip install Django

Made the trick!

  • just in case a fellow using Raspbian/Jessie gets this

回答 7

您可能正在使用virtualenvwrapper。不要忘记通过运行以下命令来选择您的环境:

$ workon env_name

You are probably using virtualenvwrapper. Don’t forget to select your enviroment by running:

$ workon env_name

回答 8

对我来说,我的服务器使用的是Python 2.4。我只是查找了安装在服务器上的Python 2.7,并创建了一个别名。

alias python=python2.7

如果您需要了解更多信息,我在这里找到了解决方案

For me, my server was using Python 2.4. I simply looked up Python 2.7, which was installed on my server, and created an alias.

alias python=python2.7

If you need to know more, I found the solution here


回答 9

尝试创建新应用时遇到了同样的问题。如果您编写python manage.py startapp myapp,则它将查找usr / bin / python。但是您需要这个“ python ”,它位于虚拟环境路径的/ bin目录中。我通过提及virtualenv的python路径来解决此问题,如下所示:

<env path>/bin/python manage.py startapp myapp

I was getting the same problem while I trying to create a new app. If you write python manage.py startapp myapp, then it looks for usr/bin/python. But you need this “python” which is located in /bin directory of your virtual env path. I solved this by mentioning the virtualenv’s python path just like this:

<env path>/bin/python manage.py startapp myapp

回答 10

尝试更改您的manage.py的第一行。

更改

#!/usr/bin/python

通过

#!/usr/bin/env python

Try change your first line of manage.py.

Change

#!/usr/bin/python

by

#!/usr/bin/env python

回答 11

python3 manage.py runserver

检查Python版本

python3 manage.py runserver

Check version of Python


回答 12

解决了!!!

在寻找了年龄并尝试了所有其他不可行的建议之后,我终于找到了适合我的设置的解决方案。

我的设置/方案:

  • Windows,Python27
  • 我的Django项目通过svn签出
  • 在新文件夹中运行python manage.py runserver时,出现导入错误
  • python manage.py runserver曾经在原始文件夹(我会提交更改)中使用,直到删除它为止

删除manage.py同一目录中名为django的所有文件夹

没错…删除文件夹“ django”后,该文件夹仅包含__init__.py文件…我可以再次运行服务器!

不知道为什么

Solved it!!!

After searching for ages and trying all these other suggestions which didn’t work, I finally found the solution for my setup.

My setup/scenario:

  • Windows, Python27
  • My django project is checked out via svn
  • when running python manage.py runserver in the new folder, I got the import error
  • python manage.py runserver used to work in the original folder (which I would commit changes from) until I deleted it

Solution

Remove any the folder named django in the same directory of manage.py

Thats right…as soon as I removed the folder “django” which only contained a __init__.py file…I could run the server again!

Have no idea why though


回答 13

对于使用Django 1.6或更高版本的用户,请注意execute_manager已删除。有张贴在第二SO答案的解决方案在这里

For those of you using Django 1.6 or newer, note that execute_manager was removed. There is a solution posted in the second SO answer here.


回答 14

将python python路径存储在一个变量中并执行。

python_path= `which python` 
$python_path manage.py runserver

Store the python python path in a variable and execute.This would include the otherwise missing packages.

python_path= `which python` 
$python_path manage.py runserver

回答 15

我有一个类似的问题。PyCharm无法运行服务器,但是我可以从命令行运行它。我尝试使用哪个python,然后确保PyCharm是相同的解释器,然后一切正常。

I had a similar problem. PyCharm couldn’t run the server but I could run it from the command line. I tried which python and then made sure that PyCharm was same interpreter and then everything worked OK.


回答 16

当未安装django时,通常会发生此错误。如果您已经安装了django但仍然遇到相同的错误,则必须在单独的虚拟环境中工作。您还需要在虚拟环境中安装django。当您在虚拟机的外壳中时,只需执行以下操作:

pip安装Django

这是因为虚拟机具有单独的文件系统,即使将Django安装在您的系统上,它也无法识别。

This error usually occurs when django is not installed. If you have already installed django but still getting the same error, then you must be working in separate virtual environment. You need to install django in your virtual environmnent as well. When you are in shell of virtual machine simply do this:

pip install django

It is because virtual machine has separate file system, it doesn’t recognize django even if it is installed on your system.


回答 17

我通过将#PATH =“ $ VIRTUAL_ENV / bin:$ PATH”更改为PATH =“ $ PATH:$ VIRTUAL_ENV / bin”来解决此问题,由于对我不明显的原因,virtualenv目录中的python可执行文件看不到Django,但安装的Python呢。

I fixed this problem by changing #PATH=”$VIRTUAL_ENV/bin:$PATH” to PATH=”$PATH:$VIRTUAL_ENV/bin” For reasons not obvious to me the python executable in the virtualenv dir does not see django but the normally installed python does.


回答 18

================================解决方案=============== =========================

首先转到:virtualenv

通过运行以下命令:source bin / activate

并安装django,因为您收到与“ import django”相关的错误:

pip install django

然后运行:

python manage.py runserver

(注意:请将“ runserver”更改为要运行的程序名称)

对于同一问题,它在我的情况下有效。=================================提要================= =========================

ERROR:
(Development) Rakeshs-MacBook-Pro:src rakesh$ python manage.py runserver
Traceback (most recent call last):
  File "manage.py", line 8, in <module>
    from django.core.management import execute_from_command_line
ModuleNotFoundError: No module named 'django'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "manage.py", line 14, in <module>
    import django
ModuleNotFoundError: No module named 'django'

在处理上述异常期间,发生了另一个异常:

Traceback (most recent call last):
  File "manage.py", line 17, in <module>
    "Couldn't import Django. Are you sure it's installed and "
ImportError: Couldn't import Django. Are you sure it's installed and available on your PYTHONPATH environment variable? Did you forget to activate a virtual environment?
(Development) Rakeshs-MacBook-Pro:src rakesh$ 
(Development) Rakeshs-MacBook-Pro:src rakesh$ 
(Development) Rakeshs-MacBook-Pro:src rakesh$ python -Wall manage.py test
Traceback (most recent call last):
  File "manage.py", line 8, in <module>
    from django.core.management import execute_from_command_line
ModuleNotFoundError: No module named 'django'

在处理上述异常期间,发生了另一个异常:

Traceback (most recent call last):
  File "manage.py", line 14, in <module>
    import django
ModuleNotFoundError: No module named 'django'

在处理上述异常期间,发生了另一个异常:

Traceback (most recent call last):
  File "manage.py", line 17, in <module>
    "Couldn't import Django. Are you sure it's installed and "
ImportError: Couldn't import Django. Are you sure it's installed and available on your PYTHONPATH environment variable? Did you forget to activate a virtual environment?

安装Django之后:

(Development) MacBook-Pro:src rakesh$ pip install django
Collecting django
  Downloading https://files.pythonhosted.org/packages/51/1a/e0ac7886c7123a03814178d7517dc822af0fe51a72e1a6bff26153103322/Django-2.1-py3-none-any.whl (7.3MB)
    100% |████████████████████████████████| 7.3MB 1.1MB/s 
Collecting pytz (from django)
  Downloading https://files.pythonhosted.org/packages/30/4e/27c34b62430286c6d59177a0842ed90dc789ce5d1ed740887653b898779a/pytz-2018.5-py2.py3-none-any.whl (510kB)
    100% |████████████████████████████████| 512kB 4.7MB/s 
Installing collected packages: pytz, django

解决后:

(Development) MacBook-Pro:src rakesh$ python manage.py runserver
Performing system checks...

System check identified no issues (0 silenced).

You have 15 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.

August 05, 2018 - 04:39:02
Django version 2.1, using settings 'trydjango.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
[05/Aug/2018 04:39:15] "GET / HTTP/1.1" 200 16348
[05/Aug/2018 04:39:15] "GET /static/admin/css/fonts.css HTTP/1.1" 200 423
[05/Aug/2018 04:39:15] "GET /static/admin/fonts/Roboto-Bold-webfont.woff HTTP/1.1" 200 82564
[05/Aug/2018 04:39:15] "GET /static/admin/fonts/Roboto-Light-webfont.woff HTTP/1.1" 200 81348
[05/Aug/2018 04:39:15] "GET /static/admin/fonts/Roboto-Regular-webfont.woff HTTP/1.1" 200 80304
Not Found: /favicon.ico
[05/Aug/2018 04:39:16] "GET /favicon.ico HTTP/1.1" 404 1976

祝好运!!

==================================SOLUTION=========================================

First goto: virtualenv

by running the command: source bin/activate

and install django because you are getting the error related to ‘import django’:

pip install django

Then run:

python manage.py runserver

(Note: please change ‘runserver’ to the program name you want to run)

For the same issue, it worked in my case. ==================================Synopsis=========================================

ERROR:
(Development) Rakeshs-MacBook-Pro:src rakesh$ python manage.py runserver
Traceback (most recent call last):
  File "manage.py", line 8, in <module>
    from django.core.management import execute_from_command_line
ModuleNotFoundError: No module named 'django'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "manage.py", line 14, in <module>
    import django
ModuleNotFoundError: No module named 'django'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "manage.py", line 17, in <module>
    "Couldn't import Django. Are you sure it's installed and "
ImportError: Couldn't import Django. Are you sure it's installed and available on your PYTHONPATH environment variable? Did you forget to activate a virtual environment?
(Development) Rakeshs-MacBook-Pro:src rakesh$ 
(Development) Rakeshs-MacBook-Pro:src rakesh$ 
(Development) Rakeshs-MacBook-Pro:src rakesh$ python -Wall manage.py test
Traceback (most recent call last):
  File "manage.py", line 8, in <module>
    from django.core.management import execute_from_command_line
ModuleNotFoundError: No module named 'django'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "manage.py", line 14, in <module>
    import django
ModuleNotFoundError: No module named 'django'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "manage.py", line 17, in <module>
    "Couldn't import Django. Are you sure it's installed and "
ImportError: Couldn't import Django. Are you sure it's installed and available on your PYTHONPATH environment variable? Did you forget to activate a virtual environment?

AFTER INSTALLATION of django:

(Development) MacBook-Pro:src rakesh$ pip install django
Collecting django
  Downloading https://files.pythonhosted.org/packages/51/1a/e0ac7886c7123a03814178d7517dc822af0fe51a72e1a6bff26153103322/Django-2.1-py3-none-any.whl (7.3MB)
    100% |████████████████████████████████| 7.3MB 1.1MB/s 
Collecting pytz (from django)
  Downloading https://files.pythonhosted.org/packages/30/4e/27c34b62430286c6d59177a0842ed90dc789ce5d1ed740887653b898779a/pytz-2018.5-py2.py3-none-any.whl (510kB)
    100% |████████████████████████████████| 512kB 4.7MB/s 
Installing collected packages: pytz, django

AFTER RESOLVING:

(Development) MacBook-Pro:src rakesh$ python manage.py runserver
Performing system checks...

System check identified no issues (0 silenced).

You have 15 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.

August 05, 2018 - 04:39:02
Django version 2.1, using settings 'trydjango.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
[05/Aug/2018 04:39:15] "GET / HTTP/1.1" 200 16348
[05/Aug/2018 04:39:15] "GET /static/admin/css/fonts.css HTTP/1.1" 200 423
[05/Aug/2018 04:39:15] "GET /static/admin/fonts/Roboto-Bold-webfont.woff HTTP/1.1" 200 82564
[05/Aug/2018 04:39:15] "GET /static/admin/fonts/Roboto-Light-webfont.woff HTTP/1.1" 200 81348
[05/Aug/2018 04:39:15] "GET /static/admin/fonts/Roboto-Regular-webfont.woff HTTP/1.1" 200 80304
Not Found: /favicon.ico
[05/Aug/2018 04:39:16] "GET /favicon.ico HTTP/1.1" 404 1976

Good luck!!


回答 19

您的项目是使用django1.3之前的旧版本django-admin.py创建的

要解决此问题,请创建另一个django项目并复制其manage.py并将其粘贴到旧的项目中

your project is created using an old version of django-admin.py, older than django1.3

to fix this create another django project and copy its manage.py and paste it in the old one


回答 20

完全同意这是一个路径问题,但是首先,我遇到了同样的错误。这是由于在设置虚拟环境时为我的Python可执行文件使用了相对路径的错误。我这样做了:

virtualenv -p ~/python_runtimes/2.7.3/bin/python venv2.7.3 --distribute

相反,我不得不给出Python可执行文件的完整路径。

哈林HTH

Agreed completely that this is a path issue but fwiw, I had this same error. It was due to the mistake of using a relative path for my Python executable when setting up my virtual environment. I had done this:

virtualenv -p ~/python_runtimes/2.7.3/bin/python venv2.7.3 --distribute

Instead I had to give the full path to the Python executable.

HTH, Harlin


回答 21

来源〜/ blog-venv / bin / activate

在此处选择您的virtualenv替换“ blog-venv”。

source ~/blog-venv/bin/activate

pick your virtualenv to replace “blog-venv” here.


回答 22

确保您在路径上使用正确的目录运行正确的Python实例。就我而言,此错误是python由偶然运行可执行文件引起的-我实际上是在python2.7框架和库下安装了Django 。由于virtualenv也可能发生相同的情况。

Be sure you’re running the right instance of Python with the right directories on the path. In my case, this error resulted from running the python executable by accident – I had actually installed Django under the python2.7 framework & libraries. The same could happen as a result of virtualenv as well.


回答 23

好的,它像这样:

您已经创建了一个虚拟环境,而django模块仅属于该环境。由于virtualenv会将其自身与其他所有事物隔离开,因此您会看到这一点。

进行以下操作以获得进一步的帮助:

http://www.swegler.com/becky/blog/2011/08/27/python-django-mysql-on-windows-7-part-i-getting-started/

1.您可以切换到虚拟环境存储的目录,然后运行django模块。

2.或者您可以通过运行pip或easy_install将django全局安装到python-> site-packages

使用pip的命令:pip install django

然后这样做:

导入django打印(django.get_version())(取决于您使用的python版本。这适用于python 3+系列)

然后您可以运行以下命令:python manage.py runserver并通过输入:localhost:8000在Web浏览器上进行检查,您应该看到django驱动的页面。

希望这可以帮助。

Okay so it goes like this:

You have created a virtual environment and django module belongs to that environment only.Since virtualenv isolates itself from everything else,hence you are seeing this.

go through this for further assistance:

http://www.swegler.com/becky/blog/2011/08/27/python-django-mysql-on-windows-7-part-i-getting-started/

1.You can switch to the directory where your virtual environment is stored and then run the django module.

2.Alternatively you can install django globally to your python->site-packages by either running pip or easy_install

Command using pip: pip install django

then do this:

import django print (django.get_version()) (depending on which version of python you use.This for python 3+ series)

and then you can run this: python manage.py runserver and check on your web browser by typing :localhost:8000 and you should see django powered page.

Hope this helps.


回答 24

我在发出startapp命令之前“之前”将新应用程序的名称包含在settings.py的INSTALLED_APPS列表中。删除列表条目后,就可以创建应用了。

I included the name of the new App to the INSTALLED_APPS list in the settings.py “before” I issued the startapp command. Once I removed the list entry, I could create the app.


回答 25

我通过使用’django-admin’命令来解决此问题,如下所示:

django-admin startproject _project_name

只需删除附加到“ django-admin”的“ .py”

I solved this problem by using ‘django-admin’ command as following instead:

django-admin startproject _project_name

just remove the “.py” attached to “django-admin”


回答 26

调用一个应用程序site也可以重现此问题。

Having an application called site can reproduce this issue either.


回答 27

我之所以忘记了,是因为我忘记使用来安装Django pip -U,因此它仅适用于运行Django应用的用户。要运行manage.py我必须做

sudo su -s /bin/bash MY_DJANGO_USER
/PATH/TO/MY/APP/manage.py

I got this due to forgetting that I installed Django using pip -U, so it was only available to the user running my Django app. To run manage.py I had to do

sudo su -s /bin/bash MY_DJANGO_USER
/PATH/TO/MY/APP/manage.py

回答 28

你们所有人都没有提到有人“像我”会在安装virtualenv之前安装django …因此,对于所有此类人,如果这样做,…在激活virtualenv..i之后重新安装django。希望这可以帮助

all of you guys didn’t mention a case where someone “like me” would install django befor installing virtualenv…so for all the people of my kind ther if you did that…reinstall django after activating the virtualenv..i hope this helps


遍历模板中的模型实例字段名称和值

问题:遍历模板中的模型实例字段名称和值

我正在尝试创建一个基本模板以显示所选实例的字段值及其名称。可以将其视为表格式的该实例的值的标准输出,第一列具有字段名称(如果在字段上指定,则为verbose_name),第二列具有该字段的值。

例如,假设我们具有以下模型定义:

class Client(Model):
    name = CharField(max_length=150)
    email = EmailField(max_length=100, verbose_name="E-mail")

我希望将其像这样在模板中输出(假定具有给定值的实例):

Field Name      Field Value
----------      -----------
Name            Wayne Koorts
E-mail          waynes@email.com

我要实现的目标是能够将模型的实例传递到模板,并能够在模板中动态地对其进行迭代,如下所示:

<table>
    {% for field in fields %}
        <tr>
            <td>{{ field.name }}</td>
            <td>{{ field.value }}</td>
        </tr>
    {% endfor %}
</table>

有没有一种经过Django批准的简洁方法?这似乎是一项非常普通的任务,对于这个特定项目,我将需要经常执行。

I’m trying to create a basic template to display the selected instance’s field values, along with their names. Think of it as just a standard output of the values of that instance in table format, with the field name (verbose_name specifically if specified on the field) in the first column and the value of that field in the second column.

For example, let’s say we have the following model definition:

class Client(Model):
    name = CharField(max_length=150)
    email = EmailField(max_length=100, verbose_name="E-mail")

I would want it to be output in the template like so (assume an instance with the given values):

Field Name      Field Value
----------      -----------
Name            Wayne Koorts
E-mail          waynes@email.com

What I’m trying to achieve is being able to pass an instance of the model to a template and be able to iterate over it dynamically in the template, something like this:

<table>
    {% for field in fields %}
        <tr>
            <td>{{ field.name }}</td>
            <td>{{ field.value }}</td>
        </tr>
    {% endfor %}
</table>

Is there a neat, “Django-approved” way to do this? It seems like a very common task, and I will need to do it often for this particular project.


回答 0

model._meta.get_all_field_names()将为您提供模型的所有字段名称,然后您就可以使用model._meta.get_field()该方法来获取详细名称,并getattr(model_instance, 'field_name')从模型中获取值。

注意:model._meta.get_all_field_names()在django 1.9中已弃用。而是使用model._meta.get_fields()获取模型的字段并field.name获取每个字段名称。

model._meta.get_all_field_names() will give you all the model’s field names, then you can use model._meta.get_field() to work your way to the verbose name, and getattr(model_instance, 'field_name') to get the value from the model.

NOTE: model._meta.get_all_field_names() is deprecated in django 1.9. Instead use model._meta.get_fields() to get the model’s fields and field.name to get each field name.


回答 1

您可以使用Django的to-python queryset序列化程序。

只需将以下代码放入您的视图中:

from django.core import serializers
data = serializers.serialize( "python", SomeModel.objects.all() )

然后在模板中:

{% for instance in data %}
    {% for field, value in instance.fields.items %}
        {{ field }}: {{ value }}
    {% endfor %}
{% endfor %}

它的巨大优点是它处理关系字段。

对于字段子集,请尝试:

data = serializers.serialize('python', SomeModel.objects.all(), fields=('name','size'))

You can use Django’s to-python queryset serializer.

Just put the following code in your view:

from django.core import serializers
data = serializers.serialize( "python", SomeModel.objects.all() )

And then in the template:

{% for instance in data %}
    {% for field, value in instance.fields.items %}
        {{ field }}: {{ value }}
    {% endfor %}
{% endfor %}

Its great advantage is the fact that it handles relation fields.

For the subset of fields try:

data = serializers.serialize('python', SomeModel.objects.all(), fields=('name','size'))

回答 2

终于在开发邮件列表中找到了一个很好的解决方案:

在视图中添加:

from django.forms.models import model_to_dict

def show(request, object_id):
    object = FooForm(data=model_to_dict(Foo.objects.get(pk=object_id)))
    return render_to_response('foo/foo_detail.html', {'object': object})

在模板中添加:

{% for field in object %}
    <li><b>{{ field.label }}:</b> {{ field.data }}</li>
{% endfor %}

Finally found a good solution to this on the dev mailing list:

In the view add:

from django.forms.models import model_to_dict

def show(request, object_id):
    object = FooForm(data=model_to_dict(Foo.objects.get(pk=object_id)))
    return render_to_response('foo/foo_detail.html', {'object': object})

in the template add:

{% for field in object %}
    <li><b>{{ field.label }}:</b> {{ field.data }}</li>
{% endfor %}

回答 3

鉴于Django 1.8的发布(以及Model _meta API的形式化,我认为我将使用更新的答案对此进行更新。

假设模型相同:

class Client(Model):
    name = CharField(max_length=150)
    email = EmailField(max_length=100, verbose_name="E-mail")

Django <= 1.7

fields = [(f.verbose_name, f.name) for f in Client._meta.fields]
>>> fields
[(u'ID', u'id'), (u'name', u'name'), (u'E-mail', u'email')]

Django 1.8+(正式的Model _meta API)

在Django 1.8中进行了更改:

Model _metaAPI一直是Django内部的,但尚未正式记录和支持。作为使此API公开的工作的一部分,一些已经存在的API入口点已稍作更改。提供了迁移指南,以帮助您转换代码以使用新的官方API。

在下面的例子中,我们将利用形式化方法检索模型的所有字段的实例通过Client._meta.get_fields()

fields = [(f.verbose_name, f.name) for f in Client._meta.get_fields()]
>>> fields
[(u'ID', u'id'), (u'name', u'name'), (u'E-mail', u'email')]

实际上,已经引起我注意的是,以上内容对于所需的内容来说有些过分了(我同意!)。简单胜于复杂。我将以上内容留作参考。但是,要在模板中显示,最好的方法是使用ModelForm并传入实例。您可以遍历表单(等同于遍历表单的每个字段),并使用label属性检索模型字段的verbose_name,并使用value方法检索值:

from django.forms import ModelForm
from django.shortcuts import get_object_or_404, render
from .models import Client

def my_view(request, pk):
    instance = get_object_or_404(Client, pk=pk)
    
    class ClientForm(ModelForm):
        class Meta:
            model = Client
            fields = ('name', 'email')

    form = ClientForm(instance=instance)

    return render(
        request, 
        template_name='template.html',
        {'form': form}
    )

现在,我们在模板中渲染字段:

<table>
    <thead>
        {% for field in form %}
            <th>{{ field.label }}</th>
        {% endfor %}
    </thead>
    <tbody>
        <tr>
            {% for field in form %}
                <td>{{ field.value|default_if_none:'' }}</td>
            {% endfor %}
        </tr>
    </tbody>
</table>
 

In light of Django 1.8’s release (and the formalization of the Model _meta API, I figured I would update this with a more recent answer.

Assuming the same model:

class Client(Model):
    name = CharField(max_length=150)
    email = EmailField(max_length=100, verbose_name="E-mail")

Django <= 1.7

fields = [(f.verbose_name, f.name) for f in Client._meta.fields]
>>> fields
[(u'ID', u'id'), (u'name', u'name'), (u'E-mail', u'email')]

Django 1.8+ (formalized Model _meta API)

Changed in Django 1.8:

The Model _meta API has always existed as a Django internal, but wasn’t formally documented and supported. As part of the effort to make this API public, some of the already existing API entry points have changed slightly. A migration guide has been provided to assist in converting your code to use the new, official API.

In the below example, we will utilize the formalized method for retrieving all field instances of a model via Client._meta.get_fields():

fields = [(f.verbose_name, f.name) for f in Client._meta.get_fields()]
>>> fields
[(u'ID', u'id'), (u'name', u'name'), (u'E-mail', u'email')]

Actually, it has been brought to my attention that the above is slightly overboard for what was needed (I agree!). Simple is better than complex. I am leaving the above for reference. However, to display in the template, the best method would be to use a ModelForm and pass in an instance. You can iterate over the form (equivalent of iterating over each of the form’s fields) and use the label attribute to retrieve the verbose_name of the model field, and use the value method to retrieve the value:

from django.forms import ModelForm
from django.shortcuts import get_object_or_404, render
from .models import Client

def my_view(request, pk):
    instance = get_object_or_404(Client, pk=pk)
    
    class ClientForm(ModelForm):
        class Meta:
            model = Client
            fields = ('name', 'email')

    form = ClientForm(instance=instance)

    return render(
        request, 
        template_name='template.html',
        {'form': form}
    )

Now, we render the fields in the template:

<table>
    <thead>
        {% for field in form %}
            <th>{{ field.label }}</th>
        {% endfor %}
    </thead>
    <tbody>
        <tr>
            {% for field in form %}
                <td>{{ field.value|default_if_none:'' }}</td>
            {% endfor %}
        </tr>
    </tbody>
</table>
 

回答 4

这是使用模型方法的另一种方法。此版本可解析选择列表/选择字段,跳过空字段,并允许您排除特定字段。

def get_all_fields(self):
    """Returns a list of all field names on the instance."""
    fields = []
    for f in self._meta.fields:

        fname = f.name        
        # resolve picklists/choices, with get_xyz_display() function
        get_choice = 'get_'+fname+'_display'
        if hasattr(self, get_choice):
            value = getattr(self, get_choice)()
        else:
            try:
                value = getattr(self, fname)
            except AttributeError:
                value = None

        # only display fields with values and skip some fields entirely
        if f.editable and value and f.name not in ('id', 'status', 'workshop', 'user', 'complete') :

            fields.append(
              {
               'label':f.verbose_name, 
               'name':f.name, 
               'value':value,
              }
            )
    return fields

然后在您的模板中:

{% for f in app.get_all_fields %}
  <dt>{{f.label|capfirst}}</dt>
    <dd>
      {{f.value|escape|urlize|linebreaks}}
    </dd>
{% endfor %}

Here’s another approach using a model method. This version resolves picklist/choice fields, skips empty fields, and lets you exclude specific fields.

def get_all_fields(self):
    """Returns a list of all field names on the instance."""
    fields = []
    for f in self._meta.fields:

        fname = f.name        
        # resolve picklists/choices, with get_xyz_display() function
        get_choice = 'get_'+fname+'_display'
        if hasattr(self, get_choice):
            value = getattr(self, get_choice)()
        else:
            try:
                value = getattr(self, fname)
            except AttributeError:
                value = None

        # only display fields with values and skip some fields entirely
        if f.editable and value and f.name not in ('id', 'status', 'workshop', 'user', 'complete') :

            fields.append(
              {
               'label':f.verbose_name, 
               'name':f.name, 
               'value':value,
              }
            )
    return fields

Then in your template:

{% for f in app.get_all_fields %}
  <dt>{{f.label|capfirst}}</dt>
    <dd>
      {{f.value|escape|urlize|linebreaks}}
    </dd>
{% endfor %}

回答 5

好的,我知道这有点晚了,但是由于我在找到正确答案之前偶然发现了这个,其他人也可能会发现。

Django文档中

# This list contains a Blog object.
>>> Blog.objects.filter(name__startswith='Beatles')
[<Blog: Beatles Blog>]

# This list contains a dictionary.
>>> Blog.objects.filter(name__startswith='Beatles').values()
[{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]

Ok, I know this is a bit late, but since I stumbled upon this before finding the correct answer so might someone else.

From the django docs:

# This list contains a Blog object.
>>> Blog.objects.filter(name__startswith='Beatles')
[<Blog: Beatles Blog>]

# This list contains a dictionary.
>>> Blog.objects.filter(name__startswith='Beatles').values()
[{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]

回答 6

您可以使用的values()方法,该方法queryset返回字典。此外,此方法接受要作为子集的字段列表。该values()方法不适用于get(),因此必须使用filter()(请参阅QuerySet API)。

view

def show(request, object_id):
   object = Foo.objects.filter(id=object_id).values()[0]
   return render_to_response('detail.html', {'object': object})

detail.html

<ul>
   {% for key, value in object.items %}
        <li><b>{{ key }}:</b> {{ value }}</li>
   {% endfor %}
</ul>

对于过滤器返回的实例集合

   object = Foo.objects.filter(id=object_id).values() # no [0]

detail.html

{% for instance in object %}
<h1>{{ instance.id }}</h1>
<ul>
    {% for key, value in instance.items %}
        <li><b>{{ key }}:</b>  {{ value }}</li>
    {% endfor %}
</ul>
{% endfor %}

You can use the values() method of a queryset, which returns a dictionary. Further, this method accepts a list of fields to subset on. The values() method will not work with get(), so you must use filter() (refer to the QuerySet API).

In view

def show(request, object_id):
   object = Foo.objects.filter(id=object_id).values()[0]
   return render_to_response('detail.html', {'object': object})

In detail.html

<ul>
   {% for key, value in object.items %}
        <li><b>{{ key }}:</b> {{ value }}</li>
   {% endfor %}
</ul>

For a collection of instances returned by filter:

   object = Foo.objects.filter(id=object_id).values() # no [0]

In detail.html

{% for instance in object %}
<h1>{{ instance.id }}</h1>
<ul>
    {% for key, value in instance.items %}
        <li><b>{{ key }}:</b>  {{ value }}</li>
    {% endfor %}
</ul>
{% endfor %}

回答 7

我使用了https://stackoverflow.com/a/3431104/2022534,但以此替换了Django的model_to_dict()以便能够处理ForeignKey:

def model_to_dict(instance):
    data = {}
    for field in instance._meta.fields:
        data[field.name] = field.value_from_object(instance)
        if isinstance(field, ForeignKey):
            data[field.name] = field.rel.to.objects.get(pk=data[field.name])
    return data

请注意,我已经删除了不需要的部分,从而大大简化了它。您可能要放回去。

I used https://stackoverflow.com/a/3431104/2022534 but replaced Django’s model_to_dict() with this to be able to handle ForeignKey:

def model_to_dict(instance):
    data = {}
    for field in instance._meta.fields:
        data[field.name] = field.value_from_object(instance)
        if isinstance(field, ForeignKey):
            data[field.name] = field.rel.to.objects.get(pk=data[field.name])
    return data

Please note that I have simplified it quite a bit by removing the parts of the original I didn’t need. You might want to put those back.


回答 8

您可以使用表格为您完成工作。

def my_model_view(request, mymodel_id):
    class MyModelForm(forms.ModelForm):
        class Meta:
            model = MyModel

    model = get_object_or_404(MyModel, pk=mymodel_id)
    form = MyModelForm(instance=model)
    return render(request, 'model.html', { 'form': form})

然后在模板中:

<table>
    {% for field in form %}
        <tr>
            <td>{{ field.name }}</td>
            <td>{{ field.value }}</td>
        </tr>
    {% endfor %}
</table>

You can have a form do the work for you.

def my_model_view(request, mymodel_id):
    class MyModelForm(forms.ModelForm):
        class Meta:
            model = MyModel

    model = get_object_or_404(MyModel, pk=mymodel_id)
    form = MyModelForm(instance=model)
    return render(request, 'model.html', { 'form': form})

Then in the template:

<table>
    {% for field in form %}
        <tr>
            <td>{{ field.name }}</td>
            <td>{{ field.value }}</td>
        </tr>
    {% endfor %}
</table>

回答 9

确实应该有一种内置方法来执行此操作。我编写了此实用程序build_pretty_data_view,该实用程序接受模型对象和表单实例(基于您的模型的表单)并返回SortedDict

该解决方案的优势包括:

  • 它使用Django的内置命令保留命令 SortedDict
  • 尝试获取标签/详细名称时,但如果未定义则回退到字段名称。
  • 也可以选择 exclude()字段名称列表以排除某些字段。
  • 如果您的表单类包含一个Meta: exclude(),但您仍想返回这些值,则将这些字段添加到可选append()列表中。

要使用此解决方案,请先将此文件/功能添加到某处,然后将其导入到中views.py

utils.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# vim: ai ts=4 sts=4 et sw=4
from django.utils.datastructures import SortedDict


def build_pretty_data_view(form_instance, model_object, exclude=(), append=()):
    i=0
    sd=SortedDict()

    for j in append:
        try:
            sdvalue={'label':j.capitalize(),
                     'fieldvalue':model_object.__getattribute__(j)}
            sd.insert(i, j, sdvalue)
            i+=1
        except(AttributeError):
            pass

    for k,v in form_instance.fields.items():
        sdvalue={'label':"", 'fieldvalue':""}
        if not exclude.__contains__(k):
            if v.label is not None:
                sdvalue = {'label':v.label,
                           'fieldvalue': model_object.__getattribute__(k)}
            else:
                sdvalue = {'label':k,
                           'fieldvalue': model_object.__getattribute__(k)}
            sd.insert(i, k, sdvalue)
            i+=1
    return sd

因此,现在views.py您可以执行以下操作

from django.shortcuts import render_to_response
from django.template import RequestContext
from utils import build_pretty_data_view
from models import Blog
from forms import BlogForm
.
.
def my_view(request):
   b=Blog.objects.get(pk=1)
   bf=BlogForm(instance=b)
   data=build_pretty_data_view(form_instance=bf, model_object=b,
                        exclude=('number_of_comments', 'number_of_likes'),
                        append=('user',))

   return render_to_response('my-template.html',
                          RequestContext(request,
                                         {'data':data,}))

现在,您my-template.html可以在模板中像这样遍历数据…

{% for field,value in data.items %}

    <p>{{ field }} : {{value.label}}: {{value.fieldvalue}}</p>

{% endfor %}

祝好运。希望这对某人有帮助!

There should really be a built-in way to do this. I wrote this utility build_pretty_data_view that takes a model object and form instance (a form based on your model) and returns a SortedDict.

Benefits to this solution include:

  • It preserves order using Django’s built-in SortedDict.
  • When tries to get the label/verbose_name, but falls back to the field name if one is not defined.
  • It will also optionally take an exclude() list of field names to exclude certain fields.
  • If your form class includes a Meta: exclude(), but you still want to return the values, then add those fields to the optional append() list.

To use this solution, first add this file/function somewhere, then import it into your views.py.

utils.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# vim: ai ts=4 sts=4 et sw=4
from django.utils.datastructures import SortedDict


def build_pretty_data_view(form_instance, model_object, exclude=(), append=()):
    i=0
    sd=SortedDict()

    for j in append:
        try:
            sdvalue={'label':j.capitalize(),
                     'fieldvalue':model_object.__getattribute__(j)}
            sd.insert(i, j, sdvalue)
            i+=1
        except(AttributeError):
            pass

    for k,v in form_instance.fields.items():
        sdvalue={'label':"", 'fieldvalue':""}
        if not exclude.__contains__(k):
            if v.label is not None:
                sdvalue = {'label':v.label,
                           'fieldvalue': model_object.__getattribute__(k)}
            else:
                sdvalue = {'label':k,
                           'fieldvalue': model_object.__getattribute__(k)}
            sd.insert(i, k, sdvalue)
            i+=1
    return sd

So now in your views.py you might do something like this

from django.shortcuts import render_to_response
from django.template import RequestContext
from utils import build_pretty_data_view
from models import Blog
from forms import BlogForm
.
.
def my_view(request):
   b=Blog.objects.get(pk=1)
   bf=BlogForm(instance=b)
   data=build_pretty_data_view(form_instance=bf, model_object=b,
                        exclude=('number_of_comments', 'number_of_likes'),
                        append=('user',))

   return render_to_response('my-template.html',
                          RequestContext(request,
                                         {'data':data,}))

Now in your my-template.html template you can iterate over the data like so…

{% for field,value in data.items %}

    <p>{{ field }} : {{value.label}}: {{value.fieldvalue}}</p>

{% endfor %}

Good Luck. Hope this helps someone!


回答 10

下面是我的,受到黑客的 启发get_all_fields。它获取一个模型实例的字典,如果遇到关系字段,则递归将字段值分配给字典。

def to_dict(obj, exclude=[]):
    """生成一个 dict, 递归包含一个 model instance 数据.
    """
    tree = {}
    for field in obj._meta.fields + obj._meta.many_to_many:
        if field.name in exclude or \
           '%s.%s' % (type(obj).__name__, field.name) in exclude:
            continue

        try :
            value = getattr(obj, field.name)
        except obj.DoesNotExist:
            value = None

        if type(field) in [ForeignKey, OneToOneField]:
            tree[field.name] = to_dict(value, exclude=exclude)
        elif isinstance(field, ManyToManyField):
            vs = []
            for v in value.all():
                vs.append(to_dict(v, exclude=exclude))
            tree[field.name] = vs
        elif isinstance(field, DateTimeField):
            tree[field.name] = str(value)
        elif isinstance(field, FileField):
            tree[field.name] = {'url': value.url}
        else:
            tree[field.name] = value

    return tree

此函数主要用于将模型实例转储到json数据:

def to_json(self):
    tree = to_dict(self, exclude=('id', 'User.password'))
    return json.dumps(tree, ensure_ascii=False)

Below is mine, inspired by shacker’s get_all_fields. It gets a dict of one model instance, if encounter relation field, then asign the field value a dict recursively.

def to_dict(obj, exclude=[]):
    """生成一个 dict, 递归包含一个 model instance 数据.
    """
    tree = {}
    for field in obj._meta.fields + obj._meta.many_to_many:
        if field.name in exclude or \
           '%s.%s' % (type(obj).__name__, field.name) in exclude:
            continue

        try :
            value = getattr(obj, field.name)
        except obj.DoesNotExist:
            value = None

        if type(field) in [ForeignKey, OneToOneField]:
            tree[field.name] = to_dict(value, exclude=exclude)
        elif isinstance(field, ManyToManyField):
            vs = []
            for v in value.all():
                vs.append(to_dict(v, exclude=exclude))
            tree[field.name] = vs
        elif isinstance(field, DateTimeField):
            tree[field.name] = str(value)
        elif isinstance(field, FileField):
            tree[field.name] = {'url': value.url}
        else:
            tree[field.name] = value

    return tree

This function is mainly used to dump a model instance to json data:

def to_json(self):
    tree = to_dict(self, exclude=('id', 'User.password'))
    return json.dumps(tree, ensure_ascii=False)

回答 11

我建议不要编写每个模型,而是建议编写一个模板标签,该标签将返回给定模型的所有字段。
每个对象都有字段列表._meta.fields
每个字段对象都具有name返回其名称的属性,而value_to_string()模型随附的方法object将返回其值。
其余的就像Django文档中所说的那样简单。

这是我的示例,此templatetag可能如下所示:

    from django.conf import settings
    from django import template

    if not getattr(settings, 'DEBUG', False):
        raise template.TemplateSyntaxError('get_fields is available only when DEBUG = True')


    register = template.Library()

    class GetFieldsNode(template.Node):
        def __init__(self, object, context_name=None):
            self.object = template.Variable(object)
            self.context_name = context_name

        def render(self, context):
            object = self.object.resolve(context)
            fields = [(field.name, field.value_to_string(object)) for field in object._meta.fields]

            if self.context_name:
                context[self.context_name] = fields
                return ''
            else:
                return fields


    @register.tag
    def get_fields(parser, token):
        bits = token.split_contents()

        if len(bits) == 4 and bits[2] == 'as':
            return GetFieldsNode(bits[1], context_name=bits[3])
        elif len(bits) == 2:
            return GetFieldsNode(bits[1])
        else:
            raise template.TemplateSyntaxError("get_fields expects a syntax of "
                           "{% get_fields <object> [as <context_name>] %}")

Instead of editing every model I would recommend to write one template tag which will return all field of any model given.
Every object has list of fields ._meta.fields.
Every field object has attribute name that will return it’s name and method value_to_string() that supplied with your model object will return its value.
The rest is as simple as it’s said in Django documentation.

Here is my example how this templatetag might look like:

    from django.conf import settings
    from django import template

    if not getattr(settings, 'DEBUG', False):
        raise template.TemplateSyntaxError('get_fields is available only when DEBUG = True')


    register = template.Library()

    class GetFieldsNode(template.Node):
        def __init__(self, object, context_name=None):
            self.object = template.Variable(object)
            self.context_name = context_name

        def render(self, context):
            object = self.object.resolve(context)
            fields = [(field.name, field.value_to_string(object)) for field in object._meta.fields]

            if self.context_name:
                context[self.context_name] = fields
                return ''
            else:
                return fields


    @register.tag
    def get_fields(parser, token):
        bits = token.split_contents()

        if len(bits) == 4 and bits[2] == 'as':
            return GetFieldsNode(bits[1], context_name=bits[3])
        elif len(bits) == 2:
            return GetFieldsNode(bits[1])
        else:
            raise template.TemplateSyntaxError("get_fields expects a syntax of "
                           "{% get_fields <object> [as <context_name>] %}")

回答 12

是的,这并不漂亮,您必须自己制作包装纸。看一看内置的数据浏览应用程序,它具有您真正需要的所有功能。

Yeah it’s not pretty, you’ll have to make your own wrapper. Take a look at builtin databrowse app, which has all the functionality you need really.


回答 13

这可能被认为是黑客,但是在使用modelform_factory将模型实例转换为表单之前,我已经做到了。

Form类内部有很多信息,这些信息非常容易迭代,并且可以达到相同的目的,但开销会稍有增加。如果您的设备尺寸相对较小,我认为对性能的影响可以忽略不计。

当然,除了方便之外,一个优点是您可以在以后轻松地将表变成可编辑的数据网格。

This may be considered a hack but I’ve done this before using modelform_factory to turn a model instance into a form.

The Form class has a lot more information inside that’s super easy to iterate over and it will serve the same purpose at the expense of slightly more overhead. If your set sizes are relatively small I think the performance impact would be negligible.

The one advantage besides convenience of course is that you can easily turn the table into an editable datagrid at a later date.


回答 14

我想出了以下方法,该方法对我有用,因为在每种情况下,模型都会有一个与之关联的ModelForm。

def GetModelData(form, fields):
    """
    Extract data from the bound form model instance and return a
    dictionary that is easily usable in templates with the actual
    field verbose name as the label, e.g.

    model_data{"Address line 1": "32 Memory lane",
               "Address line 2": "Brainville",
               "Phone": "0212378492"}

    This way, the template has an ordered list that can be easily
    presented in tabular form.
    """
    model_data = {}
    for field in fields:
        model_data[form[field].label] = eval("form.data.%s" % form[field].name)
    return model_data

@login_required
def clients_view(request, client_id):
    client = Client.objects.get(id=client_id)
    form = AddClientForm(client)

    fields = ("address1", "address2", "address3", "address4",
              "phone", "fax", "mobile", "email")
    model_data = GetModelData(form, fields)

    template_vars = RequestContext(request,
        {
            "client": client,
            "model_data": model_data
        }
    )
    return render_to_response("clients-view.html", template_vars)

这是我用于此特定视图的模板的摘录:

<table class="client-view">
    <tbody>
    {% for field, value in model_data.items %}
        <tr>
            <td class="field-name">{{ field }}</td><td>{{ value }}</td>
        </tr>
    {% endfor %}
    </tbody>
</table>

关于此方法的好处是,我可以使用传递给GetModelData的元组并指定字段名称,在逐个模板的基础上选择要显示字段标签的顺序。这也使我可以排除某些字段(例如,用户外键),因为只有通过元组传递的字段名称才内置在最终字典中。

我不会接受这个答案,因为我敢肯定有人可以提出更多“ Djangonic”的概念:-)

更新:我选择此作为最终答案,因为这是我所需要的,是最简单的答案。感谢所有贡献答案的人。

I’ve come up with the following method, which works for me because in every case the model will have a ModelForm associated with it.

def GetModelData(form, fields):
    """
    Extract data from the bound form model instance and return a
    dictionary that is easily usable in templates with the actual
    field verbose name as the label, e.g.

    model_data{"Address line 1": "32 Memory lane",
               "Address line 2": "Brainville",
               "Phone": "0212378492"}

    This way, the template has an ordered list that can be easily
    presented in tabular form.
    """
    model_data = {}
    for field in fields:
        model_data[form[field].label] = eval("form.data.%s" % form[field].name)
    return model_data

@login_required
def clients_view(request, client_id):
    client = Client.objects.get(id=client_id)
    form = AddClientForm(client)

    fields = ("address1", "address2", "address3", "address4",
              "phone", "fax", "mobile", "email")
    model_data = GetModelData(form, fields)

    template_vars = RequestContext(request,
        {
            "client": client,
            "model_data": model_data
        }
    )
    return render_to_response("clients-view.html", template_vars)

Here is an extract from the template I am using for this particular view:

<table class="client-view">
    <tbody>
    {% for field, value in model_data.items %}
        <tr>
            <td class="field-name">{{ field }}</td><td>{{ value }}</td>
        </tr>
    {% endfor %}
    </tbody>
</table>

The nice thing about this method is that I can choose on a template-by-template basis the order in which I would like to display the field labels, using the tuple passed in to GetModelData and specifying the field names. This also allows me to exclude certain fields (e.g. a User foreign key) as only the field names passed in via the tuple are built into the final dictionary.

I’m not going to accept this as the answer because I’m sure someone can come up with something more “Djangonic” :-)

Update: I’m choosing this as the final answer because it is the simplest out of those given that does what I need. Thanks to everyone who contributed answers.


回答 15

我的Django 1.7解决方案:

这里有确切的变量,但是您肯定可以剖析此示例

这里的关键是几乎使用.__dict__模型
views.py的

def display_specific(request, key):
  context = {
    'question_id':question_id,
    'client':Client.objects.get(pk=key).__dict__,
  }
  return render(request, "general_household/view_specific.html", context)

模板

{% for field in gen_house %}
    {% if field != '_state' %}
        {{ gen_house|getattribute:field }}
    {% endif %}
{% endfor %}

在模板中,我使用了过滤器来访问dict
filter.py中的字段:

@register.filter(name='getattribute')
def getattribute(value, arg):
  if value is None or arg is None:
    return ""
  try:
    return value[arg]
  except KeyError:
    return ""
  except TypeError:
    return ""

Django 1.7 solution for me:

There variables are exact to the question, but you should definitely be able to dissect this example

The key here is to pretty much use the .__dict__ of the model
views.py:

def display_specific(request, key):
  context = {
    'question_id':question_id,
    'client':Client.objects.get(pk=key).__dict__,
  }
  return render(request, "general_household/view_specific.html", context)

template:

{% for field in gen_house %}
    {% if field != '_state' %}
        {{ gen_house|getattribute:field }}
    {% endif %}
{% endfor %}

in the template I used a filter to access the field in the dict
filters.py:

@register.filter(name='getattribute')
def getattribute(value, arg):
  if value is None or arg is None:
    return ""
  try:
    return value[arg]
  except KeyError:
    return ""
  except TypeError:
    return ""

回答 16

我正在使用它,https://github.com/miracle2k/django-tables

<table>
<tr>
    {% for column in table.columns %}
    <th><a href="?sort={{ column.name_toggled }}">{{ column }}</a></th>
    {% endfor %}
</tr>
{% for row in table.rows %}
    <tr>
    {% for value in row %}
        <td>{{ value }}</td>
    {% endfor %}
    </tr>
{% endfor %}
</table>

I’m using this, https://github.com/miracle2k/django-tables.

<table>
<tr>
    {% for column in table.columns %}
    <th><a href="?sort={{ column.name_toggled }}">{{ column }}</a></th>
    {% endfor %}
</tr>
{% for row in table.rows %}
    <tr>
    {% for value in row %}
        <td>{{ value }}</td>
    {% endfor %}
    </tr>
{% endfor %}
</table>

回答 17

这种方法显示了如何使用django的ModelForm之类的类和{{form.as_table}}之类的模板标签,但是如何使所有表看起来像数据输出,而不是表单。

第一步是继承django的TextInput小部件:

from django import forms
from django.utils.safestring import mark_safe
from django.forms.util import flatatt

class PlainText(forms.TextInput):
    def render(self, name, value, attrs=None):
        if value is None:
            value = ''
        final_attrs = self.build_attrs(attrs)
        return mark_safe(u'<p %s>%s</p>' % (flatatt(final_attrs),value))

然后,我将django的ModelForm子类化,以将默认小部件换成只读版本:

from django.forms import ModelForm

class ReadOnlyModelForm(ModelForm):
    def __init__(self,*args,**kwrds):
        super(ReadOnlyModelForm,self).__init__(*args,**kwrds)
        for field in self.fields:
            if isinstance(self.fields[field].widget,forms.TextInput) or \
               isinstance(self.fields[field].widget,forms.Textarea):
                self.fields[field].widget=PlainText()
            elif isinstance(self.fields[field].widget,forms.CheckboxInput):
                self.fields[field].widget.attrs['disabled']="disabled" 

这些是我唯一需要的小部件。但是将这个想法扩展到其他小部件并不难。

This approach shows how to use a class like django’s ModelForm and a template tag like {{ form.as_table }}, but have all the table look like data output, not a form.

The first step was to subclass django’s TextInput widget:

from django import forms
from django.utils.safestring import mark_safe
from django.forms.util import flatatt

class PlainText(forms.TextInput):
    def render(self, name, value, attrs=None):
        if value is None:
            value = ''
        final_attrs = self.build_attrs(attrs)
        return mark_safe(u'<p %s>%s</p>' % (flatatt(final_attrs),value))

Then I subclassed django’s ModelForm to swap out the default widgets for readonly versions:

from django.forms import ModelForm

class ReadOnlyModelForm(ModelForm):
    def __init__(self,*args,**kwrds):
        super(ReadOnlyModelForm,self).__init__(*args,**kwrds)
        for field in self.fields:
            if isinstance(self.fields[field].widget,forms.TextInput) or \
               isinstance(self.fields[field].widget,forms.Textarea):
                self.fields[field].widget=PlainText()
            elif isinstance(self.fields[field].widget,forms.CheckboxInput):
                self.fields[field].widget.attrs['disabled']="disabled" 

Those were the only widgets I needed. But it should not be difficult to extend this idea to other widgets.


回答 18

只需编辑@wonder

def to_dict(obj, exclude=[]):
    tree = {}
    for field in obj._meta.fields + obj._meta.many_to_many:
        if field.name in exclude or \
           '%s.%s' % (type(obj).__name__, field.name) in exclude:
            continue
        try :
            value = getattr(obj, field.name)
        except obj.DoesNotExist as e:
            value = None
        except ObjectDoesNotExist as e:
            value = None
            continue
        if type(field) in [ForeignKey, OneToOneField]:
            tree[field.name] = to_dict(value, exclude=exclude)
        elif isinstance(field, ManyToManyField):
            vs = []
            for v in value.all():
                vs.append(to_dict(v, exclude=exclude))
            tree[field.name] = vs
        else:
            tree[field.name] = obj.serializable_value(field.name)
    return tree

让Django处理除相关字段以外的所有其他字段。我觉得比较稳定

Just an edit of @wonder

def to_dict(obj, exclude=[]):
    tree = {}
    for field in obj._meta.fields + obj._meta.many_to_many:
        if field.name in exclude or \
           '%s.%s' % (type(obj).__name__, field.name) in exclude:
            continue
        try :
            value = getattr(obj, field.name)
        except obj.DoesNotExist as e:
            value = None
        except ObjectDoesNotExist as e:
            value = None
            continue
        if type(field) in [ForeignKey, OneToOneField]:
            tree[field.name] = to_dict(value, exclude=exclude)
        elif isinstance(field, ManyToManyField):
            vs = []
            for v in value.all():
                vs.append(to_dict(v, exclude=exclude))
            tree[field.name] = vs
        else:
            tree[field.name] = obj.serializable_value(field.name)
    return tree

Let Django handle all the other fields other than the related fields. I feel that is more stable


回答 19

看一下django-etc应用程序。它具有model_field_verbose_name用于从模板获取字段详细名称的模板标记:http : //django-etc.rtfd.org/en/latest/models.html#model-field-template-tags

Take a look at django-etc application. It has model_field_verbose_name template tag to get field verbose name from templates: http://django-etc.rtfd.org/en/latest/models.html#model-field-template-tags


回答 20

我只是在shell中测试了类似的东西,似乎可以做到这一点:

my_object_mapped = {attr.name: str(getattr(my_object, attr.name)) for attr in MyModel._meta.fields}

请注意,如果要用str()表示异物,则应在其str方法中对其进行定义。由此,您可以确定对象的值。然后,您可以渲染某种模板或其他任何模板。

I just tested something like this in shell and seems to do it’s job:

my_object_mapped = {attr.name: str(getattr(my_object, attr.name)) for attr in MyModel._meta.fields}

Note that if you want str() representation for foreign objects you should define it in their str method. From that you have dict of values for object. Then you can render some kind of template or whatever.


回答 21

Django> = 2.0

添加get_fields()到您的models.py

class Client(Model):
    name = CharField(max_length=150)
    email = EmailField(max_length=100, verbose_name="E-mail")

    def get_fields(self):
        return [(field.verbose_name, field.value_from_object(self)) for field in self.__class__._meta.fields]

然后object.get_fields按您的名称template.html

<table>
    {% for label, value in object.get_fields %}
        <tr>
            <td>{{ label }}</td>
            <td>{{ value }}</td>
        </tr>
    {% endfor %}
</table>

Django >= 2.0

Add get_fields() to your models.py:

class Client(Model):
    name = CharField(max_length=150)
    email = EmailField(max_length=100, verbose_name="E-mail")

    def get_fields(self):
        return [(field.verbose_name, field.value_from_object(self)) for field in self.__class__._meta.fields]

Then call it as object.get_fields on your template.html:

<table>
    {% for label, value in object.get_fields %}
        <tr>
            <td>{{ label }}</td>
            <td>{{ value }}</td>
        </tr>
    {% endfor %}
</table>

回答 22

<table border='1'>
	<tr>
		{% for mfild in fields%}
			<td>{{mfild}}</td>
		{% endfor%}
	</tr>
    {%for v in records%}
        <tr>
        	<td>{{v.id}}</td>
        	<td>{{v.title}}</td>
        	<td class="">{{v.desc}}</td>

        </tr>

    {% endfor%}
 </table>
 
 
enter code here

<table border='1'>
	<tr>
		{% for mfild in fields%}
			<td>{{mfild}}</td>
		{% endfor%}
	</tr>
    {%for v in records%}
        <tr>
        	<td>{{v.id}}</td>
        	<td>{{v.title}}</td>
        	<td class="">{{v.desc}}</td>

        </tr>

    {% endfor%}
 </table>
 
 
enter code here

如何在Django模板中访问字典元素?

问题:如何在Django模板中访问字典元素?

我想打印出每个选择获得的票数。我在模板中有以下代码:

{% for choice in choices %}
    {{choice.choice}} - {{votes[choice.id]}} <br />
{% endfor %}

votes只是一个字典,而choices只是一个模型对象。

该消息引发异常:

"Could not parse the remainder"

I would like to print out the number of votes that each choice got. I have this code in a template:

{% for choice in choices %}
    {{choice.choice}} - {{votes[choice.id]}} <br />
{% endfor %}

votes is just a dictionary while choices is a model object.

It raises an exception with this message:

"Could not parse the remainder"

回答 0

为了回应/扩展Jeff的评论,我认为您应该针对的只是Choice类中的一个属性,该属性计算与该对象关联的投票数:

    class Choice(models.Model):
        text = models.CharField(max_length=200) 

        def calculateVotes(self):
            return Vote.objects.filter(choice = self).count()

        votes = property(calculateVotes)

然后在模板中,您可以执行以下操作:

    {% for choice in choices %}
            {{choice.choice}} - {{choice.votes}} <br />
    {% endfor %}

模板标签,恕我直言,此解决方案有些过分,但也不是一个糟糕的解决方案。Django中模板的目标是使您与模板中的代码隔离,反之亦然。

我会尝试上述方法,并查看ORM生成的SQL,因为我不确定它是否会预先缓存属性并仅为该属性创建子选择,还是会迭代/启用-需求运行查询以计算投票数。但是,如果它产生了残酷的查询,您总是可以使用自己收集的数据填充视图中的属性。

To echo / extend upon Jeff’s comment, what I think you should aim for is simply a property in your Choice class that calculates the number of votes associated with that object:

class Choice(models.Model):
    text = models.CharField(max_length=200)

    def calculateVotes(self):
        return Vote.objects.filter(choice=self).count()

    votes = property(calculateVotes)

And then in your template, you can do:

{% for choice in choices %}
    {{choice.choice}} - {{choice.votes}} <br />
{% endfor %}

The template tag, is IMHO a bit overkill for this solution, but it’s not a terrible solution either. The goal of templates in Django is to insulate you from code in your templates and vice-versa.

I’d try the above method and see what SQL the ORM generates as I’m not sure off the top of my head if it will pre-cache the properties and just create a subselect for the property or if it will iteratively / on-demand run the query to calculate vote count. But if it generates atrocious queries, you could always populate the property in your view with data you’ve collected yourself.


回答 1

choices = {'key1':'val1', 'key2':'val2'}

这是模板:

<ul>
{% for key, value in choices.items %} 
  <li>{{key}} - {{value}}</li>
{% endfor %}
</ul>

基本上,.items是Django关键字,它将字典分为(key, value)成对的列表,很像Python方法.items()。这样可以在Django模板中的字典上进行迭代。

choices = {'key1':'val1', 'key2':'val2'}

Here’s the template:

<ul>
{% for key, value in choices.items %} 
  <li>{{key}} - {{value}}</li>
{% endfor %}
</ul>

Basically, .items is a Django keyword that splits a dictionary into a list of (key, value) pairs, much like the Python method .items(). This enables iteration over a dictionary in a Django template.


回答 2

您可以使用点符号:

点查找可以总结如下:当模板系统遇到变量名称中的点时,它将按以下顺序尝试以下查找:

  • 字典查询(例如foo [“ bar”])
  • 属性查询(例如foo.bar)
  • 方法调用(例如foo.bar())
  • 列表索引查找(例如,foo [2])

系统使用有效的第一种查找类型。这是短路逻辑。

you can use the dot notation:

Dot lookups can be summarized like this: when the template system encounters a dot in a variable name, it tries the following lookups, in this order:

  • Dictionary lookup (e.g., foo[“bar”])
  • Attribute lookup (e.g., foo.bar)
  • Method call (e.g., foo.bar())
  • List-index lookup (e.g., foo[2])

The system uses the first lookup type that works. It’s short-circuit logic.


回答 3

您需要在此处找到(或定义)“ get”模板标签。

标签定义:

@register.filter
def hash(h, key):
    return h[key]

它的用法如下:

{% for o in objects %}
  <li>{{ dictionary|hash:o.id }}</li>
{% endfor %}

You need to find (or define) a ‘get’ template tag, for example, here.

The tag definition:

@register.filter
def hash(h, key):
    return h[key]

And it’s used like:

{% for o in objects %}
  <li>{{ dictionary|hash:o.id }}</li>
{% endfor %}

回答 4

使用字典项目:

{% for key, value in my_dictionay.items %}
  <li>{{ key }} : {{ value }}</li>
{% endfor %}

Use Dictionary Items:

{% for key, value in my_dictionay.items %}
  <li>{{ key }} : {{ value }}</li>
{% endfor %}

回答 5

django_template_filter 过滤器名称get_value_from_dict

{{ your_dict|get_value_from_dict:your_key }}

django_template_filter filter name get_value_from_dict

{{ your_dict|get_value_from_dict:your_key }}

回答 6

类似于@russian_spy的回答:

<ul>
{% for choice in choices.items %} 
  <li>{{choice.0}} - {{choice.1}}</li>
{% endfor %}
</ul>

这可能适合分解更复杂的字典。

Similar to the answer by @russian_spy :

<ul>
{% for choice in choices.items %} 
  <li>{{choice.0}} - {{choice.1}}</li>
{% endfor %}
</ul>

This might be suitable for breaking down more complex dictionaries.


回答 7

理想情况下,您将在以投票方式发现自己的选择对象上创建方法,或者在模型之间创建关系。执行字典查找的模板标记也将起作用。

Ideally, you would create a method on the choice object that found itself in votes, or create a relationship between the models. A template tag that performed the dictionary lookup would work, too.


django测试应用程序错误-创建测试数据库时出错:创建数据库的权限被拒绝

问题:django测试应用程序错误-创建测试数据库时出错:创建数据库的权限被拒绝

当我尝试使用命令测试任何应用程序时(当我尝试使用使用此命令的结构来部署myproject时,我注意到了它):

python manage.py test appname

我收到此错误:

Creating test database for alias 'default'...
Got an error creating the test database: permission denied to create database

Type 'yes' if you would like to try deleting the test database 'test_finance', or 'no' to cancel

syncdb命令似乎起作用。我在settings.py中的数据库设置:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'finance',                      # Or path to database file if using sqlite3.
        'USER': 'django',                      # Not used with sqlite3.
        'PASSWORD': 'mydb123',                  # Not used with sqlite3.
        'HOST': '127.0.0.1',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
    }
}

When I try to test any app with command (I noticed it when I tried to deploy myproject using fabric, which uses this command):

python manage.py test appname

I get this error:

Creating test database for alias 'default'...
Got an error creating the test database: permission denied to create database

Type 'yes' if you would like to try deleting the test database 'test_finance', or 'no' to cancel

syncdb command seems to work. My database settings in settings.py:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'finance',                      # Or path to database file if using sqlite3.
        'USER': 'django',                      # Not used with sqlite3.
        'PASSWORD': 'mydb123',                  # Not used with sqlite3.
        'HOST': '127.0.0.1',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
    }
}

回答 0

Django运行测试套件时,在您的情况下,它将创建一个新数据库test_finance。具有用户名的postgres用户django无权创建数据库,因此出现错误消息。

当您运行migrate或时syncdb,Django不会尝试创建finance数据库,因此不会出现任何错误。

您可以通过以超级用户身份在postgres shell中运行以下命令来向django用户添加createdb权限(此堆栈溢出答案的提示)。

=> ALTER USER django CREATEDB;

注意:ALTER USER <username> CREATEDB;命令中使用的用户名需要与Django设置文件中的数据库用户匹配。在这种情况下,原始张贴者将用户作为django上述答案。

When Django runs the test suite, it creates a new database, in your case test_finance. The postgres user with username django does not have permission to create a database, hence the error message.

When you run migrate or syncdb, Django does not try to create the finance database, so you don’t get any errors.

You can add the createdb permission to the django user by running the following command in the postgres shell as a superuser (hat tip to this stack overflow answer).

=> ALTER USER django CREATEDB;

Note: The username used in the ALTER USER <username> CREATEDB; command needs to match the database user in your Django settings files. In this case, the original poster, had the user as django the above answer.


回答 1

我找到了解决您问题的有趣方法。
实际上,对于MySQL,您可以授予不存在的数据库特权。
因此,您可以在设置中为测试数据库添加名称“ test_finance”:

    DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'finance',                      # Or path to database file if using sqlite3.
        'USER': 'django',                      # Not used with sqlite3.
        'PASSWORD': 'mydb123',                  # Not used with sqlite3.
        'HOST': '127.0.0.1',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
        'TEST': {
            'NAME': 'test_finance',
        },
    }
}

以root用户身份启动MySQL Shell:

mysql -u root -p

现在将所有特权授予该MySQL中不存在的数据库:

GRANT ALL PRIVILEGES ON test_finance.* TO 'django'@'localhost';

现在,Django将毫无问题地开始测试。

I have found interesting solution to your problem.
In fact for MySQL you can grant privileges for non-existing database.
So you can add name ‘test_finance’ for your test database in your settings:

    DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'finance',                      # Or path to database file if using sqlite3.
        'USER': 'django',                      # Not used with sqlite3.
        'PASSWORD': 'mydb123',                  # Not used with sqlite3.
        'HOST': '127.0.0.1',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
        'TEST': {
            'NAME': 'test_finance',
        },
    }
}

start MySQL shell as the root user:

mysql -u root -p

and now grant all privileges to this non-existing database in MySQL:

GRANT ALL PRIVILEGES ON test_finance.* TO 'django'@'localhost';

Now Django will start tests without any problems.


回答 2

对于Postgres,用户必须具有createdb权限。

ALTER ROLE miriam CREATEDB;

请参阅此文档:https : //docs.djangoproject.com/zh-CN/2.0/topics/testing/overview/#the-test-database

In the case of Postgres, the user must have createdb permission.

ALTER ROLE miriam CREATEDB;

See this documentation: https://docs.djangoproject.com/en/2.0/topics/testing/overview/#the-test-database


回答 3

如果数据库是mysql,那么这两个更改将完成任务。

1.打开mysite / mysite / settings.py

您的数据库设置应具有一个额外的TEST块,如projectname_test所示。

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'myproject',
        'USER': 'chandan',
        'PASSWORD': 'root',
        'HOST': 'localhost',
        'PORT': '3306',
        'TEST': {
            'NAME': 'myproject_test',
        },
    }
}

2.使用mysql命令提示符mysql工作台键入以下命令,将所有特权授予settings.py中指定的用户

GRANT ALL PRIVILEGES ON myproject_test.* TO 'chandan'@'localhost';

现在您可以运行 python manage.py test polls

If database is mysql then these two changes will get the things done.

1.Open mysite/mysite/settings.py

Your database settings should have an additional TEST block as shown with projectname_test.

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'myproject',
        'USER': 'chandan',
        'PASSWORD': 'root',
        'HOST': 'localhost',
        'PORT': '3306',
        'TEST': {
            'NAME': 'myproject_test',
        },
    }
}

2.Type the below command using mysql command prompt or mysql workbench to give all privilages to the user specified in settings.py

GRANT ALL PRIVILEGES ON myproject_test.* TO 'chandan'@'localhost';

Now you can run python manage.py test polls.


回答 4

如果您使用的docker-compose是对我有用的,则如下:

ALTER ROLE username CREATEDB;
GRANT ALL PRIVILEGES ON test_database_name.* TO 'username';

要么

ALTER ROLE username CREATEDB;
GRANT ALL PRIVILEGES ON *.* TO 'username'@'%';

我的设置如下所示:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'database_name',
        'USER': 'username',
        'PASSWORD': 'password',
        'HOST': 'db',
        'PORT': '3306',
    }
}

和我的docker-compose.yml样子如下:

version: '3'
services:
  web:
      build: .
      command: './wait_for_db_and_start_server.sh'
      env_file: env_web
      working_dir: /project_name
      links:
        - db
      volumes:
        - .:/volume_name
      ports:
        - "8000:8000"
      depends_on:
        - db
  db:
    image: mysql:5.7
    restart: always
    env_file: env_db
    working_dir: /db
    volumes:
      - ./Dump.sql:/db/Dump.sql
    ports:
      - "3306:3306"

If you are using docker-compose what worked for me was the following:

ALTER ROLE username CREATEDB;
GRANT ALL PRIVILEGES ON test_database_name.* TO 'username';

or

ALTER ROLE username CREATEDB;
GRANT ALL PRIVILEGES ON *.* TO 'username'@'%';

My settings looks like this:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'database_name',
        'USER': 'username',
        'PASSWORD': 'password',
        'HOST': 'db',
        'PORT': '3306',
    }
}

and my docker-compose.yml looks as follows:

version: '3'
services:
  web:
      build: .
      command: './wait_for_db_and_start_server.sh'
      env_file: env_web
      working_dir: /project_name
      links:
        - db
      volumes:
        - .:/volume_name
      ports:
        - "8000:8000"
      depends_on:
        - db
  db:
    image: mysql:5.7
    restart: always
    env_file: env_db
    working_dir: /db
    volumes:
      - ./Dump.sql:/db/Dump.sql
    ports:
      - "3306:3306"

回答 5

就我而言,GRANT PRIVILEGES解决方案不适用于Python 3.7.2Django 2.1.7MySQL 5.6.23 …我不知道为什么。

所以我决定使用SQLite作为TEST数据库…

DATABASES = {
    'default': {
        'NAME': 'productiondb',
        'ENGINE': 'mysql.connector.django',   # 'django.db.backends.mysql'
        'USER': '<user>',
        'PASSWORD': '<pass>',
        'HOST': 'localhost',
        'PORT': 3306,
        'OPTIONS': {
            'autocommit': True,
        },
        'TEST': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        },
    }
}

此后,TESTS的汽车运行就没有麻烦了:

$ python manage.py test
Creating test database for alias 'default'...
System check identified no issues (0 silenced).

Destroying test database for alias 'default'...
----------------------------------------------------------------------
Ran 0 tests in 0.000s

OK

Process finished with exit code 0

In my case, GRANT PRIVILEGES solutions didn’t work with Python 3.7.2, Django 2.1.7 and MySQL 5.6.23… I don’t know why.

So I decided to use SQLite as a TEST database…

DATABASES = {
    'default': {
        'NAME': 'productiondb',
        'ENGINE': 'mysql.connector.django',   # 'django.db.backends.mysql'
        'USER': '<user>',
        'PASSWORD': '<pass>',
        'HOST': 'localhost',
        'PORT': 3306,
        'OPTIONS': {
            'autocommit': True,
        },
        'TEST': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        },
    }
}

After that, TESTS car run without troubles:

$ python manage.py test
Creating test database for alias 'default'...
System check identified no issues (0 silenced).

Destroying test database for alias 'default'...
----------------------------------------------------------------------
Ran 0 tests in 0.000s

OK

Process finished with exit code 0

回答 6

哇,所以结合这里的所有答案和一点点调整,终于使我得到了一个适用于docker-compose,django和postgres的有效解决方案…

首先,noufal valapra给出的postgres命令不正确(或者可能不是最新的),它应该是:

ALTER USER docker WITH CREATEDB;

如果是docker-compose设置,它将进入init.sql文件,这就是我的样子:

CREATE USER docker;
ALTER USER docker WITH CREATEDB;
CREATE DATABASE djangodb;
GRANT ALL PRIVILEGES ON DATABASE djangodb TO docker;

然后用于postgres的Dockerfile如下所示:

FROM postgres:10.1-alpine
COPY init.sql /docker-entrypoint-initdb.d/

然后Django settings.py具有以下条目:

if 'RDS_DB_NAME' in os.environ:
    INTERNAL_DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql_psycopg2',
            'NAME': os.environ['RDS_DB_NAME'],
            'USER': os.environ['RDS_USERNAME'],
            'PASSWORD': os.environ['RDS_PASSWORD'],
            'HOST': os.environ['RDS_HOSTNAME'],
            'PORT': os.environ['RDS_PORT'],
        }
    }

和docker-compose看起来像这样:

版本:“ 3.6”

服务:

postgresdb:
  build:
    context: ./
    dockerfile: ./Dockerfile-postgresdb
  volumes:
    - postgresdata:/var/lib/postgresql/data/

django:
  build:
    context: ../
    dockerfile: ./docker/Dockerfile
  environment:
    - RDS_DB_NAME=djangodb
    - RDS_USERNAME=docker
    - RDS_PASSWORD=docker
    - RDS_HOSTNAME=postgresdb
    - RDS_PORT=5432

  stdin_open: true
  tty: true
  depends_on:
    - postgresdb

volumes:
    postgresdata:

Wow so combining all of the answers here with a little tweaking finally got me to a working solution for docker-compose, django, and postgres…

First the postgres command given by noufal valapra is not correct (or maybe just not current), it should be:

ALTER USER docker WITH CREATEDB;

In the case of a docker-compose setup, this will go in the init.sql file, this is what mine looks like:

CREATE USER docker;
ALTER USER docker WITH CREATEDB;
CREATE DATABASE djangodb;
GRANT ALL PRIVILEGES ON DATABASE djangodb TO docker;

Then the Dockerfile for postgres looks like this:

FROM postgres:10.1-alpine
COPY init.sql /docker-entrypoint-initdb.d/

Then the Django settings.py has this entry:

if 'RDS_DB_NAME' in os.environ:
    INTERNAL_DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql_psycopg2',
            'NAME': os.environ['RDS_DB_NAME'],
            'USER': os.environ['RDS_USERNAME'],
            'PASSWORD': os.environ['RDS_PASSWORD'],
            'HOST': os.environ['RDS_HOSTNAME'],
            'PORT': os.environ['RDS_PORT'],
        }
    }

and the docker-compose looks like this:

version: ‘3.6’

services:

postgresdb:
  build:
    context: ./
    dockerfile: ./Dockerfile-postgresdb
  volumes:
    - postgresdata:/var/lib/postgresql/data/

django:
  build:
    context: ../
    dockerfile: ./docker/Dockerfile
  environment:
    - RDS_DB_NAME=djangodb
    - RDS_USERNAME=docker
    - RDS_PASSWORD=docker
    - RDS_HOSTNAME=postgresdb
    - RDS_PORT=5432

  stdin_open: true
  tty: true
  depends_on:
    - postgresdb

volumes:
    postgresdata:

回答 7

也许您将测试置于暂停模式或作为后台工作。尝试fg在bash shell中使用命令。

Maybe you put your test in suspended mode or as a backgrounded job. Try with fg command in bash shell.


回答 8

超级用户帐户是保证测试顺利的最简单方法。因此,使django用户su 更简单的方法就是这样做ALTER django WITH SUPERUSER

有关更多信息https://www.postgresql.org/docs/current/sql-alteruser.html

A superuser account is the easiest way to guarantee smooth testing. so a simpler way of making the django user su is to do ALTER django WITH SUPERUSER .

for more information https://www.postgresql.org/docs/current/sql-alteruser.html


如何使用Django的ORM提取随机记录?

问题:如何使用Django的ORM提取随机记录?

我有一个模型,代表我在网站上展示的绘画。在主要网页上,我想展示其中的一些:最新的,大多数时间未访问的网页,最受欢迎的网页和随机的网页。

我正在使用Django 1.0.2。

尽管使用django模型可以轻松提取其中的前3个,但最后一个(随机)会给我带来一些麻烦。在我看来,我可以将代码进行如下编码:

number_of_records = models.Painting.objects.count()
random_index = int(random.random()*number_of_records)+1
random_paint = models.Painting.get(pk = random_index)

在我看来,这看起来并不像我想要的东西-这完全是数据库抽象的一部分,应该包含在模型中。另外,在这里,我需要处理已删除的记录(然后所有记录的数量将无法覆盖所有可能的键值)以及可能还有很多其他事情。

我还有其他方法可以做,最好是在模型抽象内进行?

I have a model that represents paintings I present on my site. On the main webpage I’d like to show some of them: newest, one that was not visited for most time, most popular one and a random one.

I’m using Django 1.0.2.

While first 3 of them are easy to pull using django models, last one (random) causes me some trouble. I can ofc code it in my view, to something like this:

number_of_records = models.Painting.objects.count()
random_index = int(random.random()*number_of_records)+1
random_paint = models.Painting.get(pk = random_index)

It doesn’t look like something I’d like to have in my view tho – this is entirely part of database abstraction and should be in the model. Also, here I need to take care of removed records (then number of all records won’t cover me all the possible key values) and probably lots of other things.

Any other options how I can do it, preferably somehow inside the model abstraction?


回答 0

使用order_by('?')将在生产的第二天杀死数据库服务器。更好的方法类似于“从关系数据库获取随机行”中所述

from django.db.models.aggregates import Count
from random import randint

class PaintingManager(models.Manager):
    def random(self):
        count = self.aggregate(count=Count('id'))['count']
        random_index = randint(0, count - 1)
        return self.all()[random_index]

Using order_by('?') will kill the db server on the second day in production. A better way is something like what is described in Getting a random row from a relational database.

from django.db.models.aggregates import Count
from random import randint

class PaintingManager(models.Manager):
    def random(self):
        count = self.aggregate(count=Count('id'))['count']
        random_index = randint(0, count - 1)
        return self.all()[random_index]

回答 1

只需使用:

MyModel.objects.order_by('?').first()

它记录在QuerySet API中

Simply use:

MyModel.objects.order_by('?').first()

It is documented in QuerySet API.


回答 2

如果使用MySQL(即使不了解其他数据库),即使对于中型表,order_by(’?’)[:N]的解决方案也非常慢。

order_by('?')[:N]将被翻译为SELECT ... FROM ... WHERE ... ORDER BY RAND() LIMIT N查询。

这意味着将对表中的每一行执行RAND()函数,然后将根据该函数的值对整个表进行排序,然后将返回前N条记录。如果您的桌子很小,那很好。但是在大多数情况下,这是一个非常慢的查询。

我写了一个简单的函数,即使id有孔(某些行已删除),该函数也可以工作:

def get_random_item(model, max_id=None):
    if max_id is None:
        max_id = model.objects.aggregate(Max('id')).values()[0]
    min_id = math.ceil(max_id*random.random())
    return model.objects.filter(id__gte=min_id)[0]

在几乎所有情况下,它都比order_by(’?’)快。

The solutions with order_by(‘?’)[:N] are extremely slow even for medium-sized tables if you use MySQL (don’t know about other databases).

order_by('?')[:N] will be translated to SELECT ... FROM ... WHERE ... ORDER BY RAND() LIMIT N query.

It means that for every row in table the RAND() function will be executed, then the whole table will be sorted according to value of this function and then first N records will be returned. If your tables are small, this is fine. But in most cases this is a very slow query.

I wrote simple function that works even if id’s have holes (some rows where deleted):

def get_random_item(model, max_id=None):
    if max_id is None:
        max_id = model.objects.aggregate(Max('id')).values()[0]
    min_id = math.ceil(max_id*random.random())
    return model.objects.filter(id__gte=min_id)[0]

It is faster than order_by(‘?’) in almost all cases.


回答 3

这是一个简单的解决方案:

from random import randint

count = Model.objects.count()
random_object = Model.objects.all()[randint(0, count - 1)] #single random object

Here’s a simple solution:

from random import randint

count = Model.objects.count()
random_object = Model.objects.all()[randint(0, count - 1)] #single random object

回答 4

您可以在模型上创建一个经理来执行此类操作。首先要明白一个经理是什么,Painting.objects方法是包含一个管理者all()filter()get(),等创建自己的管理器允许您预先筛选结果,并拥有所有这些相同的方法,以及您自己的自定义方法,工作的结果。

编辑:我修改了代码以反映该order_by['?']方法。注意,管理器返回无限数量的随机模型。因此,我加入了一些用法代码来展示如何仅获得一个模型。

from django.db import models

class RandomManager(models.Manager):
    def get_query_set(self):
        return super(RandomManager, self).get_query_set().order_by('?')

class Painting(models.Model):
    title = models.CharField(max_length=100)
    author = models.CharField(max_length=50)

    objects = models.Manager() # The default manager.
    randoms = RandomManager() # The random-specific manager.

用法

random_painting = Painting.randoms.all()[0]

最后,您可以在模型上拥有许多经理,因此可以随意创建LeastViewsManager()MostPopularManager()

You could create a manager on your model to do this sort of thing. To first understand what a manager is, the Painting.objects method is a manager that contains all(), filter(), get(), etc. Creating your own manager allows you to pre-filter results and have all these same methods, as well as your own custom methods, work on the results.

EDIT: I modified my code to reflect the order_by['?'] method. Note that the manager returns an unlimited number of random models. Because of this I’ve included a bit of usage code to show how to get just a single model.

from django.db import models

class RandomManager(models.Manager):
    def get_query_set(self):
        return super(RandomManager, self).get_query_set().order_by('?')

class Painting(models.Model):
    title = models.CharField(max_length=100)
    author = models.CharField(max_length=50)

    objects = models.Manager() # The default manager.
    randoms = RandomManager() # The random-specific manager.

Usage

random_painting = Painting.randoms.all()[0]

Lastly, you can have many managers on your models, so feel free to create a LeastViewsManager() or MostPopularManager().


回答 5

其他答案可能很慢(使用order_by('?')),或者使用多个SQL查询。这是一个示例解决方案,没有排序,只有一个查询(假设Postgres):

random_instance_or_none = Model.objects.raw('''
    select * from {0} limit 1
    offset floor(random() * (select count(*) from {0}))
'''.format(Model._meta.db_table)).first()

请注意,如果表为空,这将引发索引错误。为自己编写一个与模型无关的辅助函数以进行检查。

The other answers are either potentially slow (using order_by('?')) or use more than one SQL query. Here’s a sample solution with no ordering and just one query (assuming Postgres):

random_instance_or_none = Model.objects.raw('''
    select * from {0} limit 1
    offset floor(random() * (select count(*) from {0}))
'''.format(Model._meta.db_table)).first()

Be aware that this will raise an index error if the table is empty. Write yourself a model-agnostic helper function to check for that.


回答 6

只是一个简单的想法,我该怎么做:

def _get_random_service(self, professional):
    services = Service.objects.filter(professional=professional)
    i = randint(0, services.count()-1)
    return services[i]

Just a simple idea how I do it:

def _get_random_service(self, professional):
    services = Service.objects.filter(professional=professional)
    i = randint(0, services.count()-1)
    return services[i]

回答 7

嗨,我需要从查询集中选择一个随机记录,该记录的长度我也需要报告(即,网页生成了描述项,并且记录还剩下)

q = Entity.objects.filter(attribute_value='this or that')
item_count = q.count()
random_item = q[random.randomint(1,item_count+1)]

花费了一半的时间(0.7s和1.7s):

item_count = q.count()
random_item = random.choice(q)

我猜想它可以避免在选择随机条目之前拉低整个查询,并使我的系统对于足以重复访问某个页面的页面有足够的响应能力,以使用户希望减少item_count的计数。

Hi I needed to select a random record from a queryset who’s length I also needed to report (ie web page produced described item and said records left)

q = Entity.objects.filter(attribute_value='this or that')
item_count = q.count()
random_item = q[random.randomint(1,item_count+1)]

took half as long(0.7s vs 1.7s) as:

item_count = q.count()
random_item = random.choice(q)

I’m guessing it avoids pulling down the whole query before selecting the random entry and made my system responsive enough for a page that is accessed repeatedly for a repetitive task where users want to see the item_count count down.


回答 8

DB中的随机化在python中令人讨厌和更好。但是同时,将所有数据从数据库带到python内存只是忽略大多数结果(尤其是在生产环境中)并不是一个好主意。我们可能还需要某种过滤。

  1. 所以基本上我们在DB有数据,
  2. 我们想使用python的rand函数
  3. 后记会从DB提供所有必需的数据。

基本上,使用2个查询比在DB CPU中随机选择(在DB中计算)或加载整个数据(繁重的网络利用率)要便宜得多。解释的解决方案必须具有可伸缩性,因此尝试在此处进行计划将不适用于特别是带有过滤器,软/硬删除甚至带有is_public标志的生产环境。因为我们生成的随机ID可能会从数据库中删除或在过滤器中被删减。假定max_id(records)== count(records)是一个坏习惯。

(当然,如果您不删除与查询使用的数据相当的百分比,或者您不想使用任何种类的过滤器,并且如果您有信心,可以使用random id,然后可以使用random)

如果您只想要一项。请参阅(@Valter Silva)

import random

mgr = models.Painting.objects
qs = mgr.filter(...)
random_id = random.choice(1, qs.count())-1        # <--- [ First Query Hit ]

random_paint = qs[random_id] ## <-- [ Second Query Hit ]

如果您想要n个项目。

import random

req_no_of_random_items = 8        ## i need 8 random items.
qs = models.Painting.objects.filter(...)

## if u prefer to use random values often, you can keep this in cache. 
possible_ids = list(qs.values_list('id', flat=True))        # <--- [ First Query Hit ]

possible_ids = random.choices(possible_ids, k=8)
random_paint = qs.filter(pk__in=possible_ids) ## in a generic case to get 'n' items.

或者,如果您想为生产使用更优化的代码,请使用缓存功能获取产品ID:

from django.core.cache import cache

def id_set_cache(qs):
    key = "some_random_key_for_cache"
    id_set =  cache.get(key)
    if id_set is None:
        id_set = list(qs.values_list('id', flat=True)
        cache.set(key, id_set)
    retrun id_set

Randomization in DB feels nasty and better in python. But at the same time, it’s not a good idea to bring all the data from DB to python memory just to ignore most of the results (especially in the production environment). we might need some sort of filtering also.

  1. So Basically we have data at DB,
  2. we wanna use the rand function of python
  3. and afterwords bring up the whole required data from DB.

Basically using 2 queries will be much less expensive than picking random in DB CPU (computing in DB) or loading whole data (heavy Network Utilization). Solutions explained must need a scalable nature trying to plan here won’t work for a production environment espicially with filters, soft/hard deletes, or even with an is_public flag. because probably random id we generated might be deleted from the database or will be cut down in filters. Its a bad practice to assume max_id(records) == count(records).

(Ofcouce, If you do’not delete a percentage of data which is comparable to query uses, or if you dont wanna use any kond of filters, and if you are confident, random id which you can proceed with a random )

if you want only one items. Refer ( @Valter Silva )

import random

mgr = models.Painting.objects
qs = mgr.filter(...)
random_id = random.choice(1, qs.count())-1        # <--- [ First Query Hit ]

random_paint = qs[random_id] ## <-- [ Second Query Hit ]

if you want ‘n’ items.

import random

req_no_of_random_items = 8        ## i need 8 random items.
qs = models.Painting.objects.filter(...)

## if u prefer to use random values often, you can keep this in cache. 
possible_ids = list(qs.values_list('id', flat=True))        # <--- [ First Query Hit ]

possible_ids = random.choices(possible_ids, k=8)
random_paint = qs.filter(pk__in=possible_ids) ## in a generic case to get 'n' items.

or if you want to have a more optimized code for production, use a cachefunction to get ids of products:

from django.core.cache import cache

def id_set_cache(qs):
    key = "some_random_key_for_cache"
    id_set =  cache.get(key)
    if id_set is None:
        id_set = list(qs.values_list('id', flat=True)
        cache.set(key, id_set)
    retrun id_set

回答 9

仅需注意(一种非常常见的)特殊情况,如果表中有一个索引自动递增列且没有删除,那么执行随机选择的最佳方法是查询,例如:

SELECT * FROM table WHERE id = RAND() LIMIT 1

假设有一个名为id的表列。在Django中,您可以通过以下方式进行操作:

Painting.objects.raw('SELECT * FROM appname_painting WHERE id = RAND() LIMIT 1')

其中必须用应用程序名称替换appname。

通常,使用id列,可以使用以下命令更快地完成order_by(’?’):

Paiting.objects.raw(
        'SELECT * FROM auth_user WHERE id>=RAND() * (SELECT MAX(id) FROM auth_user) LIMIT %d' 
    % needed_count)

Just to note a (fairly common) special case, if there is a indexed auto-increment column in the table with no deletes, the optimum way to do a random select is a query like:

SELECT * FROM table WHERE id = RAND() LIMIT 1

that assumes such a column named id for table. In django you can do this by:

Painting.objects.raw('SELECT * FROM appname_painting WHERE id = RAND() LIMIT 1')

in which you must replace appname with your application name.

In General, with an id column, the order_by(‘?’) can be done much faster with:

Paiting.objects.raw(
        'SELECT * FROM auth_user WHERE id>=RAND() * (SELECT MAX(id) FROM auth_user) LIMIT %d' 
    % needed_count)

回答 10

强烈建议从关系数据库中获取随机行

因为使用django orm这样的事情,如果您的数据表很大,会使数据库服务器特别生气:

解决方案是提供一个模型管理器并手动编写SQL查询;)

更新

无需编写custom即可在任何数据库后端(甚至是非依赖数据库)上运行的另一种解决方案ModelManager在Django中从查询集获取随机对象

This is Highly recomended Getting a random row from a relational database

Because using django orm to do such a thing like that, will makes your db server angry specially if you have big data table :|

And the solution is provide a Model Manager and write the SQL query by hand ;)

Update:

Another solution which works on any database backend even non-rel ones without writing custom ModelManager. Getting Random objects from a Queryset in Django


回答 11

您可能想要使用对任何迭代器进行抽样相同的方法,尤其是如果您打算对多个项目进行抽样以创建样本集时,尤其如此。@MatijnPieters和@DzinX为此投入了很多思考:

def random_sampling(qs, N=1):
    """Sample any iterable (like a Django QuerySet) to retrieve N random elements

    Arguments:
      qs (iterable): Any iterable (like a Django QuerySet)
      N (int): Number of samples to retrieve at random from the iterable

    References:
      @DZinX:  https://stackoverflow.com/a/12583436/623735
      @MartinPieters: https://stackoverflow.com/a/12581484/623735
    """
    samples = []
    iterator = iter(qs)
    # Get the first `N` elements and put them in your results list to preallocate memory
    try:
        for _ in xrange(N):
            samples.append(iterator.next())
    except StopIteration:
        raise ValueError("N, the number of reuested samples, is larger than the length of the iterable.")
    random.shuffle(samples)  # Randomize your list of N objects
    # Now replace each element by a truly random sample
    for i, v in enumerate(qs, N):
        r = random.randint(0, i)
        if r < N:
            samples[r] = v  # at a decreasing rate, replace random items
    return samples

You may want to use the same approach that you’d use to sample any iterator, especially if you plan to sample multiple items to create a sample set. @MatijnPieters and @DzinX put a lot of thought into this:

def random_sampling(qs, N=1):
    """Sample any iterable (like a Django QuerySet) to retrieve N random elements

    Arguments:
      qs (iterable): Any iterable (like a Django QuerySet)
      N (int): Number of samples to retrieve at random from the iterable

    References:
      @DZinX:  https://stackoverflow.com/a/12583436/623735
      @MartinPieters: https://stackoverflow.com/a/12581484/623735
    """
    samples = []
    iterator = iter(qs)
    # Get the first `N` elements and put them in your results list to preallocate memory
    try:
        for _ in xrange(N):
            samples.append(iterator.next())
    except StopIteration:
        raise ValueError("N, the number of reuested samples, is larger than the length of the iterable.")
    random.shuffle(samples)  # Randomize your list of N objects
    # Now replace each element by a truly random sample
    for i, v in enumerate(qs, N):
        r = random.randint(0, i)
        if r < N:
            samples[r] = v  # at a decreasing rate, replace random items
    return samples

回答 12

一种更简单的方法包括简单地过滤到感兴趣的记录集,并根据random.sample需要选择尽可能多的记录集:

from myapp.models import MyModel
import random

my_queryset = MyModel.objects.filter(criteria=True)  # Returns a QuerySet
my_object = random.sample(my_queryset, 1)  # get a single random element from my_queryset
my_objects = random.sample(my_queryset, 5)  # get five random elements from my_queryset

注意,您应该有一些代码来验证它my_queryset是否为空。如果第一个参数包含的元素太少,则random.sample返回ValueError: sample larger than population

One much easier approach to this involves simply filtering down to the recordset of interest and using random.sample to select as many as you want:

from myapp.models import MyModel
import random

my_queryset = MyModel.objects.filter(criteria=True)  # Returns a QuerySet
my_object = random.sample(my_queryset, 1)  # get a single random element from my_queryset
my_objects = random.sample(my_queryset, 5)  # get five random elements from my_queryset

Note that you should have some code in place to verify that my_queryset is not empty; random.sample returns ValueError: sample larger than population if the first argument contains too few elements.


回答 13

自动删除不删除主键的方法

如果您有一个表,其中主键是一个没有间隔的连续整数,那么以下方法应该有效:

import random
max_id = MyModel.objects.last().id
random_id = random.randint(0, max_id)
random_obj = MyModel.objects.get(pk=random_id)

与遍历表的所有行的其他方法相比,此方法效率更高。尽管它确实需要两个数据库查询,但两者都很简单。此外,它很简单,不需要定义任何额外的类。但是,它的适用性仅限于具有自动递增主键的表,其中行从未删除,因此id序列中没有空格。

在删除行(例如空格)的情况下,如果重试该方法直到随机选择一个现有的主键,该方法仍然可以使用。

参考文献

Method for auto-incrementing primary key with no deletes

If you have a table where the primary key is a sequential integer with no gaps, then the following method should work:

import random
max_id = MyModel.objects.last().id
random_id = random.randint(0, max_id)
random_obj = MyModel.objects.get(pk=random_id)

This method is much more efficient than other methods here that iterate through all rows of the table. While it does require two database queries, both are trivial. Furthermore, it’s simple and doesn’t require defining any extra classes. However, it’s applicability is limited to tables with an auto-incrementing primary key where rows have never deleted, such that there are no gaps in the sequence of ids.

In the case where rows have been deleted such that are gaps, this method could still work if it is retried until an existing primary key is randomly selected.

References


回答 14

我有一个非常简单的解决方案,使自定义经理:

class RandomManager(models.Manager):
    def random(self):
        return random.choice(self.all())

然后添加模型:

class Example(models.Model):
    name = models.CharField(max_length=128)
    objects = RandomManager()

现在,您可以使用它:

Example.objects.random()

I got very simple solution, make custom manager:

class RandomManager(models.Manager):
    def random(self):
        return random.choice(self.all())

and then add in model:

class Example(models.Model):
    name = models.CharField(max_length=128)
    objects = RandomManager()

Now, you can use it:

Example.objects.random()

如何从外部访问本地Django Web服务器

问题:如何从外部访问本地Django Web服务器

我按照此处的说明使用内置的网络服务器运行Django,并能够使用成功运行它python manage.py runserver。如果我从Web服务器本地访问127.0.0.1:port,则将显示Django页面,表明它可以工作。

我意识到Django网络服务器不是生产服务器,但对我而言,测试至关重要的是,它可以从外部环境进行访问-即,不是从服务器上的Web浏览器而是从其他计算机上进行访问。

我试过了:

http://mywebserver:port_django_runs_on

但它没有用。我还尝试使用IP(基于ifconfig)访问:

http://myipaddress:port_django_runs_on 

这也不起作用。

Web服务器正在运行,因此必须从外部可以访问它,但我不确定如何。我没有在Apache上配置Django,但我在Apache上运行Linux。

有关如何执行此操作的任何想法?

I followed the instructions here to run Django using the built-in webserver and was able to successfully run it using python manage.py runserver. If I access 127.0.0.1:port locally from the webserver, I get the Django page indicating it worked.

I realize the Django webserver is not a production server, but it’s important for me for testing purposes to be able to access it from the outside world — i.e. not from a web browser on the server, but from a different computer.

I tried:

http://mywebserver:port_django_runs_on

but it did not work. I also tried using the IP instead (based on ifconfig) to access:

http://myipaddress:port_django_runs_on 

which did not work either.

The web server is running so it must be accessible from the outside, I’m just not sure how. I am running Linux with Apache, though I have not configured Django with Apache.

Any ideas on how to do this?


回答 0

您必须运行开发服务器,以使其侦听网络接口

例如

python manage.py runserver 0.0.0.0:8000

在端口8000的每个接口上侦听。

使用IP或主机名访问Web服务器都没有关系。我猜您仍在自己的局域网中。
如果您确实要从外部访问服务器,则还必须将路由器配置为将端口转发到例如8000服务器。


检查服务器上的防火墙,是否允许使用中端口的传入连接!

假设您可以成功地从外部访问Apache服务器,则还可以尝试以下操作:

  • 停止Apache服务器,以便该端口80可用。
  • 使用以下命令启动开发服务器 sudo python manage.py runserver 0.0.0.0:80

You have to run the development server such that it listens on the interface to your network.

E.g.

python manage.py runserver 0.0.0.0:8000

listens on every interface on port 8000.

It doesn’t matter whether you access the webserver with the IP or the hostname. I guess you are still in your own LAN.
If you really want to access the server from outside, you also have to configure your router to forward port e.g. 8000 to your server.


Check your firewall on your server whether incoming connections to the port in use are allowed!

Assuming you can access your Apache server from the outside successfully, you can also try this:

  • Stop the Apache server, so that port 80 is free.
  • Start the development server with sudo python manage.py runserver 0.0.0.0:80

回答 1

我必须将此行添加到settings.py才能使其正常工作(否则从另一台计算机访问时显示错误)

ALLOWED_HOSTS = ['*']

然后使用以下命令运行服务器:

python manage.py runserver 0.0.0.0:9595

还要确保防火墙允许连接到该端口

I had to add this line to settings.py in order to make it work (otherwise it showed an error when accessed from another computer)

ALLOWED_HOSTS = ['*']

then ran the server with:

python manage.py runserver 0.0.0.0:9595

Also ensure that the firewall allows connections to that port


回答 2

从以下选择一个或多个:

  • 您的应用程序未成功侦听预期的IP:PORT
    • 因为您尚未成功配置
    • 因为用户没有权限
  • 您的应用程序已在预期的IP:PORT上成功侦听,但客户端无法访问它,因为
    • 服务器本地iptables阻止了它。
    • 防火墙阻止了它。

因此,您可以通过lsof -i在计算机上以root用户身份运行来检查您的应用程序是否成功侦听,并查找python具有您指定的相应端口的条目。

非root用户通常不能绑定到<1024的端口。

您需要查看一下iptables -nvL是否存在阻止访问您要绑定应用程序的ip:port的规则。

如果有上游防火墙,而您对其了解不多,则需要与网络管理员联系。

Pick one or more from:

  • Your application isn’t successfully listening on the intended IP:PORT
    • Because you haven’t configured it successfully
    • Because the user doesn’t have permission to
  • Your application is listening successfully on the intended IP:PORT, but clients can’t reach it because
    • The server local iptables prevents it.
    • A firewall prevents it.

So, you can check that your application is listening successfully by running lsof -i as root on the machine and look for a python entry with the corresponding port you’ve specified.

Non-root users generally cannot bind to ports < 1024.

You’ll need to look at iptables -nvL to see if there’s a rule that would prevent access to the ip:port that you are trying to bind your application to.

If there is an upstream firewall and you don’t know much about it, you’ll need to talk to your network administrators.


回答 3

只是这样做:

python manage.py runserver 0:8000

通过以上命令,您实际上是将其绑定到外部IP地址。因此,现在当您使用端口号访问IP地址时,就可以在浏览器中毫无问题地访问它。

只需在浏览器地址栏中输入以下内容:

<your ip address>:8000

例如:

192.168.1.130:8000

您可能需要编辑settings.py在最后一行的settings.py中添加以下内容:

ALLOWED_HOSTS = ['*']

希望这会有所帮助…

just do this:

python manage.py runserver 0:8000

by the above command you are actually binding it to the external IP address. so now when you access your IP address with the port number, you will be able to access it in the browser without any problem.

just type in the following in the browser address bar:

<your ip address>:8000

eg:

192.168.1.130:8000

you may have to edit the settings.py add the following in the settings.py in the last line:

ALLOWED_HOSTS = ['*']

hope this will help…


回答 4

对于AWS用户。

我必须按照以下步骤到达目的地。

1)确保在sudo级别安装了pip和django

  • 须藤apt-get install python-pip
  • sudo pip安装Django

2)确保安全组入站规则包括端口80上的http(0.0.0.0/0)

  • 通过AWS控制台配置

3)将公共IP和DNS添加到ALLOWED_HOSTS

  • ALLOWED_HOSTS是一个列表对象,您可以在settings.py中找到
  • ALLOWED_HOSTS = [“ 75.254.65.19”,“ ec2-54-528-27-21.compute-1.amazonaws.com”]

4)在端口80上使用sudo启动开发服务器

  • 须藤python manage.py runserver 0:80

现在可以从以下任一站点访问该站点(不需要:80,因为http默认是):

  • [公共DNS],即ec2-54-528-27-21.compute-1.amazonaws.com
  • [公共IP],即75.254.65.19

For AWS users.

I had to use the following steps to get there.

1) Ensure that pip and django are installed at the sudo level

  • sudo apt-get install python-pip
  • sudo pip install django

2) Ensure that security group in-bound rules includ http on port 80 for 0.0.0.0/0

  • configured through AWS console

3) Add Public IP and DNS to ALLOWED_HOSTS

  • ALLOWED_HOSTS is a list object that you can find in settings.py
  • ALLOWED_HOSTS = [“75.254.65.19″,”ec2-54-528-27-21.compute-1.amazonaws.com”]

4) Launch development server with sudo on port 80

  • sudo python manage.py runserver 0:80

Site now available at either of the following (no need for :80 as that is default for http):

  • [Public DNS] i.e. ec2-54-528-27-21.compute-1.amazonaws.com
  • [Public IP] i.e 75.254.65.19

回答 5

我要在这里添加:

  1. sudo python manage.py runserver 80

  2. 转到您的电话或计算机,然后192.168.0.12在浏览器中输入计算机的内部IP(例如)。

此时,您应该已连接到Django服务器。

这也应该在没有sudo的情况下起作用:

python manage.py runserver 0.0.0.0:8000

I’m going to add this here:

  1. sudo python manage.py runserver 80

  2. Go to your phone or computer and enter your computers internal IP (e.g 192.168.0.12) into the browser.

At this point you should be connected to the Django server.

This should also work without sudo:

python manage.py runserver 0.0.0.0:8000

回答 6

如果您使用的是Docker,则需要确保端口也已公开

If you are using Docker you need to make sure ports are exposed as well


回答 7

2020年更新方法

python manage.py runserver yourIp:8000

ALLOWED_HOSTS = ["*"]

UPDATED 2020 TRY THIS WAY

python manage.py runserver yourIp:8000

ALLOWED_HOSTS = ["*"]

回答 8

在终端中安装ngrok

sudo apt-get install -y ngrok-client

运行之后:

ngrok http 8000
or 
ngrok http example.com:9000 

install ngrok in terminal

sudo apt-get install -y ngrok-client

after that run:

ngrok http 8000
or 
ngrok http example.com:9000 

Django CSRF检查失败,并带有Ajax POST请求

问题:Django CSRF检查失败,并带有Ajax POST请求

我可以通过我的AJAX帖子向遵循Django CSRF保护机制的人员提供帮助。我按照这里的指示进行:

http://docs.djangoproject.com/en/dev/ref/contrib/csrf/

我已经完全复制了该页面上的AJAX示例代码:

http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax

getCookie('csrftoken')xhr.setRequestHeader呼叫之前打印了警报内容,并确实在其中填充了一些数据。我不确定如何验证令牌是否正确,但是我鼓励它正在查找并发送一些消息。

但是Django仍然拒绝我的AJAX帖子。

这是我的JavaScript:

$.post("/memorize/", data, function (result) {
    if (result != "failure") {
        get_random_card();
    }
    else {
        alert("Failed to save card data.");
    }
});

这是我在Django中看到的错误:

[23 / Feb / 2011 22:08:29]“ POST / memorize / HTTP / 1.1” 403 2332

我确定我缺少某些东西,也许很简单,但是我不知道它是什么。我在SO周围搜索,并看到了一些有关通过csrf_exempt装饰器关闭CSRF检查以获取我的视图的信息,但是我发现这没有吸引力。我已经尝试过了,并且可以工作,但是我宁愿让POST按照Django期望的方式工作。

以防万一,这是我的观点正在做的要点:

def myview(request):

    profile = request.user.profile

    if request.method == 'POST':
        """
        Process the post...
        """
        return HttpResponseRedirect('/memorize/')
    else: # request.method == 'GET'

        ajax = request.GET.has_key('ajax')

        """
        Some irrelevent code...
        """

        if ajax:
            response = HttpResponse()
            profile.get_stack_json(response)
            return response
        else:
            """
            Get data to send along with the content of the page.
            """

        return render_to_response('memorize/memorize.html',
                """ My data """
                context_instance=RequestContext(request))

感谢您的回复!

I could use some help complying with Django’s CSRF protection mechanism via my AJAX post. I’ve followed the directions here:

http://docs.djangoproject.com/en/dev/ref/contrib/csrf/

I’ve copied the AJAX sample code they have on that page exactly:

http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax

I put an alert printing the contents of getCookie('csrftoken') before the xhr.setRequestHeader call and it is indeed populated with some data. I’m not sure how to verify that the token is correct, but I’m encouraged that it’s finding and sending something.

But Django is still rejecting my AJAX post.

Here’s my JavaScript:

$.post("/memorize/", data, function (result) {
    if (result != "failure") {
        get_random_card();
    }
    else {
        alert("Failed to save card data.");
    }
});

Here’s the error I’m seeing from Django:

[23/Feb/2011 22:08:29] “POST /memorize/ HTTP/1.1” 403 2332

I’m sure I’m missing something, and maybe it’s simple, but I don’t know what it is. I’ve searched around SO and saw some information about turning off the CSRF check for my view via the csrf_exempt decorator, but I find that unappealing. I’ve tried that out and it works, but I’d rather get my POST to work the way Django was designed to expect it, if possible.

Just in case it’s helpful, here’s the gist of what my view is doing:

def myview(request):

    profile = request.user.profile

    if request.method == 'POST':
        """
        Process the post...
        """
        return HttpResponseRedirect('/memorize/')
    else: # request.method == 'GET'

        ajax = request.GET.has_key('ajax')

        """
        Some irrelevent code...
        """

        if ajax:
            response = HttpResponse()
            profile.get_stack_json(response)
            return response
        else:
            """
            Get data to send along with the content of the page.
            """

        return render_to_response('memorize/memorize.html',
                """ My data """
                context_instance=RequestContext(request))

Thanks for your replies!


回答 0

真正的解决方案

好的,我设法找出问题所在。它位于Javascript(正如我在下面建议的)代码中。

您需要的是:

$.ajaxSetup({ 
     beforeSend: function(xhr, settings) {
         function getCookie(name) {
             var cookieValue = null;
             if (document.cookie && document.cookie != '') {
                 var cookies = document.cookie.split(';');
                 for (var i = 0; i < cookies.length; i++) {
                     var cookie = jQuery.trim(cookies[i]);
                     // Does this cookie string begin with the name we want?
                     if (cookie.substring(0, name.length + 1) == (name + '=')) {
                         cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                         break;
                     }
                 }
             }
             return cookieValue;
         }
         if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
             // Only send the token to relative URLs i.e. locally.
             xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
         }
     } 
});

而不是官方文档中发布的代码:https//docs.djangoproject.com/en/2.2/ref/csrf/

工作代码来自以下Django条目:http : //www.djangoproject.com/weblog/2011/feb/08/security/

因此,一般的解决方案是:“使用ajaxSetup处理程序而不是ajaxSend处理程序”。我不知道为什么会这样。但这对我有用:)

以前的帖子(无答案)

我实际上遇到了同样的问题。

它在更新到Django 1.2.5之后发生-在Django 1.2.4中AJAX POST请求没有错误(AJAX不受任何保护,但效果很好)。

就像OP一样,我尝试了Django文档中发布的JavaScript代码段。我正在使用jQuery 1.5。我也在使用“ django.middleware.csrf.CsrfViewMiddleware”中间件。

我尝试遵循中间件代码,但我知道它在此方面失败:

request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '')

然后

if request_csrf_token != csrf_token:
    return self._reject(request, REASON_BAD_TOKEN)

此“如果”为true,因为“ request_csrf_token”为空。

基本上,这意味着未设置标头。那么此JS行有什么问题吗:

xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));

我希望提供的详细信息将有助于我们解决问题:)

Real solution

Ok, I managed to trace the problem down. It lies in the Javascript (as I suggested below) code.

What you need is this:

$.ajaxSetup({ 
     beforeSend: function(xhr, settings) {
         function getCookie(name) {
             var cookieValue = null;
             if (document.cookie && document.cookie != '') {
                 var cookies = document.cookie.split(';');
                 for (var i = 0; i < cookies.length; i++) {
                     var cookie = jQuery.trim(cookies[i]);
                     // Does this cookie string begin with the name we want?
                     if (cookie.substring(0, name.length + 1) == (name + '=')) {
                         cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                         break;
                     }
                 }
             }
             return cookieValue;
         }
         if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
             // Only send the token to relative URLs i.e. locally.
             xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
         }
     } 
});

instead of the code posted in the official docs: https://docs.djangoproject.com/en/2.2/ref/csrf/

The working code, comes from this Django entry: http://www.djangoproject.com/weblog/2011/feb/08/security/

So the general solution is: “use ajaxSetup handler instead of ajaxSend handler”. I don’t know why it works. But it works for me :)

Previous post (without answer)

I’m experiencing the same problem actually.

It occurs after updating to Django 1.2.5 – there were no errors with AJAX POST requests in Django 1.2.4 (AJAX wasn’t protected in any way, but it worked just fine).

Just like OP, I have tried the JavaScript snippet posted in Django documentation. I’m using jQuery 1.5. I’m also using the “django.middleware.csrf.CsrfViewMiddleware” middleware.

I tried to follow the the middleware code and I know that it fails on this:

request_csrf_token = request.META.get('HTTP_X_CSRFTOKEN', '')

and then

if request_csrf_token != csrf_token:
    return self._reject(request, REASON_BAD_TOKEN)

this “if” is true, because “request_csrf_token” is empty.

Basically it means that the header is NOT set. So is there anything wrong with this JS line:

xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));

?

I hope that provided details will help us in resolving the issue :)


回答 1

如果使用该$.ajax函数,则可以简单地将csrf令牌添加到数据主体中:

$.ajax({
    data: {
        somedata: 'somedata',
        moredata: 'moredata',
        csrfmiddlewaretoken: '{{ csrf_token }}'
    },

If you use the $.ajax function, you can simply add the csrf token in the data body:

$.ajax({
    data: {
        somedata: 'somedata',
        moredata: 'moredata',
        csrfmiddlewaretoken: '{{ csrf_token }}'
    },

回答 2

将此行添加到您的jQuery代码中:

$.ajaxSetup({
  data: {csrfmiddlewaretoken: '{{ csrf_token }}' },
});

并做了。

Add this line to your jQuery code:

$.ajaxSetup({
  data: {csrfmiddlewaretoken: '{{ csrf_token }}' },
});

and done.


回答 3

问题是因为django希望将cookie中的值作为表单数据的一部分传递回去。上一个答案中的代码使javascript能够找出cookie值并将其放入表单数据中。从技术的角度来看,这是一种不错的方法,但是它确实有些冗长。

过去,我更简单地通过获取JavaScript将令牌值放入发布数据中来完成此操作。

如果您在模板中使用{%csrf_token%},则会发出带有该值的隐藏表单字段。但是,如果您使用{{csrf_token}},则只会获得令牌的裸值,因此可以在javascript中使用此代码…。

csrf_token = "{{ csrf_token }}";

然后,您可以在哈希中添加所需的键名称,然后将其作为数据提交给ajax调用。

The issue is because django is expecting the value from the cookie to be passed back as part of the form data. The code from the previous answer is getting javascript to hunt out the cookie value and put it into the form data. Thats a lovely way of doing it from a technical point of view, but it does look a bit verbose.

In the past, I have done it more simply by getting the javascript to put the token value into the post data.

If you use {% csrf_token %} in your template, you will get a hidden form field emitted that carries the value. But, if you use {{ csrf_token }} you will just get the bare value of the token, so you can use this in javascript like this….

csrf_token = "{{ csrf_token }}";

Then you can include that, with the required key name in the hash you then submit as the data to the ajax call.


回答 4

{% csrf_token %}在HTML模板放里面<form></form>

转换为:

<input type='hidden' name='csrfmiddlewaretoken' value='Sdgrw2HfynbFgPcZ5sjaoAI5zsMZ4wZR' />

所以为什么不像这样在您的JS中grep它:

token = $("#change_password-form").find('input[name=csrfmiddlewaretoken]').val()

然后通过它,例如进行一些POST,例如:

$.post( "/panel/change_password/", {foo: bar, csrfmiddlewaretoken: token}, function(data){
    console.log(data);
});

The {% csrf_token %} put in html templates inside <form></form>

translates to something like:

<input type='hidden' name='csrfmiddlewaretoken' value='Sdgrw2HfynbFgPcZ5sjaoAI5zsMZ4wZR' />

so why not just grep it in your JS like this:

token = $("#change_password-form").find('input[name=csrfmiddlewaretoken]').val()

and then pass it e.g doing some POST, like:

$.post( "/panel/change_password/", {foo: bar, csrfmiddlewaretoken: token}, function(data){
    console.log(data);
});

回答 5

非jQuery答案:

var csrfcookie = function() {
    var cookieValue = null,
        name = 'csrftoken';
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = cookies[i].trim();
            if (cookie.substring(0, name.length + 1) == (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
};

用法:

var request = new XMLHttpRequest();
request.open('POST', url, true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
request.setRequestHeader('X-CSRFToken', csrfcookie());
request.onload = callback;
request.send(data);

Non-jquery answer:

var csrfcookie = function() {
    var cookieValue = null,
        name = 'csrftoken';
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = cookies[i].trim();
            if (cookie.substring(0, name.length + 1) == (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
};

usage:

var request = new XMLHttpRequest();
request.open('POST', url, true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
request.setRequestHeader('X-CSRFToken', csrfcookie());
request.onload = callback;
request.send(data);

回答 6

如果您的表单在没有JS的Django中正确发布,那么您应该能够使用Ajax逐步增强它,而不会造成任何黑客攻击或csrf令牌的混乱传递。只需序列化整个表单,它将自动选择所有表单字段,包括隐藏的csrf字段:

$('#myForm').submit(function(){
    var action = $(this).attr('action');
    var that = $(this);
    $.ajax({
        url: action,
        type: 'POST',
        data: that.serialize()
        ,success: function(data){
            console.log('Success!');
        }
    });
    return false;
});

我已经使用Django 1.3+和jQuery 1.5+进行了测试。显然,这将适用于任何HTML表单,而不仅仅是Django应用。

If your form posts correctly in Django without JS, you should be able to progressively enhance it with ajax without any hacking or messy passing of the csrf token. Just serialize the whole form and that will automatically pick up all your form fields including the hidden csrf field:

$('#myForm').submit(function(){
    var action = $(this).attr('action');
    var that = $(this);
    $.ajax({
        url: action,
        type: 'POST',
        data: that.serialize()
        ,success: function(data){
            console.log('Success!');
        }
    });
    return false;
});

I’ve tested this with Django 1.3+ and jQuery 1.5+. Obviously this will work for any HTML form, not just Django apps.


回答 7

将Firefox与Firebug结合使用。触发ajax请求时,打开“控制台”选项卡。这样一来,DEBUG=True您将得到漂亮的django错误页面作为响应,甚至可以在控制台选项卡中看到ajax响应的呈现的html。

然后,您将知道错误是什么。

Use Firefox with Firebug. Open the ‘Console’ tab while firing the ajax request. With DEBUG=True you get the nice django error page as response and you can even see the rendered html of the ajax response in the console tab.

Then you will know what the error is.


回答 8

可接受的答案很可能是鲱鱼。Django 1.2.4和1.2.5之间的区别是AJAX请求需要CSRF令牌。

我在Django 1.3上遇到了这个问题,这是由于未设置CSRF cookie引起的首先。除非必须,否则Django不会设置cookie。因此,运行在Django 1.2.4上的排他或大量ajax站点可能永远不会向客户端发送令牌,然后需要令牌的升级会导致403错误。

理想的解决方法是在这里:http : //docs.djangoproject.com/en/dev/ref/contrib/csrf/#page-uses-ajax-without-any-html-form
但您必须等待1.4,除非这只是跟上代码的文档

编辑

还要注意,以后的Django文档注意到jQuery 1.5中的一个错误,因此请确保您将Django建议的代码与1.5.1或更高版本一起使用:http : //docs.djangoproject.com/en/1.3/ref/contrib/csrf/#阿贾克斯

The accepted answer is most likely a red herring. The difference between Django 1.2.4 and 1.2.5 was the requirement for a CSRF token for AJAX requests.

I came across this problem on Django 1.3 and it was caused by the CSRF cookie not being set in the first place. Django will not set the cookie unless it has to. So an exclusively or heavily ajax site running on Django 1.2.4 would potentially never have sent a token to the client and then the upgrade requiring the token would cause the 403 errors.

The ideal fix is here: http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#page-uses-ajax-without-any-html-form
but you’d have to wait for 1.4 unless this is just documentation catching up with the code

Edit

Note also that the later Django docs note a bug in jQuery 1.5 so ensure you are using 1.5.1 or later with the Django suggested code: https://docs.djangoproject.com/en/dev/ref/csrf/#ajax


回答 9

似乎没有人提到过使用X-CSRFTokenheader和来在纯JS中执行此操作的方法{{ csrf_token }},因此这是一个简单的解决方案,您无需搜索cookie或DOM:

var xhttp = new XMLHttpRequest();
xhttp.open("POST", url, true);
xhttp.setRequestHeader("X-CSRFToken", "{{ csrf_token }}");
xhttp.send();

It seems nobody has mentioned how to do this in pure JS using the X-CSRFToken header and {{ csrf_token }}, so here’s a simple solution where you don’t need to search through the cookies or the DOM:

var xhttp = new XMLHttpRequest();
xhttp.open("POST", url, true);
xhttp.setRequestHeader("X-CSRFToken", "{{ csrf_token }}");
xhttp.send();

回答 10

由于当前答案中没有任何地方说明,因此如果您不将 js 嵌入模板中,最快的解决方案是:

<script type="text/javascript"> window.CSRF_TOKEN = "{{ csrf_token }}"; </script>你的模板里面引用之前的script.js文件,然后添加csrfmiddlewaretoken到您的data字典在你的js文件:

$.ajax({
            type: 'POST',
            url: somepathname + "do_it/",
            data: {csrfmiddlewaretoken: window.CSRF_TOKEN},
            success: function() {
                console.log("Success!");
            }
        })

As it is not stated anywhere in the current answers, the fastest solution if you are not embedding js into your template is:

Put <script type="text/javascript"> window.CSRF_TOKEN = "{{ csrf_token }}"; </script> before your reference to script.js file in your template, then add csrfmiddlewaretoken into your data dictionary in your js file:

$.ajax({
            type: 'POST',
            url: somepathname + "do_it/",
            data: {csrfmiddlewaretoken: window.CSRF_TOKEN},
            success: function() {
                console.log("Success!");
            }
        })

回答 11

我刚刚遇到了一些不同但相似的情况。不能100%确定是否可以解决您的问题,但是我通过设置POST参数’csrfmiddlewaretoken’并使用适当的cookie值字符串解决了Django 1.3的问题,该参数通常由Django的home HTML形式返回。带有'{%csrf_token%}’标签的模板系统。我没有尝试使用较旧的Django,只是在Django1.3上发生并解决了。我的问题是,通过Ajax从表单提交的第一个请求已成功完成,但从完全相同的第二次请求失败,导致了403状态,即使标头’X-CSRFToken’也已正确放置CSRF令牌值就像第一次尝试一样。希望这可以帮助。

问候,

I’ve just encountered a bit different but similar situation. Not 100% sure if it’d be a resolution to your case, but I resolved the issue for Django 1.3 by setting a POST parameter ‘csrfmiddlewaretoken’ with the proper cookie value string which is usually returned within the form of your home HTML by Django’s template system with ‘{% csrf_token %}’ tag. I did not try on the older Django, just happened and resolved on Django1.3. My problem was that the first request submitted via Ajax from a form was successfully done but the second attempt from the exact same from failed, resulted in 403 state even though the header ‘X-CSRFToken’ is correctly placed with the CSRF token value as well as in the case of the first attempt. Hope this helps.

Regards,

Hiro


回答 12

您可以将此js粘贴到您的html文件中,请记住将其放在其他js函数之前

<script>
  // using jQuery
  function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie != '') {
      var cookies = document.cookie.split(';');
      for (var i = 0; i < cookies.length; i++) {
        var cookie = jQuery.trim(cookies[i]);
        // Does this cookie string begin with the name we want?
        if (cookie.substring(0, name.length + 1) == (name + '=')) {
          cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
          break;
        }
      }
    }
    return cookieValue;
  }

  function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
  }

  $(document).ready(function() {
    var csrftoken = getCookie('csrftoken');
    $.ajaxSetup({
      beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
          xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
      }
    });
  });
</script>

You can paste this js into your html file, remember put it before other js function

<script>
  // using jQuery
  function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie != '') {
      var cookies = document.cookie.split(';');
      for (var i = 0; i < cookies.length; i++) {
        var cookie = jQuery.trim(cookies[i]);
        // Does this cookie string begin with the name we want?
        if (cookie.substring(0, name.length + 1) == (name + '=')) {
          cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
          break;
        }
      }
    }
    return cookieValue;
  }

  function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
  }

  $(document).ready(function() {
    var csrftoken = getCookie('csrftoken');
    $.ajaxSetup({
      beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
          xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
      }
    });
  });
</script>

回答 13

每个会话(即每次登录)都分配一个CSRF令牌。因此,在希望获取用户输入的某些数据并将其作为ajax调用发送给受csrf_protect装饰器保护的某个函数之前,请先尝试查找正在被调用的函数,然后再从用户获取此数据。例如,必须渲染一些模板,以便用户在其上输入数据。该模板由某些功能渲染。在此函数中,您可以按以下方式获取csrf令牌:csrf = request.COOKIES [‘csrftoken’]现在在上下文字典中传递此csrf值,针对该字典呈现相关模板。现在在该模板中编写以下行:现在,在您的javascript函数中,在发出ajax请求之前,请编写:var csrf = $(’#csrf’)。val()这将选择传递给模板的令牌的值并将其存储在变量csrf中。现在,在进行ajax调用时,在您的帖子数据中,还要传递此值:“ csrfmiddlewaretoken”:csrf

即使您未实现Django表单,这也将起作用。

实际上,这里的逻辑是:您需要可以从请求中获取的令牌。因此,您只需要确定登录后立即调用的函数即可。一旦有了此令牌,就可以再次调用ajax来获取它,或者将其传递给可被ajax访问的模板。

One CSRF token is assigned to every session ( i.e. every time you log in). So before you wish to get some data entered by user and send that as ajax call to some function which is protected by csrf_protect decorator, try to find the functions that are being called before you are getting this data from user. E.g. some template must be being rendered on which your user is entering data. That template is being rendered by some function. In this function you can get csrf token as follows: csrf = request.COOKIES[‘csrftoken’] Now pass this csrf value in context dictionary against which template in question is being rendered. Now in that template write this line: Now in your javascript function, before making ajax request, write this: var csrf = $(‘#csrf’).val() this will pick value of token passed to template and store it in variable csrf. Now while making ajax call, in your post data, pass this value as well : “csrfmiddlewaretoken”: csrf

This will work even if you are not implementing django forms.

In fact, logic over here is : You need token which you can get from request. So you just need to figure out the function being called immediately after log in. Once you have this token, either make another ajax call to get it or pass it to some template which is accessible by your ajax.


回答 14

对于遇到此问题并尝试调试的人:

1)django csrf检查(假设您要发送一个)是 这里

2)在我的情况下,将settings.CSRF_HEADER_NAME其设置为“ HTTP_X_CSRFTOKEN”,而我的AJAX调用正在发送名为“ HTTP_X_CSRF_TOKEN”的标头,因此无法正常工作。我可以在AJAX调用或Django设置中更改它。

3)如果您选择在服务器端进行更改,请找到django的安装位置,并csrf middleware在使用的.f中放置一个断点virtualenv,它将类似于:~/.envs/my-project/lib/python2.7/site-packages/django/middleware/csrf.py

import ipdb; ipdb.set_trace() # breakpoint!!
if request_csrf_token == "":
    # Fall back to X-CSRFToken, to make things easier for AJAX,
    # and possible for PUT/DELETE.
    request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')

然后,确保csrf令牌是从request.META正确获取的。

4)如果您需要更改标题等,请在设置文件中更改该变量

for someone who comes across this and is trying to debug:

1) the django csrf check (assuming you’re sending one) is here

2) In my case, settings.CSRF_HEADER_NAME was set to ‘HTTP_X_CSRFTOKEN’ and my AJAX call was sending a header named ‘HTTP_X_CSRF_TOKEN’ so stuff wasn’t working. I could either change it in the AJAX call, or django setting.

3) If you opt to change it server-side, find your install location of django and throw a breakpoint in the csrf middleware.f you’re using virtualenv, it’ll be something like: ~/.envs/my-project/lib/python2.7/site-packages/django/middleware/csrf.py

import ipdb; ipdb.set_trace() # breakpoint!!
if request_csrf_token == "":
    # Fall back to X-CSRFToken, to make things easier for AJAX,
    # and possible for PUT/DELETE.
    request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')

Then, make sure the csrf token is correctly sourced from request.META

4) If you need to change your header, etc – change that variable in your settings file


回答 15

如果有人正在努力使用axios进行这项工作,那么这对我有帮助:

import axios from 'axios';

axios.defaults.xsrfCookieName = 'csrftoken'
axios.defaults.xsrfHeaderName = 'X-CSRFToken'

资料来源:https : //cbuelter.wordpress.com/2017/04/10/django-csrf-with-axios/

If someone is strugling with axios to make this work this helped me:

import axios from 'axios';

axios.defaults.xsrfCookieName = 'csrftoken'
axios.defaults.xsrfHeaderName = 'X-CSRFToken'

Source: https://cbuelter.wordpress.com/2017/04/10/django-csrf-with-axios/


回答 16

在我的情况下,问题出在我将nginx配置从主服务器复制到一个临时的服务器,并禁用了第二个服务器上不需要的https。

我必须在配置中注释掉这两行以使其再次起作用:

# uwsgi_param             UWSGI_SCHEME    https;
# uwsgi_pass_header       X_FORWARDED_PROTO;

In my case the problem was with the nginx config that I’ve copied from main server to a temporary one with disabling https that is not needed on the second one in the process.

I had to comment out these two lines in the config to make it work again:

# uwsgi_param             UWSGI_SCHEME    https;
# uwsgi_pass_header       X_FORWARDED_PROTO;

回答 17

这是Django提供的较为简单的解决方案:

<script type="text/javascript">
// using jQuery
var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();

function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
// set csrf header
$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});

// Ajax call here
$.ajax({
    url:"{% url 'members:saveAccount' %}",
    data: fd,
    processData: false,
    contentType: false,
    type: 'POST',
    success: function(data) {
        alert(data);
        }
    });
</script>

来源:https : //docs.djangoproject.com/en/1.11/ref/csrf/

Here’s a less verbose solution provided by Django:

<script type="text/javascript">
// using jQuery
var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();

function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
// set csrf header
$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});

// Ajax call here
$.ajax({
    url:"{% url 'members:saveAccount' %}",
    data: fd,
    processData: false,
    contentType: false,
    type: 'POST',
    success: function(data) {
        alert(data);
        }
    });
</script>

Source: https://docs.djangoproject.com/en/1.11/ref/csrf/


当DEBUG = False时,Django给出错误请求(400)

问题:当DEBUG = False时,Django给出错误请求(400)

我是django-1.6的新手。当我使用运行django服务器时DEBUG = True,它运行良好。但是,当我改变DEBUGFalse在设置文件,然后在服务器停止,并让在命令提示符下以下错误:

CommandError: You must set settings.ALLOWED_HOSTS if DEBUG is False.

更改ALLOWED_HOSTS为之后["http://127.0.0.1:8000",],在浏览器中出现错误:

Bad Request (400)

是否可以在没有调试模式的情况下运行Django?

I am new to django-1.6. When I run the django server with DEBUG = True, it’s running perfectly. But when I change DEBUG to False in the settings file, then the server stopped and it gives the following error on the command prompt:

CommandError: You must set settings.ALLOWED_HOSTS if DEBUG is False.

After I changed ALLOWED_HOSTS to ["http://127.0.0.1:8000",], in the browser I get the error:

Bad Request (400)

Is it possible to run Django without debug mode?


回答 0

ALLOWED_HOSTS列表应包含标准主机名而不是 URL。省略端口和协议。如果您使用127.0.0.1,我也将添加localhost到列表中:

ALLOWED_HOSTS = ['127.0.0.1', 'localhost']

您还可以*用来匹配任何主机:

ALLOWED_HOSTS = ['*']

引用文档:

此列表中的值可以是完全限定的名称(例如'www.example.com'),在这种情况下,它们将与请求的Host标头完全匹配(不区分大小写,不包括port)。用了一段开头的值可以用作一个子域通配符:'.example.com'将匹配example.comwww.example.com以及任何其他子域example.com。值'*'将匹配任何内容;在这种情况下,您有责任提供自己的Host标头验证(可能在中间件中;如果是,则必须在中首先列出该中间件MIDDLEWARE_CLASSES)。

大胆强调我

您收到的状态400响应是由于主机标头与该列表中的任何值都不匹配时引发的SuspiciousOperation异常

The ALLOWED_HOSTS list should contain fully qualified host names, not urls. Leave out the port and the protocol. If you are using 127.0.0.1, I would add localhost to the list too:

ALLOWED_HOSTS = ['127.0.0.1', 'localhost']

You could also use * to match any host:

ALLOWED_HOSTS = ['*']

Quoting the documentation:

Values in this list can be fully qualified names (e.g. 'www.example.com'), in which case they will be matched against the request’s Host header exactly (case-insensitive, not including port). A value beginning with a period can be used as a subdomain wildcard: '.example.com' will match example.com, www.example.com, and any other subdomain of example.com. A value of '*' will match anything; in this case you are responsible to provide your own validation of the Host header (perhaps in a middleware; if so this middleware must be listed first in MIDDLEWARE_CLASSES).

Bold emphasis mine.

The status 400 response you get is due to a SuspiciousOperation exception being raised when your host header doesn’t match any values in that list.


回答 1

对我来说,我没有设置USE_X_FORWARDED_HOST为true便得到了这个错误。从文档:

仅当使用设置此标头的代理时,才应启用此功能。

我的托管服务在其文档中明确表示,该设置必须被使用,如果我忘了我得到这个400错误。

For me, I got this error by not setting USE_X_FORWARDED_HOST to true. From the docs:

This should only be enabled if a proxy which sets this header is in use.

My hosting service wrote explicitly in their documentation that this setting must be used, and I get this 400 error if I forget it.


回答 2

我遇到了同样的问题,并通过设置ALLOWED_HOSTS = ['*']并解决静态映像的问题来解决它,您必须像这样更改环境配置中的虚拟路径:

虚拟路径                 目录

/ static / / opt / python / current / app / yourpj / static /
/ media / / opt / python / current / app / Nuevo / media /

希望对您有帮助。

PD:对不起,我的英语不好。

I had the same problem and I fixed it by setting ALLOWED_HOSTS = ['*'] and to solve the problem with the static images you have to change the virtual paths in the environment configuration like this:

Virtual Path                 Directory

/static/                          /opt/python/current/app/yourpj/static/
/media/                        /opt/python/current/app/Nuevo/media/

I hope it helps you.

PD: sorry for my bad english.


回答 3

我遇到了同样的问题,没有一个答案可以解决我的问题,为了解决这种情况,最好通过在settings.py临时目录中添加以下配置来启用日志记录

LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'file': { 'level': 'DEBUG', 'class': 'logging.FileHandler', 'filename': '/tmp/debug.log', }, }, 'loggers': { 'django': { 'handlers': ['file'], 'level': 'DEBUG', 'propagate': True, }, }, }

并尝试tail -f /tmp/debug.log。当您看到问题时,比盲目调试要容易得多。

我的问题即将

无效的HTTP_HOST标头:“ pt_web:8000”。根据RFC 1034/1035,提供的域名无效。

并通过添加解决它proxy_set_header Host $host;,以Nginx的配置文件,通过启用端口转发USE_X_FORWARDED_PORT = Truesettings.py(这是因为在我的情况我已经听过请求Nginx的端口8080,并把它传递给guni上港8000

I had the same problem and none of the answers resolved my problem, for resolving the situation like this it’s better to enable logging by adding the following config to settings.py temporary

LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'file': { 'level': 'DEBUG', 'class': 'logging.FileHandler', 'filename': '/tmp/debug.log', }, }, 'loggers': { 'django': { 'handlers': ['file'], 'level': 'DEBUG', 'propagate': True, }, }, }

and try to tail -f /tmp/debug.log. and when you see your issue you can handle it much easier than blind debugging.

My issue was about to

Invalid HTTP_HOST header: ‘pt_web:8000’. The domain name provided is not valid according to RFC 1034/1035.

and resolve it by adding proxy_set_header Host $host; to Nginx config file and enabling port forwarding by USE_X_FORWARDED_PORT = True in the settings.py ( it’s because in my case I’ve listened to request in Nginx on port 8080 and pass it to guni on port 8000


回答 4

对我来说,我已经在127.0.0.1上使用了xampp,在127.0.1.1上使用了django,并且我一直在尝试添加主机

ALLOWED_HOSTS = ['127.0.0.1', 'localhost', 'www.yourdomain.com', '*', '127.0.1.1']

并且我遇到相同的错误或(400)错误的请求 在此处输入图片说明

所以我将URL更改为127.0.1.1 :(使用的端口)/ project和瞧!

您必须检查您的虚拟网络地址是什么,对我来说,因为我在Linux上使用bitnami django堆栈2.2.3-1,所以我可以检查django使用的端口。如果您有一个错误(400错误的请求),那么我猜django在不同的虚拟网络上..祝您好运 在此处输入图片说明

For me as I have already xampp on 127.0.0.1 and django on 127.0.1.1 and i kept trying adding hosts

ALLOWED_HOSTS = ['127.0.0.1', 'localhost', 'www.yourdomain.com', '*', '127.0.1.1']

and i got the same error or (400) bad request enter image description here

so I change the url to 127.0.1.1:(the used port)/project and voila !

you have to check what is your virtual network address, for me as i use bitnami django stack 2.2.3-1 on Linux i can check which port django is using. if you have an error ( 400 bad request ) then i guess django on different virtual network .. good luck enter image description here


回答 5

随着DEBUG = False在你的设置文件,你还需要ALLOWED_HOST列表设置。尝试包括ALLOWED_HOST = ['127.0.0.1', 'localhost', 'www.yourdomain.com']

否则,您可能会收到来自django的Bad Request(400)错误消息。

With DEBUG = False in you settings file, you also need ALLOWED_HOST list set up. Try including ALLOWED_HOST = ['127.0.0.1', 'localhost', 'www.yourdomain.com']

Otherwise you might receive a Bad Request(400) error from django.


回答 6

尝试使用–insecure运行服务器,如下所示:

python manage.py runserver-不安全

Try to run your server with the –insecure just like this:

python manage.py runserver –insecure


回答 7

我必须先停止apache服务器。

(fe sudo systemctl stop httpd.service/ sudo systemctl disable httpd.service)。

除了编辑’ settings.py‘文件,这解决了我的问题

ALLOWED_HOSTS = ['se.rv.er.ip', 'www.example.com']

I had to stop the apache server first.

(f.e. sudo systemctl stop httpd.service / sudo systemctl disable httpd.service).

That solved my problem besides editing the ‘settings.py‘ file

to ALLOWED_HOSTS = ['se.rv.er.ip', 'www.example.com']


回答 8

导航到设置并找到base.py文件将允许的主机设置为ALLOWED_HOSTS = [‘*’]

Navigate to settings and locate the base.py file Set the allowed hosts to ALLOWED_HOSTS = [‘*’]


DatabaseError:当前事务中止,命令被忽略,直到事务块结束?

问题:DatabaseError:当前事务中止,命令被忽略,直到事务块结束?

消息有很多错误:

"DatabaseError: current transaction is aborted, commands ignored until end of transaction block"

从python-psycopg更改为python-psycopg2作为Django项目的数据库引擎。

代码保持不变,只是不知道这些错误来自何处。

I got a lot of errors with the message :

"DatabaseError: current transaction is aborted, commands ignored until end of transaction block"

after changed from python-psycopg to python-psycopg2 as Django project’s database engine.

The code remains the same, just don’t know where those errors are from.


回答 0

当查询产生错误并且您尝试运行另一个查询而不先回滚事务时,这就是postgres所做的。(您可能会认为这是一项安全功能,可以防止您破坏数据。)

要解决此问题,您将需要弄清楚错误查询在代码中的何处执行。在您的PostgreSQL服务器中使用log_statementlog_min_error_statement选项可能会有所帮助。

This is what postgres does when a query produces an error and you try to run another query without first rolling back the transaction. (You might think of it as a safety feature, to keep you from corrupting your data.)

To fix this, you’ll want to figure out where in the code that bad query is being executed. It might be helpful to use the log_statement and log_min_error_statement options in your postgresql server.


回答 1

要消除错误,请在修复代码后回滚上一个(错误的)事务

from django.db import transaction
transaction.rollback()

您可以使用try-except来防止发生错误:

from django.db import transaction, DatabaseError
try:
    a.save()
except DatabaseError:
    transaction.rollback()

参考:Django文档

To get rid of the error, roll back the last (erroneous) transaction after you’ve fixed your code:

from django.db import transaction
transaction.rollback()

You can use try-except to prevent the error from occurring:

from django.db import transaction, DatabaseError
try:
    a.save()
except DatabaseError:
    transaction.rollback()

Refer : Django documentation


回答 2

因此,我遇到了同样的问题。我在这里遇到的问题是我的数据库未正确同步。简单的问题似乎总是引起最大的忧虑。

要在终端的应用程序目录中同步django db,请输入:

$ python manage.py syncdb

编辑:请注意,如果您使用的是django-south,则运行’$ python manage.py migration’命令也可以解决此问题。

祝您编码愉快!

So, I ran into this same issue. The problem I was having here was that my database wasn’t properly synced. Simple problems always seem to cause the most angst…

To sync your django db, from within your app directory, within terminal, type:

$ python manage.py syncdb

Edit: Note that if you are using django-south, running the ‘$ python manage.py migrate’ command may also resolve this issue.

Happy coding!


回答 3

在Flask中,您只需要编写:

curs = conn.cursor()
curs.execute("ROLLBACK")
conn.commit()

PS文档在这里https://www.postgresql.org/docs/9.4/static/sql-rollback.html

In Flask you just need to write:

curs = conn.cursor()
curs.execute("ROLLBACK")
conn.commit()

P.S. Documentation goes here https://www.postgresql.org/docs/9.4/static/sql-rollback.html


回答 4

以我的经验,这些错误是通过以下方式发生的:

try:
    code_that_executes_bad_query()
    # transaction on DB is now bad
except:
    pass

# transaction on db is still bad
code_that_executes_working_query() # raises transaction error

第二个查询没有任何问题,但是由于发现了真正的错误,因此第二个查询引发了错误(信息少得多)。

编辑:仅当except子句捕获IntegrityError(或任何其他低级数据库异常)时,才会发生这种情况;如果捕获到DoesNotExist此类错误,则不会出现此错误,因为DoesNotExist这不会破坏事务。

这里的类是不要尝试/exceptions/通过。

In my experience, these errors happen this way:

try:
    code_that_executes_bad_query()
    # transaction on DB is now bad
except:
    pass

# transaction on db is still bad
code_that_executes_working_query() # raises transaction error

There nothing wrong with the second query, but since the real error was caught, the second query is the one that raises the (much less informative) error.

edit: this only happens if the except clause catches IntegrityError (or any other low level database exception), If you catch something like DoesNotExist this error will not come up, because DoesNotExist does not corrupt the transaction.

The lesson here is don’t do try/except/pass.


回答 5

我认为使用PostgreSQL时,priestc提到的模式更可能是此问题的常见原因。

但是,我认为该模式有有效的用途,我不认为这个问题应该成为始终避免它的原因。例如:

try:
    profile = user.get_profile()
except ObjectDoesNotExist:
    profile = make_default_profile_for_user(user)

do_something_with_profile(profile)

如果您确实对这种模式感到满意,但是想避免到处都是显式的事务处理代码,那么您可能希望考虑启用自动提交模式(PostgreSQL 8.2+):https ://docs.djangoproject.com/en/ dev / ref / databases /#autocommit-mode

DATABASES['default'] = {
    #.. you usual options...
    'OPTIONS': {
        'autocommit': True,
    }
}

我不确定是否有重要的性能考虑因素(或任何其他类型的考虑因素)。

I think the pattern priestc mentions is more likely to be the usual cause of this issue when using PostgreSQL.

However I feel there are valid uses for the pattern and I don’t think this issue should be a reason to always avoid it. For example:

try:
    profile = user.get_profile()
except ObjectDoesNotExist:
    profile = make_default_profile_for_user(user)

do_something_with_profile(profile)

If you do feel OK with this pattern, but want to avoid explicit transaction handling code all over the place then you might want to look into turning on autocommit mode (PostgreSQL 8.2+): https://docs.djangoproject.com/en/dev/ref/databases/#autocommit-mode

DATABASES['default'] = {
    #.. you usual options...
    'OPTIONS': {
        'autocommit': True,
    }
}

I am unsure if there are important performance considerations (or of any other type).


回答 6

如果您在交互式外壳程序中得到此消息并需要快速修复,请执行以下操作:

from django.db import connection
connection._rollback()

最初在此答案中看到

If you get this while in interactive shell and need a quick fix, do this:

from django.db import connection
connection._rollback()

originally seen in this answer


回答 7

postgres终端上运行有故障的事务时,我遇到了类似的行为。此后什么都没有发生,因为database处于的状态error。但是,如果可以避免的话,只是快速解决方法rollback transaction。以下对我有用:

COMMIT;

I encountered a similar behavior while running a malfunctioned transaction on the postgres terminal. Nothing went through after this, as the database is in a state of error. However, just as a quick fix, if you can afford to avoid rollback transaction. Following did the trick for me:

COMMIT;


回答 8

我有silimar问题。解决的办法是迁移数据库(manage.py syncdb或者manage.py schemamigration --auto <table name>如果您使用南方)。

I’ve got the silimar problem. The solution was to migrate db (manage.py syncdb or manage.py schemamigration --auto <table name> if you use south).


回答 9

只是使用回滚

范例程式码

try:
    cur.execute("CREATE TABLE IF NOT EXISTS test2 (id serial, qa text);")
except:
    cur.execute("rollback")
    cur.execute("CREATE TABLE IF NOT EXISTS test2 (id serial, qa text);")

just use rollback

Example code

try:
    cur.execute("CREATE TABLE IF NOT EXISTS test2 (id serial, qa text);")
except:
    cur.execute("rollback")
    cur.execute("CREATE TABLE IF NOT EXISTS test2 (id serial, qa text);")

回答 10

我也刚遇到这个错误,但是它掩盖了另一个更相关的错误消息,其中代码试图将125个字符的字符串存储在100个字符的列中:

DatabaseError: value too long for type character varying(100)

我必须调试代码才能显示以上消息,否则它将显示

DatabaseError: current transaction is aborted

I just had this error too but it was masking another more relevant error message where the code was trying to store a 125 characters string in a 100 characters column:

DatabaseError: value too long for type character varying(100)

I had to debug through the code for the above message to show up, otherwise it displays

DatabaseError: current transaction is aborted

回答 11

作为对@priestc和@Sebastian的回应,如果您做这样的事情怎么办?

try:
    conn.commit()
except:
    pass

cursor.execute( sql )
try: 
    return cursor.fetchall()
except: 
    conn.commit()
    return None

我只是尝试了这段代码,它似乎可以正常工作,无需关心任何可能的错误就可以静默失败,并且在查询良好时可以正常工作。

In response to @priestc and @Sebastian, what if you do something like this?

try:
    conn.commit()
except:
    pass

cursor.execute( sql )
try: 
    return cursor.fetchall()
except: 
    conn.commit()
    return None

I just tried this code and it seems to work, failing silently without having to care about any possible errors, and working when the query is good.


回答 12

我相信@AnujGupta的答案是正确的。但是,回滚本身会引发异常,您应该捕获并处理该异常:

from django.db import transaction, DatabaseError
try:
    a.save()
except DatabaseError:
    try:
        transaction.rollback()
    except transaction.TransactionManagementError:
        # Log or handle otherwise

如果发现要在各个save()位置重写此代码,则可以提取方法:

import traceback
def try_rolling_back():
    try:
        transaction.rollback()
        log.warning('rolled back')  # example handling
    except transaction.TransactionManagementError:
        log.exception(traceback.format_exc())  # example handling

最后,您可以使用装饰器装饰它,该装饰器保护使用的方法save()

from functools import wraps
def try_rolling_back_on_exception(fn):
    @wraps(fn)
    def wrapped(*args, **kwargs):
        try:
            return fn(*args, **kwargs)
        except:
            traceback.print_exc()
            try_rolling_back()
    return wrapped

@try_rolling_back_on_exception
def some_saving_method():
    # ...
    model.save()
    # ...

即使您实现了上面的装饰器,try_rolling_back()在需要进行特殊处理而通用装饰器处理还不够的情况下,如果需要手动使用提取方法,将其保留为提取方法仍然很方便。

I believe @AnujGupta’s answer is correct. However the rollback can itself raise an exception which you should catch and handle:

from django.db import transaction, DatabaseError
try:
    a.save()
except DatabaseError:
    try:
        transaction.rollback()
    except transaction.TransactionManagementError:
        # Log or handle otherwise

If you find you’re rewriting this code in various save() locations, you can extract-method:

import traceback
def try_rolling_back():
    try:
        transaction.rollback()
        log.warning('rolled back')  # example handling
    except transaction.TransactionManagementError:
        log.exception(traceback.format_exc())  # example handling

Finally, you can prettify it using a decorator that protects methods which use save():

from functools import wraps
def try_rolling_back_on_exception(fn):
    @wraps(fn)
    def wrapped(*args, **kwargs):
        try:
            return fn(*args, **kwargs)
        except:
            traceback.print_exc()
            try_rolling_back()
    return wrapped

@try_rolling_back_on_exception
def some_saving_method():
    # ...
    model.save()
    # ...

Even if you implement the decorator above, it’s still convenient to keep try_rolling_back() as an extracted method in case you need to use it manually for cases where specific handling is required, and the generic decorator handling isn’t enough.


回答 13

这对我来说是非常奇怪的行为。我很惊讶没有人想到保存点。在我的代码中,查询失败是预期的行为:

from django.db import transaction
@transaction.commit_on_success
def update():
    skipped = 0
    for old_model in OldModel.objects.all():
        try:
            Model.objects.create(
                group_id=old_model.group_uuid,
                file_id=old_model.file_uuid,
            )
        except IntegrityError:
            skipped += 1
    return skipped

我已经以这种方式更改代码以使用保存点:

from django.db import transaction
@transaction.commit_on_success
def update():
    skipped = 0
    sid = transaction.savepoint()
    for old_model in OldModel.objects.all():
        try:
            Model.objects.create(
                group_id=old_model.group_uuid,
                file_id=old_model.file_uuid,
            )
        except IntegrityError:
            skipped += 1
            transaction.savepoint_rollback(sid)
        else:
            transaction.savepoint_commit(sid)
    return skipped

This is very strange behavior for me. I’m surprised that no one thought of savepoints. In my code failing query was expected behavior:

from django.db import transaction
@transaction.commit_on_success
def update():
    skipped = 0
    for old_model in OldModel.objects.all():
        try:
            Model.objects.create(
                group_id=old_model.group_uuid,
                file_id=old_model.file_uuid,
            )
        except IntegrityError:
            skipped += 1
    return skipped

I have changed code this way to use savepoints:

from django.db import transaction
@transaction.commit_on_success
def update():
    skipped = 0
    sid = transaction.savepoint()
    for old_model in OldModel.objects.all():
        try:
            Model.objects.create(
                group_id=old_model.group_uuid,
                file_id=old_model.file_uuid,
            )
        except IntegrityError:
            skipped += 1
            transaction.savepoint_rollback(sid)
        else:
            transaction.savepoint_commit(sid)
    return skipped

回答 14

在Flask Shell中,我需要做的只是session.rollback()克服这个问题。

In Flask shell, all I needed to do was a session.rollback() to get past this.


回答 15

我已经遇到了这个问题,由于错误交易尚未正确结束,因此出现错误,我在这里找到了postgresql_transactionsTransaction Control命令

交易控制

以下命令用于控制交易

BEGIN TRANSACTION  To start a transaction.

COMMIT  To save the changes, alternatively you can use END TRANSACTION command.

ROLLBACK  To rollback the changes.

所以我使用END TRANSACTION来结束错误TRANSACTION,如下代码:

    for key_of_attribute, command in sql_command.items():
        cursor = connection.cursor()
        g_logger.info("execute command :%s" % (command))
        try:
            cursor.execute(command)
            rows = cursor.fetchall()
            g_logger.info("the command:%s result is :%s" % (command, rows))
            result_list[key_of_attribute] = rows
            g_logger.info("result_list is :%s" % (result_list))
        except Exception as e:
            cursor.execute('END TRANSACTION;')
            g_logger.info("error command :%s and error is :%s" % (command, e))
    return result_list

I have met this issue , the error comes out since the error transactions hasn’t been ended rightly, I found the postgresql_transactions of Transaction Control command here

Transaction Control

The following commands are used to control transactions

BEGIN TRANSACTION − To start a transaction.

COMMIT − To save the changes, alternatively you can use END TRANSACTION command.

ROLLBACK − To rollback the changes.

so i use the END TRANSACTION to end the error TRANSACTION, code like this:

    for key_of_attribute, command in sql_command.items():
        cursor = connection.cursor()
        g_logger.info("execute command :%s" % (command))
        try:
            cursor.execute(command)
            rows = cursor.fetchall()
            g_logger.info("the command:%s result is :%s" % (command, rows))
            result_list[key_of_attribute] = rows
            g_logger.info("result_list is :%s" % (result_list))
        except Exception as e:
            cursor.execute('END TRANSACTION;')
            g_logger.info("error command :%s and error is :%s" % (command, e))
    return result_list

回答 16

您可以通过“ set_isolation_level(0)”禁用交易

you could disable transaction via “set_isolation_level(0)”