标签归档:Django

如何使用Python / Django执行HTML解码/编码?

问题:如何使用Python / Django执行HTML解码/编码?

我有一个HTML编码的字符串:

'''<img class="size-medium wp-image-113"\
 style="margin-left: 15px;" title="su1"\
 src="http://blah.org/wp-content/uploads/2008/10/su1-300x194.jpg"\
 alt="" width="300" height="194" />'''

我想将其更改为:

<img class="size-medium wp-image-113" style="margin-left: 15px;" 
  title="su1" src="http://blah.org/wp-content/uploads/2008/10/su1-300x194.jpg" 
  alt="" width="300" height="194" /> 

我希望将其注册为HTML,以便浏览器将其呈现为图像,而不是显示为文本。

字符串的存储方式是这样的,因为我正在使用一种名为的网络抓取工具BeautifulSoup,它将“扫描”网页并从中获取某些内容,然后以该格式返回字符串。

我已经找到了如何在C#中而不是在Python中执行此操作。有人可以帮我吗?

有关

I have a string that is HTML encoded:

'''&lt;img class=&quot;size-medium wp-image-113&quot;\
 style=&quot;margin-left: 15px;&quot; title=&quot;su1&quot;\
 src=&quot;http://blah.org/wp-content/uploads/2008/10/su1-300x194.jpg&quot;\
 alt=&quot;&quot; width=&quot;300&quot; height=&quot;194&quot; /&gt;'''

I want to change that to:

<img class="size-medium wp-image-113" style="margin-left: 15px;" 
  title="su1" src="http://blah.org/wp-content/uploads/2008/10/su1-300x194.jpg" 
  alt="" width="300" height="194" /> 

I want this to register as HTML so that it is rendered as an image by the browser instead of being displayed as text.

The string is stored like that because I am using a web-scraping tool called BeautifulSoup, it “scans” a web-page and gets certain content from it, then returns the string in that format.

I’ve found how to do this in C# but not in Python. Can someone help me out?

Related


回答 0

给定Django用例,对此有两个答案。这是它的django.utils.html.escape功能,以供参考:

def escape(html):
    """Returns the given HTML with ampersands, quotes and carets encoded."""
    return mark_safe(force_unicode(html).replace('&', '&amp;').replace('<', '&l
t;').replace('>', '&gt;').replace('"', '&quot;').replace("'", '&#39;'))

为了解决这个问题,Jake的答案中描述的Cheetah函数应该起作用,但是缺少单引号。此版本包含一个更新的元组,并且替换顺序相反,以避免出现对称问题:

def html_decode(s):
    """
    Returns the ASCII decoded version of the given HTML string. This does
    NOT remove normal HTML tags like <p>.
    """
    htmlCodes = (
            ("'", '&#39;'),
            ('"', '&quot;'),
            ('>', '&gt;'),
            ('<', '&lt;'),
            ('&', '&amp;')
        )
    for code in htmlCodes:
        s = s.replace(code[1], code[0])
    return s

unescaped = html_decode(my_string)

但是,这不是一般的解决方案。仅适用于以编码的字符串django.utils.html.escape。更笼统地说,坚持使用标准库是一个好主意:

# Python 2.x:
import HTMLParser
html_parser = HTMLParser.HTMLParser()
unescaped = html_parser.unescape(my_string)

# Python 3.x:
import html.parser
html_parser = html.parser.HTMLParser()
unescaped = html_parser.unescape(my_string)

# >= Python 3.5:
from html import unescape
unescaped = unescape(my_string)

建议:将未转义的HTML存储在数据库中可能更有意义。如果可能的话,值得一探的是从BeautifulSoup获得未转义的结果,并完全避免此过程。

对于Django,转义仅在模板渲染期间发生;因此,为了防止转义,您只需告诉模板引擎不要转义您的字符串即可。为此,请在模板中使用以下选项之一:

{{ context_var|safe }}
{% autoescape off %}
    {{ context_var }}
{% endautoescape %}

Given the Django use case, there are two answers to this. Here is its django.utils.html.escape function, for reference:

def escape(html):
    """Returns the given HTML with ampersands, quotes and carets encoded."""
    return mark_safe(force_unicode(html).replace('&', '&amp;').replace('<', '&l
t;').replace('>', '&gt;').replace('"', '&quot;').replace("'", '&#39;'))

To reverse this, the Cheetah function described in Jake’s answer should work, but is missing the single-quote. This version includes an updated tuple, with the order of replacement reversed to avoid symmetric problems:

def html_decode(s):
    """
    Returns the ASCII decoded version of the given HTML string. This does
    NOT remove normal HTML tags like <p>.
    """
    htmlCodes = (
            ("'", '&#39;'),
            ('"', '&quot;'),
            ('>', '&gt;'),
            ('<', '&lt;'),
            ('&', '&amp;')
        )
    for code in htmlCodes:
        s = s.replace(code[1], code[0])
    return s

unescaped = html_decode(my_string)

This, however, is not a general solution; it is only appropriate for strings encoded with django.utils.html.escape. More generally, it is a good idea to stick with the standard library:

# Python 2.x:
import HTMLParser
html_parser = HTMLParser.HTMLParser()
unescaped = html_parser.unescape(my_string)

# Python 3.x:
import html.parser
html_parser = html.parser.HTMLParser()
unescaped = html_parser.unescape(my_string)

# >= Python 3.5:
from html import unescape
unescaped = unescape(my_string)

As a suggestion: it may make more sense to store the HTML unescaped in your database. It’d be worth looking into getting unescaped results back from BeautifulSoup if possible, and avoiding this process altogether.

With Django, escaping only occurs during template rendering; so to prevent escaping you just tell the templating engine not to escape your string. To do that, use one of these options in your template:

{{ context_var|safe }}
{% autoescape off %}
    {{ context_var }}
{% endautoescape %}

回答 1

使用标准库:

  • HTML转义

    try:
        from html import escape  # python 3.x
    except ImportError:
        from cgi import escape  # python 2.x
    
    print(escape("<"))
    
  • HTML转义

    try:
        from html import unescape  # python 3.4+
    except ImportError:
        try:
            from html.parser import HTMLParser  # python 3.x (<3.4)
        except ImportError:
            from HTMLParser import HTMLParser  # python 2.x
        unescape = HTMLParser().unescape
    
    print(unescape("&gt;"))
    

With the standard library:

  • HTML Escape

    try:
        from html import escape  # python 3.x
    except ImportError:
        from cgi import escape  # python 2.x
    
    print(escape("<"))
    
  • HTML Unescape

    try:
        from html import unescape  # python 3.4+
    except ImportError:
        try:
            from html.parser import HTMLParser  # python 3.x (<3.4)
        except ImportError:
            from HTMLParser import HTMLParser  # python 2.x
        unescape = HTMLParser().unescape
    
    print(unescape("&gt;"))
    

回答 2

对于html编码,标准库中有cgi.escape

>> help(cgi.escape)
cgi.escape = escape(s, quote=None)
    Replace special characters "&", "<" and ">" to HTML-safe sequences.
    If the optional flag quote is true, the quotation mark character (")
    is also translated.

对于html解码,我使用以下代码:

import re
from htmlentitydefs import name2codepoint
# for some reason, python 2.5.2 doesn't have this one (apostrophe)
name2codepoint['#39'] = 39

def unescape(s):
    "unescape HTML code refs; c.f. http://wiki.python.org/moin/EscapingHtml"
    return re.sub('&(%s);' % '|'.join(name2codepoint),
              lambda m: unichr(name2codepoint[m.group(1)]), s)

对于更复杂的事情,我使用BeautifulSoup。

For html encoding, there’s cgi.escape from the standard library:

>> help(cgi.escape)
cgi.escape = escape(s, quote=None)
    Replace special characters "&", "<" and ">" to HTML-safe sequences.
    If the optional flag quote is true, the quotation mark character (")
    is also translated.

For html decoding, I use the following:

import re
from htmlentitydefs import name2codepoint
# for some reason, python 2.5.2 doesn't have this one (apostrophe)
name2codepoint['#39'] = 39

def unescape(s):
    "unescape HTML code refs; c.f. http://wiki.python.org/moin/EscapingHtml"
    return re.sub('&(%s);' % '|'.join(name2codepoint),
              lambda m: unichr(name2codepoint[m.group(1)]), s)

For anything more complicated, I use BeautifulSoup.


回答 3

如果编码字符集受到相对限制,请使用daniel的解决方案。否则,请使用众多HTML解析库之一。

我喜欢BeautifulSoup,因为它可以处理格式错误的XML / HTML:

http://www.crummy.com/software/BeautifulSoup/

对于您的问题,他们的文档中有一个示例

from BeautifulSoup import BeautifulStoneSoup
BeautifulStoneSoup("Sacr&eacute; bl&#101;u!", 
                   convertEntities=BeautifulStoneSoup.HTML_ENTITIES).contents[0]
# u'Sacr\xe9 bleu!'

Use daniel’s solution if the set of encoded characters is relatively restricted. Otherwise, use one of the numerous HTML-parsing libraries.

I like BeautifulSoup because it can handle malformed XML/HTML :

http://www.crummy.com/software/BeautifulSoup/

for your question, there’s an example in their documentation

from BeautifulSoup import BeautifulStoneSoup
BeautifulStoneSoup("Sacr&eacute; bl&#101;u!", 
                   convertEntities=BeautifulStoneSoup.HTML_ENTITIES).contents[0]
# u'Sacr\xe9 bleu!'

回答 4

在Python 3.4+中:

import html

html.unescape(your_string)

In Python 3.4+:

import html

html.unescape(your_string)

回答 5

请参阅此页面底部的Python Wiki,至少有2个选项可以“取消转义” html。

See at the bottom of this page at Python wiki, there are at least 2 options to “unescape” html.


回答 6

丹尼尔的评论作为答案:

“转义仅发生在Django模板渲染期间。因此,不需要进行转义-您只需告诉模板引擎不要转义。{{context_var | safe}}或{%autoescape off%} {{context_var}} { %endautoescape%}”

Daniel’s comment as an answer:

“escaping only occurs in Django during template rendering. Therefore, there’s no need for an unescape – you just tell the templating engine not to escape. either {{ context_var|safe }} or {% autoescape off %}{{ context_var }}{% endautoescape %}”


回答 7

我在以下位置找到了很好的功能:http : //snippets.dzone.com/posts/show/4569

def decodeHtmlentities(string):
    import re
    entity_re = re.compile("&(#?)(\d{1,5}|\w{1,8});")

    def substitute_entity(match):
        from htmlentitydefs import name2codepoint as n2cp
        ent = match.group(2)
        if match.group(1) == "#":
            return unichr(int(ent))
        else:
            cp = n2cp.get(ent)

            if cp:
                return unichr(cp)
            else:
                return match.group()

    return entity_re.subn(substitute_entity, string)[0]

I found a fine function at: http://snippets.dzone.com/posts/show/4569

def decodeHtmlentities(string):
    import re
    entity_re = re.compile("&(#?)(\d{1,5}|\w{1,8});")

    def substitute_entity(match):
        from htmlentitydefs import name2codepoint as n2cp
        ent = match.group(2)
        if match.group(1) == "#":
            return unichr(int(ent))
        else:
            cp = n2cp.get(ent)

            if cp:
                return unichr(cp)
            else:
                return match.group()

    return entity_re.subn(substitute_entity, string)[0]

回答 8

如果有人在寻找通过django模板执行此操作的简单方法,则可以始终使用以下过滤器:

<html>
{{ node.description|safe }}
</html>

我有一些来自供应商的数据,我发布的所有内容实际上都是在呈现的页面上写的html标签,就像您在查看源代码一样。上面的代码极大地帮助了我。希望这对其他人有帮助。

干杯!!

If anyone is looking for a simple way to do this via the django templates, you can always use filters like this:

<html>
{{ node.description|safe }}
</html>

I had some data coming from a vendor and everything I posted had html tags actually written on the rendered page as if you were looking at the source. The above code helped me greatly. Hope this helps others.

Cheers!!


回答 9

即使这是一个非常老的问题,也可能有效。

的Django 1.5.5

In [1]: from django.utils.text import unescape_entities
In [2]: unescape_entities('&lt;img class=&quot;size-medium wp-image-113&quot; style=&quot;margin-left: 15px;&quot; title=&quot;su1&quot; src=&quot;http://blah.org/wp-content/uploads/2008/10/su1-300x194.jpg&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;194&quot; /&gt;')
Out[2]: u'<img class="size-medium wp-image-113" style="margin-left: 15px;" title="su1" src="http://blah.org/wp-content/uploads/2008/10/su1-300x194.jpg" alt="" width="300" height="194" />'

Even though this is a really old question, this may work.

Django 1.5.5

In [1]: from django.utils.text import unescape_entities
In [2]: unescape_entities('&lt;img class=&quot;size-medium wp-image-113&quot; style=&quot;margin-left: 15px;&quot; title=&quot;su1&quot; src=&quot;http://blah.org/wp-content/uploads/2008/10/su1-300x194.jpg&quot; alt=&quot;&quot; width=&quot;300&quot; height=&quot;194&quot; /&gt;')
Out[2]: u'<img class="size-medium wp-image-113" style="margin-left: 15px;" title="su1" src="http://blah.org/wp-content/uploads/2008/10/su1-300x194.jpg" alt="" width="300" height="194" />'

回答 10

我在猎豹的源代码中找到了这个(这里

htmlCodes = [
    ['&', '&amp;'],
    ['<', '&lt;'],
    ['>', '&gt;'],
    ['"', '&quot;'],
]
htmlCodesReversed = htmlCodes[:]
htmlCodesReversed.reverse()
def htmlDecode(s, codes=htmlCodesReversed):
    """ Returns the ASCII decoded version of the given HTML string. This does
        NOT remove normal HTML tags like <p>. It is the inverse of htmlEncode()."""
    for code in codes:
        s = s.replace(code[1], code[0])
    return s

不确定为什么要反转列表,我认为它与编码方式有关,因此对于您而言,可能不需要反转。另外,如果我是我,我会将htmlCodes更改为元组列表,而不是列表列表…尽管这将在我的库中进行:)

我也注意到您的标题也要求编码,所以这是猎豹的编码功能。

def htmlEncode(s, codes=htmlCodes):
    """ Returns the HTML encoded version of the given string. This is useful to
        display a plain ASCII text string on a web page."""
    for code in codes:
        s = s.replace(code[0], code[1])
    return s

I found this in the Cheetah source code (here)

htmlCodes = [
    ['&', '&amp;'],
    ['<', '&lt;'],
    ['>', '&gt;'],
    ['"', '&quot;'],
]
htmlCodesReversed = htmlCodes[:]
htmlCodesReversed.reverse()
def htmlDecode(s, codes=htmlCodesReversed):
    """ Returns the ASCII decoded version of the given HTML string. This does
        NOT remove normal HTML tags like <p>. It is the inverse of htmlEncode()."""
    for code in codes:
        s = s.replace(code[1], code[0])
    return s

not sure why they reverse the list, I think it has to do with the way they encode, so with you it may not need to be reversed. Also if I were you I would change htmlCodes to be a list of tuples rather than a list of lists… this is going in my library though :)

i noticed your title asked for encode too, so here is Cheetah’s encode function.

def htmlEncode(s, codes=htmlCodes):
    """ Returns the HTML encoded version of the given string. This is useful to
        display a plain ASCII text string on a web page."""
    for code in codes:
        s = s.replace(code[0], code[1])
    return s

回答 11

您也可以使用django.utils.html.escape

from django.utils.html import escape

something_nice = escape(request.POST['something_naughty'])

You can also use django.utils.html.escape

from django.utils.html import escape

something_nice = escape(request.POST['something_naughty'])

回答 12

以下是使用module的python函数htmlentitydefs。这不是完美的。htmlentitydefs我所拥有的版本不完整,它假设所有实体都解码到一个代码点,这对于像这样的实体是错误的&NotEqualTilde;

http://www.w3.org/TR/html5/named-character-references.html

NotEqualTilde;     U+02242 U+00338    ≂̸

尽管有这些警告,但这里是代码。

def decodeHtmlText(html):
    """
    Given a string of HTML that would parse to a single text node,
    return the text value of that node.
    """
    # Fast path for common case.
    if html.find("&") < 0: return html
    return re.sub(
        '&(?:#(?:x([0-9A-Fa-f]+)|([0-9]+))|([a-zA-Z0-9]+));',
        _decode_html_entity,
        html)

def _decode_html_entity(match):
    """
    Regex replacer that expects hex digits in group 1, or
    decimal digits in group 2, or a named entity in group 3.
    """
    hex_digits = match.group(1)  # '&#10;' -> unichr(10)
    if hex_digits: return unichr(int(hex_digits, 16))
    decimal_digits = match.group(2)  # '&#x10;' -> unichr(0x10)
    if decimal_digits: return unichr(int(decimal_digits, 10))
    name = match.group(3)  # name is 'lt' when '&lt;' was matched.
    if name:
        decoding = (htmlentitydefs.name2codepoint.get(name)
            # Treat &GT; like &gt;.
            # This is wrong for &Gt; and &Lt; which HTML5 adopted from MathML.
            # If htmlentitydefs included mappings for those entities,
            # then this code will magically work.
            or htmlentitydefs.name2codepoint.get(name.lower()))
        if decoding is not None: return unichr(decoding)
    return match.group(0)  # Treat "&noSuchEntity;" as "&noSuchEntity;"

Below is a python function that uses module htmlentitydefs. It is not perfect. The version of htmlentitydefs that I have is incomplete and it assumes that all entities decode to one codepoint which is wrong for entities like &NotEqualTilde;:

http://www.w3.org/TR/html5/named-character-references.html

NotEqualTilde;     U+02242 U+00338    ≂̸

With those caveats though, here’s the code.

def decodeHtmlText(html):
    """
    Given a string of HTML that would parse to a single text node,
    return the text value of that node.
    """
    # Fast path for common case.
    if html.find("&") < 0: return html
    return re.sub(
        '&(?:#(?:x([0-9A-Fa-f]+)|([0-9]+))|([a-zA-Z0-9]+));',
        _decode_html_entity,
        html)

def _decode_html_entity(match):
    """
    Regex replacer that expects hex digits in group 1, or
    decimal digits in group 2, or a named entity in group 3.
    """
    hex_digits = match.group(1)  # '&#10;' -> unichr(10)
    if hex_digits: return unichr(int(hex_digits, 16))
    decimal_digits = match.group(2)  # '&#x10;' -> unichr(0x10)
    if decimal_digits: return unichr(int(decimal_digits, 10))
    name = match.group(3)  # name is 'lt' when '&lt;' was matched.
    if name:
        decoding = (htmlentitydefs.name2codepoint.get(name)
            # Treat &GT; like &gt;.
            # This is wrong for &Gt; and &Lt; which HTML5 adopted from MathML.
            # If htmlentitydefs included mappings for those entities,
            # then this code will magically work.
            or htmlentitydefs.name2codepoint.get(name.lower()))
        if decoding is not None: return unichr(decoding)
    return match.group(0)  # Treat "&noSuchEntity;" as "&noSuchEntity;"

回答 13

这是解决此问题的最简单方法-

{% autoescape on %}
   {{ body }}
{% endautoescape %}

从此页面

This is the easiest solution for this problem –

{% autoescape on %}
   {{ body }}
{% endautoescape %}

From this page.


回答 14

在Django和Python中搜索此问题的最简单解决方案,我发现您可以使用内置函数来转义/转义html代码。

我将您的html代码保存在scraped_html和中clean_html

scraped_html = (
    '&lt;img class=&quot;size-medium wp-image-113&quot; '
    'style=&quot;margin-left: 15px;&quot; title=&quot;su1&quot; '
    'src=&quot;http://blah.org/wp-content/uploads/2008/10/su1-300x194.jpg&quot; '
    'alt=&quot;&quot; width=&quot;300&quot; height=&quot;194&quot; /&gt;'
)
clean_html = (
    '<img class="size-medium wp-image-113" style="margin-left: 15px;" '
    'title="su1" src="http://blah.org/wp-content/uploads/2008/10/su1-300x194.jpg" '
    'alt="" width="300" height="194" />'
)

Django的

您需要Django> = 1.0

逃生

取消抓取的 HTML代码的转义,可以使用django.utils.text.unescape_entities,其中:

将所有命名和数字字符引用转换为相应的unicode字符。

>>> from django.utils.text import unescape_entities
>>> clean_html == unescape_entities(scraped_html)
True

逃逸

要转义干净的html代码,可以使用django.utils.html.escape,其中:

返回给定文本,该文本带有与符号,引号和尖括号,并编码为在HTML中使用。

>>> from django.utils.html import escape
>>> scraped_html == escape(clean_html)
True

Python

您需要Python> = 3.4

逃生

取消抓取的 html代码,可以使用html.unescape,其中:

转换所有命名和数字字符引用(例如&gt;&#62;&x3e;到对应的Unicode字符字符串s)。

>>> from html import unescape
>>> clean_html == unescape(scraped_html)
True

逃逸

要转义干净的html代码,可以使用html.escape,其中:

转换角色&<>在字符串s到HTML安全序列。

>>> from html import escape
>>> scraped_html == escape(clean_html)
True

Searching the simplest solution of this question in Django and Python I found you can use builtin theirs functions to escape/unescape html code.

Example

I saved your html code in scraped_html and clean_html:

scraped_html = (
    '&lt;img class=&quot;size-medium wp-image-113&quot; '
    'style=&quot;margin-left: 15px;&quot; title=&quot;su1&quot; '
    'src=&quot;http://blah.org/wp-content/uploads/2008/10/su1-300x194.jpg&quot; '
    'alt=&quot;&quot; width=&quot;300&quot; height=&quot;194&quot; /&gt;'
)
clean_html = (
    '<img class="size-medium wp-image-113" style="margin-left: 15px;" '
    'title="su1" src="http://blah.org/wp-content/uploads/2008/10/su1-300x194.jpg" '
    'alt="" width="300" height="194" />'
)

Django

You need Django >= 1.0

unescape

To unescape your scraped html code you can use django.utils.text.unescape_entities which:

Convert all named and numeric character references to the corresponding unicode characters.

>>> from django.utils.text import unescape_entities
>>> clean_html == unescape_entities(scraped_html)
True

escape

To escape your clean html code you can use django.utils.html.escape which:

Returns the given text with ampersands, quotes and angle brackets encoded for use in HTML.

>>> from django.utils.html import escape
>>> scraped_html == escape(clean_html)
True

Python

You need Python >= 3.4

unescape

To unescape your scraped html code you can use html.unescape which:

Convert all named and numeric character references (e.g. &gt;, &#62;, &x3e;) in the string s to the corresponding unicode characters.

>>> from html import unescape
>>> clean_html == unescape(scraped_html)
True

escape

To escape your clean html code you can use html.escape which:

Convert the characters &, < and > in string s to HTML-safe sequences.

>>> from html import escape
>>> scraped_html == escape(clean_html)
True

无法通过套接字’/tmp/mysql.sock连接到本地MySQL服务器

问题:无法通过套接字’/tmp/mysql.sock连接到本地MySQL服务器

当我在测试套件中尝试连接到本地MySQL服务器时,它失败并显示以下错误:

OperationalError: (2002, "Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)")

但是,我始终可以通过运行命令行mysql程序连接到MySQL 。A ps aux | grep mysql显示服务器正在运行,并 stat /tmp/mysql.sock确认套接字存在。此外,如果我在except该异常的子句中打开调试器,则可以使用完全相同的参数可靠地进行连接。

这个问题可以相当可靠地重现,但是似乎不是100%,因为每当我遇到一个蓝色月亮时,我的测试套件实际上都运行了而没有遇到此错误。当我尝试使用sudo dtruss它时,它没有复制。

所有的客户端代码都在Python中,尽管我不知道这是如何相关的。

切换为使用主机127.0.0.1会产生错误:

DatabaseError: Can't connect to MySQL server on '127.0.0.1' (61)

When I attempted to connect to a local MySQL server during my test suite, it fails with the error:

OperationalError: (2002, "Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)")

However, I’m able to at all times, connect to MySQL by running the command line mysql program. A ps aux | grep mysql shows the server is running, and stat /tmp/mysql.sock confirm that the socket exists. Further, if I open a debugger in except clause of that exception, I’m able to reliably connect with the exact same parameters.

This issue reproduces fairly reliably, however it doesn’t appear to be 100%, because every once in a blue moon, my test suite does in fact run without hitting this error. When I attempted to run with sudo dtruss it did not reproduce.

All the client code is in Python, though I can’t figure how that’d be relevant.

Switching to use host 127.0.0.1 produces the error:

DatabaseError: Can't connect to MySQL server on '127.0.0.1' (61)

回答 0

sudo /usr/local/mysql/support-files/mysql.server start 

这对我有用。但是,如果这不起作用,请确保mysqld正在运行并尝试连接。

sudo /usr/local/mysql/support-files/mysql.server start 

This worked for me. However, if this doesnt work then make sure that mysqld is running and try connecting.


回答 1

MySQL手册的相关部分在这里。我首先要完成列出的调试步骤。

另外,请记住,在这种情况下,localhost和127.0.0.1是不同的:

  • 如果host设置为localhost,则使用套接字或管道。
  • 如果将host设置为127.0.0.1,则客户端将被强制使用TCP / IP。

因此,例如,您可以检查数据库是否正在侦听TCP连接vi netstat -nlp。它似乎正在侦听TCP连接,因为您说这mysql -h 127.0.0.1很好。要检查是否可以通过套接字连接到数据库,请使用mysql -h localhost

如果以上方法均无济于事,那么您可能需要发布有关MySQL配置,实例化连接的确切方式等的更多详细信息。

The relevant section of the MySQL manual is here. I’d start by going through the debugging steps listed there.

Also, remember that localhost and 127.0.0.1 are not the same thing in this context:

  • If host is set to localhost, then a socket or pipe is used.
  • If host is set to 127.0.0.1, then the client is forced to use TCP/IP.

So, for example, you can check if your database is listening for TCP connections vi netstat -nlp. It seems likely that it IS listening for TCP connections because you say that mysql -h 127.0.0.1 works just fine. To check if you can connect to your database via sockets, use mysql -h localhost.

If none of this helps, then you probably need to post more details about your MySQL config, exactly how you’re instantiating the connection, etc.


回答 2

对我来说,问题是我没有运行mysql服务器。首先运行服务器,然后执行mysql

$ mysql.server start
$ mysql -h localhost -u root -p

For me the problem was I wasn’t running MySQL Server. Run server first and then execute mysql.

$ mysql.server start
$ mysql -h localhost -u root -p

回答 3

当我的开发人员安装了堆栈管理器(如MAMP)并在非标准位置预先安装了MySQL时,就已经在我的商店中看到这种情况。

在您的终端运行

mysql_config --socket

这将为您提供袜子文件的路径。走那条路,并在您的数据库主机参数中使用它。

您需要做的就是指出您的

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'test',
        'USER': 'test',
        'PASSWORD': 'test',
        'HOST': '/Applications/MAMP/tmp/mysql/mysql.sock',
        'PORT': '',
    },
}

注意

which mysql_config如果您以某种方式在计算机上安装了多个mysql服务器实例,则也可以运行,您可能连接了错误的实例。

I’ve seen this happen at my shop when my devs have a stack manager like MAMP installed that comes preconfigured with MySQL installed in a non standard place.

at your terminal run

mysql_config --socket

that will give you your path to the sock file. take that path and use it in your DATABASES HOST paramater.

What you need to do is point your

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'test',
        'USER': 'test',
        'PASSWORD': 'test',
        'HOST': '/Applications/MAMP/tmp/mysql/mysql.sock',
        'PORT': '',
    },
}

NOTE

also run which mysql_config if you somehow have multiple instances of mysql server installed on the machine you may be connecting to the wrong one.


回答 4

我只是将HOSTfrom 更改为localhost127.0.0.1并且效果很好:

# settings.py of Django project
...

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

I just changed the HOST from localhost to 127.0.0.1 and it works fine:

# settings.py of Django project
...

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

回答 5

何时,如果您在Mac OSx中丢失了守护进程mysql,但在其他路径中(例如在private / var中存在),请执行以下命令

1)

ln -s /private/var/mysql/mysql.sock /tmp/mysql.sock

2)使用以下命令重新启动与mysql的连接:

mysql -u username -p -h host databasename

也适用于mariadb

When, if you lose your daemon mysql in mac OSx but is present in other path for exemple in private/var do the following command

1)

ln -s /private/var/mysql/mysql.sock /tmp/mysql.sock

2) restart your connexion to mysql with :

mysql -u username -p -h host databasename

works also for mariadb


回答 6

在终端中运行以下cmd

/ usr / local / mysql / bin / mysqld_safe

然后重新启动机器以生效。有用!!

Run the below cmd in terminal

/usr/local/mysql/bin/mysqld_safe

Then restart the machine to take effect. It works!!


回答 7

使用lsof命令检查mysql进程的打开文件数。

增加打开文件的限制,然后再次运行。

Check number of open files for the mysql process using lsof command.

Increase the open files limit and run again.


回答 8

在尝试了其中一些解决方案但没有成功之后,这对我有用:

  1. 重启系统
  2. mysql.server启动
  3. 成功!

After attempting a few of these solutions and not having any success, this is what worked for me:

  1. Restart system
  2. mysql.server start
  3. Success!

回答 9

这可能是以下问题之一。

  1. 错误的mysql锁定。解决方案:您必须通过以下方式找出正确的mysql套接字,

mysqladmin -p变量| grep套接字

然后将其放在您的数据库连接代码中:

pymysql.connect(db='db', user='user', passwd='pwd', unix_socket="/tmp/mysql.sock")

/tmp/mysql.sock是grep返回的

2.不正确的mysql端口解决方案:您必须找出正确的mysql端口:

mysqladmin -p variables | grep port

然后在您的代码中:

pymysql.connect(db='db', user='user', passwd='pwd', host='localhost', port=3306)

3306是从grep返回的端口

我认为第一种选择可以解决您的问题。

This may be one of following problems.

  1. Incorrect mysql lock. solution: You have to find out the correct mysql socket by,

mysqladmin -p variables | grep socket

and then put it in your db connection code:

pymysql.connect(db='db', user='user', passwd='pwd', unix_socket="/tmp/mysql.sock")

/tmp/mysql.sock is the returned from grep

2.Incorrect mysql port solution: You have to find out the correct mysql port:

mysqladmin -p variables | grep port

and then in your code:

pymysql.connect(db='db', user='user', passwd='pwd', host='localhost', port=3306)

3306 is the port returned from the grep

I think first option will resolve your problem.


回答 10

对于通过自制软件从5.7升级到8.0的用户,此错误很可能是由于升级未完成引起的。就我而言,mysql.server start出现以下错误:

错误!服务器退出而不更新PID文件

然后,我通过检查了日志文件cat /usr/local/var/mysql/YOURS.err | tail -n 50

InnoDB:不支持崩溃后升级。

如果您在同一条船上,请首先mysql@5.7通过自制程序安装,停止服务器,然后再次启动8.0系统。

brew install mysql@5.7

/usr/local/opt/mysql@5.7/bin/mysql.server start
/usr/local/opt/mysql@5.7/bin/mysql.server stop

然后,

mysql.server start

这将使您的MySQL(8.0)再次正常工作。

To those who upgraded from 5.7 to 8.0 via homebrew, this error is likely caused by the upgrade not being complete. In my case, mysql.server start got me the following error:

ERROR! The server quit without updating PID file

I then checked the log file via cat /usr/local/var/mysql/YOURS.err | tail -n 50, and found the following:

InnoDB: Upgrade after a crash is not supported.

If you are on the same boat, first install mysql@5.7 via homebrew, stop the server, and then start the 8.0 system again.

brew install mysql@5.7

/usr/local/opt/mysql@5.7/bin/mysql.server start
/usr/local/opt/mysql@5.7/bin/mysql.server stop

Then,

mysql.server start

This would get your MySQL (8.0) working again.


回答 11

我想我前一段时间也看到了相同的行为,但记不清细节了。
在我们的案例中,问题在于测试运行程序相对于所需的第一次数据库交互(例如,通过在settings.py或某个__init__.py中导入模块)初始化数据库连接的时刻。我将尝试挖掘更多信息,但这可能已经为您解决了。

I think i saw this same behavior some time ago, but can’t remember the details.
In our case, the problem was the moment the testrunner initialises database connections relative to first database interaction required, for instance, by import of a module in settings.py or some __init__.py. I’ll try to digg up some more info, but this might already ring a bell for your case.


回答 12

确保您的/ etc / hosts包含127.0.0.1 localhost其中,并且应该工作正常

Make sure your /etc/hosts has 127.0.0.1 localhost in it and it should work fine


回答 13

我对此有两个偷偷摸摸的猜想

主题1

调查无法访问/tmp/mysql.sock文件的可能性。设置MySQL数据库时,通常将套接字文件站点放入/var/lib/mysql。如果您以身份登录到mysql root@localhost,则您的OS会话需要访问该/tmp文件夹。确保/tmp在操作系统中具有正确的访问权限。另外,请确保sudo用户始终可以读取文件/tmp

主题2

通过访问MySQL 127.0.0.1如果您不注意,则可能会引起一些混乱。怎么样?

在命令行中,如果使用来连接到MySQL 127.0.0.1,则可能需要指定TCP / IP协议。

mysql -uroot -p -h127.0.0.1 --protocol=tcp

或尝试使用DNS名称

mysql -uroot -p -hDNSNAME

这将绕过以身份登录root@localhost,但请确保已root@'127.0.0.1'定义。

下次连接到MySQL时,运行以下命令:

SELECT USER(),CURRENT_USER();

这给你什么?

如果这些函数返回的值相同,则说明您正在按预期进行连接和身份验证。如果值不同,则可能需要创建相应的user root@127.0.0.1

I have two sneaky conjectures on this one

CONJECTURE #1

Look into the possibility of not being able to access the /tmp/mysql.sock file. When I setup MySQL databases, I normally let the socket file site in /var/lib/mysql. If you login to mysql as root@localhost, your OS session needs access to the /tmp folder. Make sure /tmp has the correct access rights in the OS. Also, make sure the sudo user can always read file in /tmp.

CONJECTURE #2

Accessing mysql via 127.0.0.1 can cause some confusion if you are not paying attention. How?

From the command line, if you connect to MySQL with 127.0.0.1, you may need to specify the TCP/IP protocol.

mysql -uroot -p -h127.0.0.1 --protocol=tcp

or try the DNS name

mysql -uroot -p -hDNSNAME

This will bypass logging in as root@localhost, but make sure you have root@'127.0.0.1' defined.

Next time you connect to MySQL, run this:

SELECT USER(),CURRENT_USER();

What does this give you?

  • USER() reports how you attempted to authenticate in MySQL
  • CURRENT_USER() reports how you were allowed to authenticate in MySQL

If these functions return with the same values, then you are connecting and authenticating as expected. If the values are different, you may need to create the corresponding user root@127.0.0.1.


回答 14

遇到了同样的问题。原来mysqld已经停止运行了(我在Mac OSX上)。我重新启动它,错误消失了。

我发现mysqld该链接在很大程度上没有运行: http //dev.mysql.com/doc/refman/5.6/en/can-not-connect-to-server.html

注意第一个技巧!

Had this same problem. Turned out mysqld had stopped running (I’m on Mac OSX). I restarted it and the error went away.

I figured out that mysqld was not running largely because of this link: http://dev.mysql.com/doc/refman/5.6/en/can-not-connect-to-server.html

Notice the first tip!


回答 15

如果出现如下错误:

django.db.utils.OperationalError: (2002, "Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)")

然后只要找到您的mysqld.sock文件位置并将其添加到“主机”即可。

就像我在Linux上使用xampp一样,所以我的mysqld.sock文件在另一个位置。因此它不适用于“ /var/run/mysqld/mysqld.sock

DATABASES = {

    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'asd',
        'USER' : 'root',
        'PASSWORD' : '',
        'HOST' : '/opt/lampp/var/mysql/mysql.sock',
        'PORT' : ''
    }
}

if you get an error like below :

django.db.utils.OperationalError: (2002, "Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)")

Then just find your mysqld.sock file location and add it to “HOST”.

Like i am using xampp on linux so my mysqld.sock file is in another location. so it is not working for ‘/var/run/mysqld/mysqld.sock

DATABASES = {

    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'asd',
        'USER' : 'root',
        'PASSWORD' : '',
        'HOST' : '/opt/lampp/var/mysql/mysql.sock',
        'PORT' : ''
    }
}

回答 16

如果my.cnf中的设置不正确,请检查您的mysql是否未达到最大连接数,或是否未处于某种引导循环中。

使用ps aux | grep mysql检查PID是否正在更改。

Check that your mysql has not reached maximum connections, or is not in some sort of booting loop as happens quite often if the settings are incorrect in my.cnf.

Use ps aux | grep mysql to check if the PID is changing.


回答 17

在网上环顾四周时间太长,无济于事。尝试从命令行键入mysql提示符后,我继续收到此消息:

错误2002(HY000):无法通过套接字’/tmp/mysql.sock’连接到本地MySQL服务器(2)

这是因为我的本地mysql服务器不再运行。为了重新启动服务器,我导航到

shell> cd /user/local/bin

我的mysql.server所在的位置。在这里,只需键入:

shell> mysql.server start

这将重新启动本地mysql服务器。

从那里您可以根据需要重置root密码。

mysql> UPDATE mysql.user SET Password=PASSWORD('MyNewPass')
->                   WHERE User='root';
mysql> FLUSH PRIVILEGES;

Looked around online too long not to contribute. After trying to type in the mysql prompt from the command line, I was continuing to receive this message:

ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/tmp/mysql.sock’ (2)

This was due to the fact that my local mysql server was no longer running. In order to restart the server, I navigated to

shell> cd /user/local/bin

where my mysql.server was located. From here, simply type:

shell> mysql.server start

This will relaunch the local mysql server.

From there you can reset the root password if need be..

mysql> UPDATE mysql.user SET Password=PASSWORD('MyNewPass')
->                   WHERE User='root';
mysql> FLUSH PRIVILEGES;

回答 18

我必须首先找到所有进程ID,以杀死mysql的所有实例:

ps aux | grep MySQL的

然后杀死他们:

杀死-9 {pid}

然后:

mysql.server启动

为我工作。

I had to kill off all instances of mysql by first finding all the process IDs:

ps aux | grep mysql

And then killing them off:

kill -9 {pid}

Then:

mysql.server start

Worked for me.


回答 19

套接字位于/ tmp中。在Unix系统上,由于/ tmp上的模式和所有权,这可能会引起一些问题。但是,只要您告诉我们可以正常使用mysql连接,我想这对您的系统来说不是问题。首要检查应该是将mysql.sock放置在一个更中性的目录中。

问题“随机”发生(或并非每次都发生),这一事实让我认为这可能是服务器问题。

  • 您的/ tmp是位于标准磁盘上,还是位于奇异的挂载上(如RAM中)?

  • / tmp是空的吗?

  • iotop遇到问题时,是否表明您有问题?

The socket is located in /tmp. On Unix system, due to modes & ownerships on /tmp, this could cause some problem. But, as long as you tell us that you CAN use your mysql connexion normally, I guess it is not a problem on your system. A primal check should be to relocate mysql.sock in a more neutral directory.

The fact that the problem occurs “randomly” (or not every time) let me think that it could be a server problem.

  • Is your /tmp located on a standard disk, or on an exotic mount (like in the RAM) ?

  • Is your /tmp empty ?

  • Does iotopshow you something wrong when you encounter the problem ?


回答 20

在“管理数据库连接”对话框中配置数据库连接。选择“标准(TCP / IP)”作为连接方法。

有关更多详细信息,请参见此页面 http://dev.mysql.com/doc/workbench/en/wb-manage-db-connections.html

根据另一页,即使您指定localhost,也会使用套接字文件。

如果您未指定主机名或指定特殊主机名localhost,则使用Unix套接字文件。

它还显示了如何通过运行以下命令来检查服务器:

如果mysqld进程正在运行,则可以通过尝试以下命令进行检查。您的设置中的端口号或Unix套接字文件名可能不同。host_ip代表运行服务器的计算机的IP地址。

shell> mysqladmin version 
shell> mysqladmin variables 
shell> mysqladmin -h `hostname` version variables 
shell> mysqladmin -h `hostname` --port=3306 version 
shell> mysqladmin -h host_ip version 
shell> mysqladmin --protocol=SOCKET --socket=/tmp/mysql.sock version

Configure your DB connection in the ‘Manage DB Connections dialog. Select ‘Standard (TCP/IP)’ as connection method.

See this page for more details http://dev.mysql.com/doc/workbench/en/wb-manage-db-connections.html

According to this other page a socket file is used even if you specify localhost.

A Unix socket file is used if you do not specify a host name or if you specify the special host name localhost.

It also shows how to check on your server by running these commands:

If a mysqld process is running, you can check it by trying the following commands. The port number or Unix socket file name might be different in your setup. host_ip represents the IP address of the machine where the server is running.

shell> mysqladmin version 
shell> mysqladmin variables 
shell> mysqladmin -h `hostname` version variables 
shell> mysqladmin -h `hostname` --port=3306 version 
shell> mysqladmin -h host_ip version 
shell> mysqladmin --protocol=SOCKET --socket=/tmp/mysql.sock version

回答 21

在ubuntu14.04中,您可以执行此操作以解决此问题。

zack@zack:~/pycodes/python-scraping/chapter5$ **mysqladmin -p variables|grep socket**
Enter password: 
| socket                                            | ***/var/run/mysqld/mysqld.sock***                                                                                            |
zack@zack:~/pycodes/python-scraping/chapter5$***ln -s  /var/run/mysqld/mysqld.sock /tmp/mysql.sock***
zack@zack:~/pycodes/python-scraping/chapter5$ ll /tmp/mysql.sock 
lrwxrwxrwx 1 zack zack 27 11 29 13:08 /tmp/mysql.sock -> /var/run/mysqld/mysqld.sock=

in ubuntu14.04 you can do this to slove this problem.

zack@zack:~/pycodes/python-scraping/chapter5$ **mysqladmin -p variables|grep socket**
Enter password: 
| socket                                            | ***/var/run/mysqld/mysqld.sock***                                                                                            |
zack@zack:~/pycodes/python-scraping/chapter5$***ln -s  /var/run/mysqld/mysqld.sock /tmp/mysql.sock***
zack@zack:~/pycodes/python-scraping/chapter5$ ll /tmp/mysql.sock 
lrwxrwxrwx 1 zack zack 27 11月 29 13:08 /tmp/mysql.sock -> /var/run/mysqld/mysqld.sock=

回答 22

对我来说,我确定mysqld已启动,并且命令行mysql可以正常工作。但是httpd服务器显示了问题(无法通过套接字连接到mysql)。

我使用mysqld_safe&启动了该服务。

最后,我发现当我使用服务mysqld start启动mysqld服务时,出现了问题(selinux权限问题),当我修复了selinux问题,并使用“ service mysqld start”启动mysqld时,httpd连接问题消失了。但是,当我使用mysqld_safe&启动mysqld时,可以使用mysqld。(mysql客户端可以正常工作)。但是与httpd连接时仍然存在问题。

For me, I’m sure mysqld is started, and command line mysql can work properly. But the httpd server show the issue(can’t connect to mysql through socket).

I started the service with mysqld_safe&.

finally, I found when I start the mysqld service with service mysqld start, there are issues(selinux permission issue), and when I fix the selinux issue, and start the mysqld with “service mysqld start”, the httpd connection issue disappear. But when I start the mysqld with mysqld_safe&, mysqld can be worked. (mysql client can work properly). But there are still issue when connect with httpd.


回答 23

如果与套接字相关,请阅读此文件

/etc/mysql/my.cnf

并查看什么是标准插座位置。就像这样的一行:

socket = /var/run/mysqld/mysqld.sock

现在为您的shell创建一个别名,例如:

alias mysql="mysql --socket=/var/run/mysqld/mysqld.sock"

这样,您就不需要root特权。

If it’s socket related read this file

/etc/mysql/my.cnf

and see what is the standard socket location. It’s a line like:

socket = /var/run/mysqld/mysqld.sock

now create an alias for your shell like:

alias mysql="mysql --socket=/var/run/mysqld/mysqld.sock"

This way you don’t need root privileges.


回答 24

只需尝试运行 mysqld

在Mac上,这对我不起作用。如果不起作用/usr/local/var/mysql/<your_name>.err,请尝试查看详细的错误日志。

Simply try to run mysqld.

This was what was not working for me on mac. If it doesn’t work try go to /usr/local/var/mysql/<your_name>.err to see detailed error logs.


回答 25

# shell script ,ignore the first 
$ $(dirname `which mysql`)\/mysql.server start

可能会有帮助。

# shell script ,ignore the first 
$ $(dirname `which mysql`)\/mysql.server start

May be helpful.


回答 26

使用通过Homebrew安装的适用于MySQL 8.0.19的MacOS Mojave 10.14.6

  • sudo find / -name my.cnf
  • 文件位于 /usr/local/etc/my.cnf

工作了一段时间,然后最终返回了错误。卸载MySQL的Homebrew版本并直接从.dmg文件安装此处

从那时起,我们一直很高兴地建立联系。

Using MacOS Mojave 10.14.6 for MySQL 8.0.19 installed via Homebrew

  • Ran sudo find / -name my.cnf
  • File found at /usr/local/etc/my.cnf

Worked for a time then eventually the error returned. Uninstalled the Homebrew version of MySQL and installed the .dmg file directly from here

Happily connecting since then.


回答 27

就我而言,帮助编辑文件/etc/mysql/mysql.conf.d/mysqld.cnf并替换以下行:

socket      = /var/run/mysqld/mysqld.sock

socket      = /tmp/mysql.sock

然后,我重新启动服务器,它工作正常。有趣的是,如果我将线路恢复原状并重新启动,它仍然可以工作。

In my case what helped was to edit the file /etc/mysql/mysql.conf.d/mysqld.cnfand replace the line:

socket      = /var/run/mysqld/mysqld.sock

with

socket      = /tmp/mysql.sock

Then I restarted the server and it worked fine. The funny thing is that if I put back the line as it was before and restarted it still worked..


回答 28

我最近也遇到过类似的问题。经历了许多答案。我按照以下步骤操作。

  1. 更改/etc/my.cnf中的套接字路径(因为我反复出现/tmp/mysql.sock错误)引用以更改套接字路径
  2. 运行mysqld_safe以重新启动服务器,因为这是在出现错误时重新启动的推荐方法。引用mysqld_safe

I had faced similar problem recently. Went through many answers. I got it working by following steps.

  1. change the socket path in /etc/my.cnf (as i was repeatedly getting error with /tmp/mysql.sock ) reference to change the socket path
  2. run mysqld_safe to restart the server as it is the recommended way to restart in case of errors. reference to mysqld_safe

回答 29

对我而言,mysql服务器未运行。因此,我通过启动了mysql服务器

mysql.server start

然后

mysql_secure_installation

保护服务器,现在我可以通过访问MySQL服务器

sudo mysql -uroot -p

For me, the mysql server was not running. So, i started the mysql server through

mysql.server start

then

mysql_secure_installation

to secure the server and now I can visit the MySQL server through

sudo mysql -uroot -p


有关使用Google App Engine的反馈?[关闭]

问题:有关使用Google App Engine的反馈?[关闭]

希望做一个非常小,快速而又肮脏的项目。我喜欢Google App Engine在Python上运行并内置Django的事实-给我借口尝试该平台…但是我的问题是:

除了玩具问题以外,还有人利用App Engine处理其他事情吗?我看到了一些很好的示例应用程序,因此我认为这对于真实交易来说已经足够了,但是我想获得一些反馈。

任何其他成功/失败记录都很棒。

Looking to do a very small, quick ‘n dirty side project. I like the fact that the Google App Engine is running on Python with Django built right in – gives me an excuse to try that platform… but my question is this:

Has anyone made use of the app engine for anything other than a toy problem? I see some good example apps out there, so I would assume this is good enough for the real deal, but wanted to get some feedback.

Any other success/failure notes would be great.


回答 0

我已经为小型地震监视应用程序http://quakewatch.appspot.com/尝试了应用引擎

我的目的是查看应用程序引擎的功能,因此主要要点:

  1. 默认情况下,它不是Django附带的,它有自己的Web框架,它是pythonic的,具有像Django这样的URL调度程序,并且使用Django模板。因此,如果您有Django exp。您会发现它易于使用
  2. 您无法在服务器上执行任何长时间运行的进程,您要做的就是回复请求,并且应该很快,否则appengine会杀死它。因此,如果您的应用程序需要大量后端处理,则appengine不是最佳方法,否则您将不得不进行处理在您自己的服务器上
  3. 我的quakewatch应用程序具有订阅功能,这意味着我必须通过电子邮件将最新的地震发生,但是我无法在app引擎中运行后台进程来监视新的地震解决方案,这里是使用像pingablity.com这样的第三方服务,连接到您的页面之一并执行订阅电子邮件程序,但是在这里您还必须注意不要在这里花费太多时间或将任务分成几部分
  4. 它提供了类似于Django的建模功能,但后端完全不同,但是对于新项目而言,这并不重要。

但是总的来说,我认为这对于创建不需要大量后台处理的应用程序非常有用。

编辑:现在,任务队列可用于运行批处理或计划的任务

编辑:在GAE上工作/创建一个真实的应用程序一年之后,现在我的看法是,除非您要开发需要扩展到数百万用户的应用程序,否则请不要使用GAE。由于具有分布式特性,因此在GAE中维护和执行琐碎的任务是一件令人头疼的事情,为了避免超出期限,错误地计数实体或执行复杂的查询需要复杂的代码,因此小型复杂的应用程序应坚持使用LAMP。

编辑:模型应该特别考虑到您将来希望进行的所有交易而设计,因为只能在同一实体组中的实体可以在交易中使用,并且这使得更新两个不同组的过程成为噩梦,例如将资金从user1转移到user2除非它们在同一个实体组中,否则不可能在事务中进行交易,但是对于频繁更新而言,使它们成为同一实体组可能不是最好的….阅读此http://blog.notdot.net/2009/9/Distributed-Transactions-应用引擎

I have tried app engine for my small quake watch application http://quakewatch.appspot.com/

My purpose was to see the capabilities of app engine, so here are the main points:

  1. it doesn’t come by default with Django, it has its own web framework which is pythonic has URL dispatcher like Django and it uses Django templates So if you have Django exp. you will find it easy to use
  2. You can not execute any long running process on server, what you do is reply to request and which should be quick otherwise appengine will kill it So if your app needs lots of backend processing appengine is not the best way otherwise you will have to do processing on a server of your own
  3. My quakewatch app has a subscription feature, it means I had to email latest quakes as they happend, but I can not run a background process in app engine to monitor new quakes solution here is to use a third part service like pingablity.com which can connect to one of your page and which executes the subscription emailer but here also you will have to take care that you don’t spend much time here or break task into several pieces
  4. It provides Django like modeling capabilities but backend is totally different but for a new project it should not matter.

But overall I think it is excellent for creating apps which do not need lot of background processing.

Edit: Now task queues can be used for running batch processing or scheduled tasks

Edit: after working/creating a real application on GAE for a year, now my opnion is that unless you are making a application which needs to scale to million and million of users, don’t use GAE. Maintaining and doing trivial tasks in GAE is a headache due to distributed nature, to avoid deadline exceeded errors, count entities or do complex queries requires complex code, so small complex application should stick to LAMP.

Edit: Models should be specially designed considering all the transactions you wish to have in future, because entities only in same entity group can be used in a transaction and it makes the process of updating two different groups a nightmare e.g. transfer money from user1 to user2 in transaction is impossible unless they are in same entity group, but making them same entity group may not be best for frequent update purposes…. read this http://blog.notdot.net/2009/9/Distributed-Transactions-on-App-Engine


回答 1

我正在使用GAE托管多个高流量应用程序。大约为50-100 req / sec。太好了,我不能推荐它。

我以前的Web开发经验是使用Ruby(Rails / Merb)。学习Python很容易。我并没有弄乱Django或Pylons或任何其他框架,只是从GAE示例开始,并从提供的基本webapp库中构建了我需要的东西。

如果您习惯了SQL的灵活性,那么数据存储区可能需要一些时间来适应。没什么太伤人的!最大的调整是远离JOIN。您必须摆脱标准化是至关重要的想法。

I am using GAE to host several high-traffic applications. Like on the order of 50-100 req/sec. It is great, I can’t recommend it enough.

My previous experience with web development was with Ruby (Rails/Merb). Learning Python was easy. I didn’t mess with Django or Pylons or any other framework, just started from the GAE examples and built what I needed out of the basic webapp libraries that are provided.

If you’re used to the flexibility of SQL the datastore can take some getting used to. Nothing too traumatic! The biggest adjustment is moving away from JOINs. You have to shed the idea that normalizing is crucial.

Ben


回答 2

我使用Google App Engine的令人信服的原因之一是它与您所在域的Google Apps集成。从本质上讲,它允许您创建自定义的托管Web应用程序,这些应用程序仅限于您域的(受控)登录名。

我在这段代码中的大部分经验是构建一个简单的时间/任务跟踪应用程序。模板引擎很简单,但是使多页应用程序非常容易上手。登录/用户意识api同样有用。我能够创建一个公共页面/私有页面范例而没有太多问题。(用户将登录以查看私有页面。仅向匿名用户显示公共页面。)

当我因从事“实际工作”而离开时,我只是进入项目的数据存储部分。

我能够在极短的时间内完成很多工作(尚未完成)。因为我以前从未使用过Python,所以这特别令人愉快(既因为这对我来说是一种新语言,也因为尽管使用了新语言,但开发仍然非常快)。我碰到的很少,使我相信我将无法完成任务。相反,我对功能和特性有一个相当积极的印象。

这就是我的经验。也许它不仅仅代表未完成的玩具项目,还代表对平台的知情试用,我希望能有所帮助。

One of the compelling reasons I have come across for using Google App Engine is its integration with Google Apps for your domain. Essentially it allows you to create custom, managed web applications that are restricted to the (controlled) logins of your domain.

Most of my experience with this code was building a simple time/task tracking application. The template engine was simple and yet made a multi-page application very approachable. The login/user awareness api is similarly useful. I was able to make a public page/private page paradigm without too much issue. (a user would log in to see the private pages. An anonymous user was only shown the public page.)

I was just getting into the datastore portion of the project when I got pulled away for “real work”.

I was able to accomplish a lot (it still is not done yet) in a very little amount of time. Since I had never used Python before, this was particularly pleasant (both because it was a new language for me, and also because the development was still fast despite the new language). I ran into very little that led me to believe that I wouldn’t be able to accomplish my task. Instead I have a fairly positive impression of the functionality and features.

That is my experience with it. Perhaps it doesn’t represent more than an unfinished toy project, but it does represent an informed trial of the platform, and I hope that helps.


回答 3

“运行Django的App Engine”的想法有点误导。App Engine取代了整个Django模型层,因此准备花一些时间适应App Engine的数据存储,这需要以不同的方式建模和思考数据。

The “App Engine running Django” idea is a bit misleading. App Engine replaces the entire Django model layer so be prepared to spend some time getting acclimated with App Engine’s datastore which requires a different way of modeling and thinking about data.


回答 4

我用GAE建立了http://www.muspy.com

它不仅是一个玩具项目,而且也不过分复杂。我仍然依赖于Google可以解决的一些问题,但是整体开发网站是一种令人愉快的体验。

如果您不想处理托管问题,服务器管理等问题,绝对可以推荐。特别是如果您已经了解Python和Django。

I used GAE to build http://www.muspy.com

It’s a bit more than a toy project but not overly complex either. I still depend on a few issues to be addressed by Google, but overall developing the website was an enjoyable experience.

If you don’t want to deal with hosting issues, server administration, etc, I can definitely recommend it. Especially if you already know Python and Django.


回答 5

我认为,对于小型项目,App Engine目前非常不错。有很多事情可以说,不必担心托管。该API还会引导您朝着构建可扩展应用程序的方向发展,这是一种很好的做法。

  • app-engine-patch是Django和App Engine之间的良好层,可启用auth应用程序及更多功能。
  • Google承诺在2008年底之前提供SLA和定价模型。
  • 请求必须在10秒内完成,对Web服务的子请求则需要在5秒内完成。这迫使您设计一个快速,轻量级的应用程序,将重要的处理工作卸载到其他平台(例如,托管服务或EC2实例)。
  • 更多语言即将推出!Google不会说:-)。我的钱接下来是Java。

I think App Engine is pretty cool for small projects at this point. There’s a lot to be said for never having to worry about hosting. The API also pushes you in the direction of building scalable apps, which is good practice.

  • app-engine-patch is a good layer between Django and App Engine, enabling the use of the auth app and more.
  • Google have promised an SLA and pricing model by the end of 2008.
  • Requests must complete in 10 seconds, sub-requests to web services required to complete in 5 seconds. This forces you to design a fast, lightweight application, off-loading serious processing to other platforms (e.g. a hosted service or an EC2 instance).
  • More languages are coming soon! Google won’t say which though :-). My money’s on Java next.

回答 6

这个问题已经被完全回答。哪个好 但是也许有一件事值得一提。google app引擎有一个eclipse ide插件,很高兴使用。

如果您已经使用Eclipse进行开发,您将对此感到非常高兴。

要在Google App Engine的网站上进行部署,我需要做的就是单击一个带有飞机徽标的小按钮-超级。

This question has been fully answered. Which is good. But one thing perhaps is worth mentioning. The google app engine has a plugin for the eclipse ide which is a joy to work with.

If you already do your development with eclipse you are going to be so happy about that.

To deploy on the google app engine’s web site all I need to do is click one little button – with the airplane logo – super.


回答 7

看一下sql游戏,它非常稳定,实际上将流量限制提高了一点,从而使其受到Google的限制。除了将App托管在其他人完全控制的服务器上之外,我没有看到关于App Engine的好消息。

Take a look the the sql game, it is very stable and actually pushed traffic limits at one point so that it was getting throttled by Google. I have seen nothing but good news about App Engine, other than hosting you app on servers someone else controls completely.


回答 8

我使用GAE构建了一个简单的应用程序,该应用程序接受一些参数,格式并发送电子邮件。这是非常简单和快速的。我还在GAE数据存储和内存缓存服务(http://dbaspects.blogspot.com/2010/01/memcache-vs-datastore-on-google-app.html)上做了一些性能基准测试。没有那么快。我认为GAE是执行特定方法的严肃平台。我认为它将演变为真正可扩展的平台,在该平台上根本不允许不良做法。

I used GAE to build a simple application which accepts some parameters, formats and send email. It was extremely simple and fast. I also made some performance benchmarks on the GAE datastore and memcache services (http://dbaspects.blogspot.com/2010/01/memcache-vs-datastore-on-google-app.html ). It is not that fast. My opinion is that GAE is serious platform which enforce certain methodology. I think it will evolve to the truly scalable platform, where bad practices simply not allowed.


回答 9

我将GAE用于我的Flash游戏网站Bearded Games。GAE是一个很棒的平台。我使用了Django模板,它比PHP过去要容易得多。它带有出色的管理面板,并为您提供了非常好的日志。数据存储区不同于MySQL之类的数据库,但是使用起来要容易得多。建立网站非常简单明了,他们在网站上有很多有用的建议。

I used GAE for my flash gaming site, Bearded Games. GAE is a great platform. I used Django templates which are so much easier than the old days of PHP. It comes with a great admin panel, and gives you really good logs. The datastore is different than a database like MySQL, but it’s much easier to work with. Building the site was easy and straightforward and they have lots of helpful advice on the site.


回答 10

我使用GAE和Django构建了Facebook应用程序。我以http://code.google.com/p/app-engine-patch作为起点,因为它具有Django 1.1支持。我没有尝试使用任何manage.py命令,因为我认为它们不起作用,但是我什至没有调查。该应用程序具有三个模型,还使用了pyfacebook,但这就是复杂程度。我正在构建一个更加复杂的应用程序,并开始在http://brianyamabe.com上发布博客。

I used GAE and Django to build a Facebook application. I used http://code.google.com/p/app-engine-patch as my starting point as it has Django 1.1 support. I didn’t try to use any of the manage.py commands because I assumed they wouldn’t work, but I didn’t even look into it. The application had three models and also used pyfacebook, but that was the extent of the complexity. I’m in the process of building a much more complicated application which I’m starting to blog about on http://brianyamabe.com.


如何仅在内存中运行Django的测试数据库?

问题:如何仅在内存中运行Django的测试数据库?

我的Django单元测试需要很长时间才能运行,因此我正在寻找加快速度的方法。我正在考虑安装SSD,但我知道它也有缺点。当然,我的代码可以做一些事情,但是我正在寻找结构上的修复方法。由于每次都需要重建/向南迁移数据库,因此即使运行单个测试也很慢。所以这是我的主意…

由于我知道测试数据库总是很小,所以为什么不能仅将系统配置为始终将整个测试数据库保留在RAM中?绝对不要触摸磁盘。如何在Django中配置它?我宁愿继续使用MySQL,因为这是我在生产中使用的方式,但是如果使用SQLite  3或其他方法可以简化这一点,我会采用这种方式。

SQLite或MySQL是否可以选择完全在内存中运行?应该可以配置RAM磁盘,然后配置测试数据库以将其数据存储在其中,但是我不确定如何告诉Django / MySQL为特定数据库使用不同的数据目录,特别是因为它不断被删除并重新创建每次运行。(我在Mac FWIW上。)

My Django unit tests take a long time to run, so I’m looking for ways to speed that up. I’m considering installing an SSD, but I know that has its downsides too. Of course, there are things I could do with my code, but I’m looking for a structural fix. Even running a single test is slow since the database needs to be rebuilt / south migrated every time. So here’s my idea…

Since I know the test database will always be quite small, why can’t I just configure the system to always keep the entire test database in RAM? Never touch the disk at all. How do I configure this in Django? I’d prefer to keep using MySQL since that’s what I use in production, but if SQLite 3 or something else makes this easy, I’d go that way.

Does SQLite or MySQL have an option to run entirely in memory? It should be possible to configure a RAM disk and then configure the test database to store its data there, but I’m not sure how to tell Django / MySQL to use a different data directory for a certain database, especially since it keeps getting erased and recreated each run. (I’m on a Mac FWIW.)


回答 0

如果在运行测试时将数据库引擎设置为sqlite3,则Django将使用内存数据库

settings.py在运行测试时使用如下代码将引擎设置为sqlite:

if 'test' in sys.argv:
    DATABASE_ENGINE = 'sqlite3'

或在Django 1.2中:

if 'test' in sys.argv:
    DATABASES['default'] = {'ENGINE': 'sqlite3'}

最后在Django 1.3和1.4中:

if 'test' in sys.argv:
    DATABASES['default'] = {'ENGINE': 'django.db.backends.sqlite3'}

(到Django 1.3并不一定要有完整的后端路径,但是可以使设置向前兼容。)

您还可以添加以下行,以防南向迁移出现问题:

    SOUTH_TESTS_MIGRATE = False

If you set your database engine to sqlite3 when you run your tests, Django will use a in-memory database.

I’m using code like this in my settings.py to set the engine to sqlite when running my tests:

if 'test' in sys.argv:
    DATABASE_ENGINE = 'sqlite3'

Or in Django 1.2:

if 'test' in sys.argv:
    DATABASES['default'] = {'ENGINE': 'sqlite3'}

And finally in Django 1.3 and 1.4:

if 'test' in sys.argv:
    DATABASES['default'] = {'ENGINE': 'django.db.backends.sqlite3'}

(The full path to the backend isn’t strictly necessary with Django 1.3, but makes the setting forward compatible.)

You can also add the following line, in case you are having problems with South migrations:

    SOUTH_TESTS_MIGRATE = False

回答 1

我通常为测试创建一个单独的设置文件,并在测试命令中使用它,例如

python manage.py test --settings=mysite.test_settings myapp

它有两个好处:

  1. 您不必检查testsys.argv中的任何此类神奇词,test_settings.py只需

    from settings import *
    
    # make tests faster
    SOUTH_TESTS_MIGRATE = False
    DATABASES['default'] = {'ENGINE': 'django.db.backends.sqlite3'}

    或者,您可以根据需要进一步调整它,将测试设置与生产设置完全分开。

  2. 另一个好处是您可以使用生产数据库引擎而不是sqlite3进行测试,从而避免了细微的错误,因此在开发使用时

    python manage.py test --settings=mysite.test_settings myapp

    并在提交代码之前运行一次

    python manage.py test myapp

    只是为了确保所有测试都通过了。

I usually create a separate settings file for tests and use it in test command e.g.

python manage.py test --settings=mysite.test_settings myapp

It has two benefits:

  1. You don’t have to check for test or any such magic word in sys.argv, test_settings.py can simply be

    from settings import *
    
    # make tests faster
    SOUTH_TESTS_MIGRATE = False
    DATABASES['default'] = {'ENGINE': 'django.db.backends.sqlite3'}
    

    Or you can further tweak it for your needs, cleanly separating test settings from production settings.

  2. Another benefit is that you can run test with production database engine instead of sqlite3 avoiding subtle bugs, so while developing use

    python manage.py test --settings=mysite.test_settings myapp
    

    and before committing code run once

    python manage.py test myapp
    

    just to be sure that all test are really passing.


回答 2

MySQL支持称为“ MEMORY”的存储引擎,您可以在数据库config(settings.py)中对其进行配置,如下所示:

    'USER': 'root',                      # Not used with sqlite3.
    'PASSWORD': '',                  # Not used with sqlite3.
    'OPTIONS': {
        "init_command": "SET storage_engine=MEMORY",
    }

请注意,MEMORY存储引擎不支持blob /文本列,因此,如果您使用django.db.models.TextField此功能,则将无法使用。

MySQL supports a storage engine called “MEMORY”, which you can configure in your database config (settings.py) as such:

    'USER': 'root',                      # Not used with sqlite3.
    'PASSWORD': '',                  # Not used with sqlite3.
    'OPTIONS': {
        "init_command": "SET storage_engine=MEMORY",
    }

Note that the MEMORY storage engine doesn’t support blob / text columns, so if you’re using django.db.models.TextField this won’t work for you.


回答 3

我无法回答您的主要问题,但是您可以做一些事情来加快速度。

首先,请确保您的MySQL数据库已设置为使用InnoDB。然后,它可以使用事务在每次测试之前回滚db的状态,以我的经验,这导致了极大的提速。您可以在settings.py中传递数据库init命令(Django 1.2语法):

DATABASES = {
    'default': {
            'ENGINE':'django.db.backends.mysql',
            'HOST':'localhost',
            'NAME':'mydb',
            'USER':'whoever',
            'PASSWORD':'whatever',
            'OPTIONS':{"init_command": "SET storage_engine=INNODB" } 
        }
    }

其次,您不需要每次都运行South迁移。设置SOUTH_TESTS_MIGRATE = False在你的settings.py和数据库将与普通的执行syncdb,这将是比通过所有历史悠久的迁移运行更快创建。

I can’t answer your main question, but there are a couple of things that you can do to speed things up.

Firstly, make sure that your MySQL database is set up to use InnoDB. Then it can use transactions to rollback the state of the db before each test, which in my experience has led to a massive speed-up. You can pass a database init command in your settings.py (Django 1.2 syntax):

DATABASES = {
    'default': {
            'ENGINE':'django.db.backends.mysql',
            'HOST':'localhost',
            'NAME':'mydb',
            'USER':'whoever',
            'PASSWORD':'whatever',
            'OPTIONS':{"init_command": "SET storage_engine=INNODB" } 
        }
    }

Secondly, you don’t need to run the South migrations each time. Set SOUTH_TESTS_MIGRATE = False in your settings.py and the database will be created with plain syncdb, which will be much quicker than running through all the historic migrations.


回答 4

您可以进行两次调整:

  • 使用事务表:在每个TestCase之后,将使用数据库回滚来设置初始固定装置状态。
  • 将您的数据库数据目录放在ramdisk上:就数据库创建而言,您将获得很多收益,并且运行测试会更快。

我正在使用这两种技巧,我很高兴。

如何在Ubuntu上为MySQL设置它:

$ sudo service mysql stop
$ sudo cp -pRL /var/lib/mysql /dev/shm/mysql

$ vim /etc/mysql/my.cnf
# datadir = /dev/shm/mysql
$ sudo service mysql start

当心,这只是为了测试,从内存中重新启动数据库后,丢失了!

You can do double tweaking:

  • use transactional tables: initial fixtures state will be set using database rollback after every TestCase.
  • put your database data dir on ramdisk: you will gain much as far as database creation is concerned and also running test will be faster.

I’m using both tricks and I’m quite happy.

How to set up it for MySQL on Ubuntu:

$ sudo service mysql stop
$ sudo cp -pRL /var/lib/mysql /dev/shm/mysql

$ vim /etc/mysql/my.cnf
# datadir = /dev/shm/mysql
$ sudo service mysql start

Beware, it’s just for testing, after reboot your database from memory is lost!


回答 5

另一种方法:让另一个MySQL实例在使用RAM磁盘的tempf中运行。这篇博客文章中的说明:加速MySQL以在Django中进行测试

优点:

  • 您使用与生产服务器完全相同的数据库
  • 无需更改默认的mysql配置

Another approach: have another instance of MySQL running in a tempfs that uses a RAM Disk. Instructions in this blog post: Speeding up MySQL for testing in Django.

Advantages:

  • You use the exactly same database that your production server uses
  • no need to change your default mysql configuration

回答 6

通过扩展Anurag的答案,我通过创建相同的test_settings并将以下内容添加到manage.py来简化了过程

if len(sys.argv) > 1 and sys.argv[1] == "test":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.test_settings")
else:
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")

似乎更干净,因为sys已经导入并且manage.py仅通过命令行使用,因此无需弄乱设置

Extending on Anurag’s answer I simplified the process by creating the same test_settings and adding the following to manage.py

if len(sys.argv) > 1 and sys.argv[1] == "test":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.test_settings")
else:
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")

seems cleaner since sys is already imported and manage.py is only used via command line, so no need to clutter up settings


回答 7

在您的下方使用 setting.py

DATABASES['default']['ENGINE'] = 'django.db.backends.sqlite3'

Use below in your setting.py

DATABASES['default']['ENGINE'] = 'django.db.backends.sqlite3'

如何覆盖和扩展基本的Django管理模板?

问题:如何覆盖和扩展基本的Django管理模板?

如何覆盖管理模板(例如admin / index.html),同时扩展它(请参阅https://docs.djangoproject.com/en/dev/ref/contrib/admin/#overriding-vs-replacing -an-admin-template)?

首先-我知道这个问题已经被问过并回答过(请参阅Django:覆盖和扩展应用程序模板),但是正如答案所言,如果您使用的是app_directories模板加载器(这是大多数时间)。

我当前的解决方法是制作副本并从中扩展,而不是直接从管理模板扩展。这很好用,但是确实很混乱,并且在管理模板更改时增加了额外的工作。

它可能会想到一些针对模板的自定义扩展标签,但如果已有解决方案,我不想重新发明轮子。

附带说明一下:有人知道Django本身是否可以解决此问题?

How do I override an admin template (e.g. admin/index.html) while at the same time extending it (see https://docs.djangoproject.com/en/dev/ref/contrib/admin/#overriding-vs-replacing-an-admin-template)?

First – I know that this question has been asked and answered before (see Django: Overriding AND extending an app template) but as the answer says it isn’t directly applicable if you’re using the app_directories template loader (which is most of the time).

My current workaround is to make copies and extend from them instead of extending directly from the admin templates. This works great but it’s really confusing and adds extra work when the admin templates change.

It could think of some custom extend-tag for the templates but I don’t want to reinvent the wheel if there already exists a solution.

On a side note: Does anybody know if this problem will be addressed by Django itself?


回答 0

更新

阅读适用于您的Django版本的文档。例如

https://docs.djangoproject.com/zh-CN/1.11/ref/contrib/admin/#admin-overriding-templates https://docs.djangoproject.com/en/2.0/ref/contrib/admin/#admin-overriding -模板

2011年的原始答案:

大约一年半以前,我遇到了同样的问题,并且在djangosnippets.org上找到了一个不错的模板加载器,可以轻松实现这一目的。它允许您在特定应用程序中扩展模板,从而使您能够创建自己的admin / index.html,从而从管理应用程序扩展admin / index.html模板。像这样:

{% extends "admin:admin/index.html" %}

{% block sidebar %}
    {{block.super}}
    <div>
        <h1>Extra links</h1>
        <a href="https://stackoverflow.com/admin/extra/">My extra link</a>
    </div>
{% endblock %}

我在我网站上的博客文章中提供了有关如何使用此模板加载器的完整示例。

Update:

Read the Docs for your version of Django. e.g.

https://docs.djangoproject.com/en/1.11/ref/contrib/admin/#admin-overriding-templates https://docs.djangoproject.com/en/2.0/ref/contrib/admin/#admin-overriding-templates https://docs.djangoproject.com/en/3.0/ref/contrib/admin/#admin-overriding-templates

Original answer from 2011:

I had the same issue about a year and a half ago and I found a nice template loader on djangosnippets.org that makes this easy. It allows you to extend a template in a specific app, giving you the ability to create your own admin/index.html that extends the admin/index.html template from the admin app. Like this:

{% extends "admin:admin/index.html" %}

{% block sidebar %}
    {{block.super}}
    <div>
        <h1>Extra links</h1>
        <a href="/admin/extra/">My extra link</a>
    </div>
{% endblock %}

I’ve given a full example on how to use this template loader in a blog post on my website.


回答 1

对于最新版本的Django 1.8,无需进行符号链接,将admin / templates复制到您的项目文件夹中,也无需按照上面的答案建议安装中间件。这是做什么的:

  1. 创建以下树结构(官方文档推荐)

    your_project
         |-- your_project/
         |-- myapp/
         |-- templates/
              |-- admin/
                  |-- myapp/
                      |-- change_form.html  <- do not misspell this

注意:此文件的位置并不重要。您可以将其放入您的应用程序中,并且仍然可以使用。只要它的位置可以被django发现。更重要的是,HTML文件的名称必须与django提供的原始HTML文件名相同。

  1. 将此模板路径添加到您的settings.py中

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'templates')], # <- add this line
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                ],
            },
        },
    ]
  2. 确定名称和要覆盖的块。这是通过查看django的admin / templates目录来完成的。我正在使用virtualenv,因此对我来说,路径在这里:

    ~/.virtualenvs/edge/lib/python2.7/site-packages/django/contrib/admin/templates/admin

在此示例中,我要修改添加新用户表单。该视图负责的模板是change_form.html。打开change_form.html并找到要扩展的{%block%}。

  1. 您的change_form.html中,编写如下内容:

    {% extends "admin/change_form.html" %}
    {% block field_sets %}
         {# your modification here #}
    {% endblock %}
  2. 加载您的页面,您应该看到更改

As for Django 1.8 being the current release, there is no need to symlink, copy the admin/templates to your project folder, or install middlewares as suggested by the answers above. Here is what to do:

  1. create the following tree structure(recommended by the official documentation)

    your_project
         |-- your_project/
         |-- myapp/
         |-- templates/
              |-- admin/
                  |-- myapp/
                      |-- change_form.html  <- do not misspell this
    

Note: The location of this file is not important. You can put it inside your app and it will still work. As long as its location can be discovered by django. What’s more important is the name of the HTML file has to be the same as the original HTML file name provided by django.

  1. Add this template path to your settings.py:

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'templates')], # <- add this line
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                ],
            },
        },
    ]
    
  2. Identify the name and block you want to override. This is done by looking into django’s admin/templates directory. I am using virtualenv, so for me, the path is here:

    ~/.virtualenvs/edge/lib/python2.7/site-packages/django/contrib/admin/templates/admin
    

In this example, I want to modify the add new user form. The template responsiblve for this view is change_form.html. Open up the change_form.html and find the {% block %} that you want to extend.

  1. In your change_form.html, write somethings like this:

    {% extends "admin/change_form.html" %}
    {% block field_sets %}
         {# your modification here #}
    {% endblock %}
    
  2. Load up your page and you should see the changes


回答 2

如果您需要覆盖admin/index.html,则可以设置的index_template参数AdminSite

例如

# urls.py
...
from django.contrib import admin

admin.site.index_template = 'admin/my_custom_index.html'
admin.autodiscover()

并将您的模板放在 <appname>/templates/admin/my_custom_index.html

if you need to overwrite the admin/index.html, you can set the index_template parameter of the AdminSite.

e.g.

# urls.py
...
from django.contrib import admin

admin.site.index_template = 'admin/my_custom_index.html'
admin.autodiscover()

and place your template in <appname>/templates/admin/my_custom_index.html


回答 3

django至少使用1.5,您可以定义要用于特定模板的模板modeladmin

参见https://docs.djangoproject.com/en/1.5/ref/contrib/admin/#custom-template-options

你可以做类似的事情

class Myadmin(admin.ModelAdmin):
    change_form_template = 'change_form.htm'

通过change_form.html扩展为简单的html模板admin/change_form.html(如果您想从头开始,则不这样做)

With django 1.5 (at least) you can define the template you want to use for a particular modeladmin

see https://docs.djangoproject.com/en/1.5/ref/contrib/admin/#custom-template-options

You can do something like

class Myadmin(admin.ModelAdmin):
    change_form_template = 'change_form.htm'

With change_form.html being a simple html template extending admin/change_form.html (or not if you want to do it from scratch)


回答 4

Chengs的答案是正确的,根据管理文档,并非所有的管理模板都可以通过这种方式覆盖:https ://docs.djangoproject.com/en/1.9/ref/contrib/admin/#overriding-admin-templates

可以针对每个应用或模型覆盖的模板

并非每个应用程序或每个模型都可以覆盖contrib / admin / templates / admin中的每个模板。以下可以:

app_index.html
change_form.html
change_list.html
delete_confirmation.html
object_history.html

对于无法以这种方式覆盖的模板,您仍然可以在整个项目中覆盖它们。只需新版本放在您的template / admin目录中即可。这对于创建自定义404和500页特别有用

我必须覆盖admin的login.html,因此必须将覆盖的模板放在此文件夹结构中:

your_project
 |-- your_project/
 |-- myapp/
 |-- templates/
      |-- admin/
          |-- login.html  <- do not misspell this

(没有admin中的myapp子文件夹)我没有足够的声誉来评论Cheng的帖子,这就是为什么我不得不将其编写为新答案。

Chengs’s answer is correct, howewer according to the admin docs not every admin template can be overwritten this way: https://docs.djangoproject.com/en/1.9/ref/contrib/admin/#overriding-admin-templates

Templates which may be overridden per app or model

Not every template in contrib/admin/templates/admin may be overridden per app or per model. The following can:

app_index.html
change_form.html
change_list.html
delete_confirmation.html
object_history.html

For those templates that cannot be overridden in this way, you may still override them for your entire project. Just place the new version in your templates/admin directory. This is particularly useful to create custom 404 and 500 pages

I had to overwrite the login.html of the admin and therefore had to put the overwritten template in this folder structure:

your_project
 |-- your_project/
 |-- myapp/
 |-- templates/
      |-- admin/
          |-- login.html  <- do not misspell this

(without the myapp subfolder in the admin) I do not have enough repution for commenting on Cheng’s post this is why I had to write this as new answer.


回答 5

最好的方法是将Django管理模板放入您的项目中。因此,您的模板将在其中,templates/admin而库存的Django管理模板将在其中template/django_admin。然后,您可以执行以下操作:

templates / admin / change_form.html

{% extends 'django_admin/change_form.html' %}

Your stuff here

如果您担心要使库存模板保持最新状态,则可以在svn外部组件或类似工具中包含它们。

The best way to do it is to put the Django admin templates inside your project. So your templates would be in templates/admin while the stock Django admin templates would be in say template/django_admin. Then, you can do something like the following:

templates/admin/change_form.html

{% extends 'django_admin/change_form.html' %}

Your stuff here

If you’re worried about keeping the stock templates up to date, you can include them with svn externals or similar.


回答 6

我找不到官方的Django文档中的单个答案或某个部分,而该部分没有覆盖/扩展默认管理模板所需的全部信息,因此,我正在将此答案作为完整指南编写,希望对您有所帮助为将来的其他人。

假设标准的Django项目结构为:

mysite-container/         # project container directory
    manage.py
    mysite/               # project package
        __init__.py
        admin.py
        apps.py
        settings.py
        urls.py
        wsgi.py
    app1/
    app2/
    ...
    static/
    templates/

这是您需要做的:

  1. 在中mysite/admin.py,创建以下子类AdminSite

    from django.contrib.admin import AdminSite
    
    
    class CustomAdminSite(AdminSite):
        # set values for `site_header`, `site_title`, `index_title` etc.
        site_header = 'Custom Admin Site'
        ...
    
        # extend / override admin views, such as `index()`
        def index(self, request, extra_context=None):
            extra_context = extra_context or {}
    
            # do whatever you want to do and save the values in `extra_context`
            extra_context['world'] = 'Earth'
    
            return super(CustomAdminSite, self).index(request, extra_context)
    
    
    custom_admin_site = CustomAdminSite()

    确保导入custom_admin_siteadmin.py你的应用程序并注册它的模型在您的自定义管理网站显示它们(如果你愿意的话)。

  2. 在中mysite/apps.py,创建的子类,AdminConfig并从上一步中将其设置default_siteadmin.CustomAdminSite

    from django.contrib.admin.apps import AdminConfig
    
    
    class CustomAdminConfig(AdminConfig):
        default_site = 'admin.CustomAdminSite'
  3. mysite/settings.py,替换django.admin.siteINSTALLED_APPSapps.CustomAdminConfig(来自之前的步骤自定义管理应用程序配置)。

  4. 在中mysite/urls.pyadmin.site.urls从管理URL 替换为custom_admin_site.urls

    from .admin import custom_admin_site
    
    
    urlpatterns = [
        ...
        path('admin/', custom_admin_site.urls),
        # for Django 1.x versions: url(r'^admin/', include(custom_admin_site.urls)),
        ...
    ]
  5. templates目录中创建要修改的模板,并保持docs中指定的默认Django管理模板目录结构。例如,如果要修改admin/index.html,请创建文件templates/admin/index.html

    所有现有模板都可以通过这种方式进行修改,并且它们的名称和结构可以在Django的源代码中找到

  6. 现在,您可以通过从头开始编写模板来覆盖模板,也可以对其进行扩展,然后覆盖/扩展特定的块。

    例如,如果您想将所有内容保持原样但要覆盖该content块(在索引页面上列出了您注册的应用及其模型),则将以下内容添加到中templates/admin/index.html

    {% extends 'admin/index.html' %}
    
    {% block content %}
      <h1>
        Hello, {{ world }}!
      </h1>
    {% endblock %}

    要保留块的原始内容,请{{ block.super }}在希望显示原始内容的任何位置添加:

    {% extends 'admin/index.html' %}
    
    {% block content %}
      <h1>
        Hello, {{ world }}!
      </h1>
      {{ block.super }}
    {% endblock %}

    您还可以通过修改extrastyleextrahead块来添加自定义样式和脚本。

I couldn’t find a single answer or a section in the official Django docs that had all the information I needed to override/extend the default admin templates, so I’m writing this answer as a complete guide, hoping that it would be helpful for others in the future.

Assuming the standard Django project structure:

mysite-container/         # project container directory
    manage.py
    mysite/               # project package
        __init__.py
        admin.py
        apps.py
        settings.py
        urls.py
        wsgi.py
    app1/
    app2/
    ...
    static/
    templates/

Here’s what you need to do:

  1. In mysite/admin.py, create a sub-class of AdminSite:

    from django.contrib.admin import AdminSite
    
    
    class CustomAdminSite(AdminSite):
        # set values for `site_header`, `site_title`, `index_title` etc.
        site_header = 'Custom Admin Site'
        ...
    
        # extend / override admin views, such as `index()`
        def index(self, request, extra_context=None):
            extra_context = extra_context or {}
    
            # do whatever you want to do and save the values in `extra_context`
            extra_context['world'] = 'Earth'
    
            return super(CustomAdminSite, self).index(request, extra_context)
    
    
    custom_admin_site = CustomAdminSite()
    

    Make sure to import custom_admin_site in the admin.py of your apps and register your models on it to display them on your customized admin site (if you want to).

  2. In mysite/apps.py, create a sub-class of AdminConfig and set default_site to admin.CustomAdminSite from the previous step:

    from django.contrib.admin.apps import AdminConfig
    
    
    class CustomAdminConfig(AdminConfig):
        default_site = 'admin.CustomAdminSite'
    
  3. In mysite/settings.py, replace django.admin.site in INSTALLED_APPS with apps.CustomAdminConfig (your custom admin app config from the previous step).

  4. In mysite/urls.py, replace admin.site.urls from the admin URL to custom_admin_site.urls

    from .admin import custom_admin_site
    
    
    urlpatterns = [
        ...
        path('admin/', custom_admin_site.urls),
        # for Django 1.x versions: url(r'^admin/', include(custom_admin_site.urls)),
        ...
    ]
    
  5. Create the template you want to modify in your templates directory, maintaining the default Django admin templates directory structure as specified in the docs. For example, if you were modifying admin/index.html, create the file templates/admin/index.html.

    All of the existing templates can be modified this way, and their names and structures can be found in Django’s source code.

  6. Now you can either override the template by writing it from scratch or extend it and then override/extend specific blocks.

    For example, if you wanted to keep everything as-is but wanted to override the content block (which on the index page lists the apps and their models that you registered), add the following to templates/admin/index.html:

    {% extends 'admin/index.html' %}
    
    {% block content %}
      <h1>
        Hello, {{ world }}!
      </h1>
    {% endblock %}
    

    To preserve the original contents of a block, add {{ block.super }} wherever you want the original contents to be displayed:

    {% extends 'admin/index.html' %}
    
    {% block content %}
      <h1>
        Hello, {{ world }}!
      </h1>
      {{ block.super }}
    {% endblock %}
    

    You can also add custom styles and scripts by modifying the extrastyle and extrahead blocks.


回答 7

我同意克里斯·普拉特(Chris Pratt)的观点。但我认为最好将符号链接创建到原始Django文件夹,并将其放置在管理模板中:

ln -s /usr/local/lib/python2.7/dist-packages/django/contrib/admin/templates/admin/ templates/django_admin

如您所见,它取决于python版本和Django的安装文件夹。因此,将来或在生产服务器上,您可能需要更改路径。

I agree with Chris Pratt. But I think it’s better to create the symlink to original Django folder where the admin templates place in:

ln -s /usr/local/lib/python2.7/dist-packages/django/contrib/admin/templates/admin/ templates/django_admin

and as you can see it depends on python version and the folder where the Django installed. So in future or on a production server you might need to change the path.


回答 8

这个站点有一个与我的Django 1.7配置一起使用的简单解决方案。

首先:在项目的template /目录中,创建一个名为admin_src的符号链接到已安装的Django模板。对我来说,使用virtualenv在Dreamhost上,我的“源” Django管理模板位于:

~/virtualenvs/mydomain/lib/python2.7/site-packages/django/contrib/admin/templates/admin

第二:在模板/中创建管理目录

所以我项目的template /目录现在看起来像这样:

/templates/
   admin
   admin_src -> [to django source]
   base.html
   index.html
   sitemap.xml
   etc...

第三:在新的template / admin /目录中,创建具有以下内容的base.html文件:

{% extends "admin_src/base.html" %}

{% block extrahead %}
<link rel='shortcut icon' href='{{ STATIC_URL }}img/favicon-admin.ico' />
{% endblock %}

第四:将您的admin favicon-admin.ico添加到您的静态根img文件夹中。

做完了 简单。

This site had a simple solution that worked with my Django 1.7 configuration.

FIRST: Make a symlink named admin_src in your project’s template/ directory to your installed Django templates. For me on Dreamhost using a virtualenv, my “source” Django admin templates were in:

~/virtualenvs/mydomain/lib/python2.7/site-packages/django/contrib/admin/templates/admin

SECOND: Create an admin directory in templates/

So my project’s template/ directory now looked like this:

/templates/
   admin
   admin_src -> [to django source]
   base.html
   index.html
   sitemap.xml
   etc...

THIRD: In your new template/admin/ directory create a base.html file with this content:

{% extends "admin_src/base.html" %}

{% block extrahead %}
<link rel='shortcut icon' href='{{ STATIC_URL }}img/favicon-admin.ico' />
{% endblock %}

FOURTH: Add your admin favicon-admin.ico into your static root img folder.

Done. Easy.


回答 9

对于应用程序索引,将此行添加到某个常见的py文件(例如url.py)中

admin.site.index_template = 'admin/custom_index.html'

对于应用程序模块索引:将此行添加到admin.py

admin.AdminSite.app_index_template = "servers/servers-home.html"

对于更改列表:将此行添加到admin类:

change_list_template = "servers/servers_changelist.html"

对于应用程序模块表单模板:将此行添加到您的管理类中

change_form_template = "servers/server_changeform.html"

等等,并在同一管理员的模块类中查找其他

for app index add this line to somewhere common py file like url.py

admin.site.index_template = 'admin/custom_index.html'

for app module index : add this line to admin.py

admin.AdminSite.app_index_template = "servers/servers-home.html"

for change list : add this line to admin class:

change_list_template = "servers/servers_changelist.html"

for app module form template : add this line to your admin class

change_form_template = "servers/server_changeform.html"

etc. and find other in same admin’s module classes


回答 10

您可以使用django-overextends,它为Django提供了循环模板继承。

它来自Mezzanine CMS,Stephen从中将其提取到独立的Django扩展中。

您可以在夹层文档中的“覆盖与扩展模板”(http:/mezzanine.jupo.org/docs/content-architecture.html#overriding-vs-extending-templates)中找到更多信息。

有关更深入的信息,请参见Stephens Blog“ Django的循环模板继承”(http:/blog.jupo.org/2012/05/17/circular-template-inheritance-for-django)。

在Google网上论坛中,讨论(https://groups.google.com/forum/#!topic/mezzanine-users/sUydcf_IZkQ)开始了该功能的开发。

注意:

我没有添加两个以上链接的声誉。但是我认为这些链接提供了有趣的背景信息。因此,我在“ http(s):”之后留了一个斜线。也许信誉较高的人可以修复链接并删除此注释。

You can use django-overextends, which provides circular template inheritance for Django.

It comes from the Mezzanine CMS, from where Stephen extracted it into a standalone Django extension.

More infos you find in “Overriding vs Extending Templates” (http:/mezzanine.jupo.org/docs/content-architecture.html#overriding-vs-extending-templates) inside the Mezzanine docs.

For deeper insides look at Stephens Blog “Circular Template Inheritance for Django” (http:/blog.jupo.org/2012/05/17/circular-template-inheritance-for-django).

And in Google Groups the discussion (https:/groups.google.com/forum/#!topic/mezzanine-users/sUydcf_IZkQ) which started the development of this feature.

Note:

I don’t have the reputation to add more than 2 links. But I think the links provide interesting background information. So I just left out a slash after “http(s):”. Maybe someone with better reputation can repair the links and remove this note.


如何在Django中过滤用于计数注释的对象?

问题:如何在Django中过滤用于计数注释的对象?

考虑简单的Django模型EventParticipant

class Event(models.Model):
    title = models.CharField(max_length=100)

class Participant(models.Model):
    event = models.ForeignKey(Event, db_index=True)
    is_paid = models.BooleanField(default=False, db_index=True)

使用参与者总数来注释事件查询很容易:

events = Event.objects.all().annotate(participants=models.Count('participant'))

如何用筛选的参与者计数进行注释is_paid=True

我需要查询所有事件,而与参与者人数无关,例如,我不需要按带注释的结果进行过滤。如果有0参与者,那没关系,我只需要带有0注释的值即可。

文档中的示例在这里不起作用,因为它从查询中排除了对象,而不是使用注释了对象0

更新。Django 1.8具有新的条件表达式功能,因此我们现在可以这样做:

events = Event.objects.all().annotate(paid_participants=models.Sum(
    models.Case(
        models.When(participant__is_paid=True, then=1),
        default=0,
        output_field=models.IntegerField()
    )))

更新 2。Django 2.0具有新的条件聚合功能,请参阅下面的可接受答案

Consider simple Django models Event and Participant:

class Event(models.Model):
    title = models.CharField(max_length=100)

class Participant(models.Model):
    event = models.ForeignKey(Event, db_index=True)
    is_paid = models.BooleanField(default=False, db_index=True)

It’s easy to annotate events query with total number of participants:

events = Event.objects.all().annotate(participants=models.Count('participant'))

How to annotate with count of participants filtered by is_paid=True?

I need to query all events regardless of number of participants, e.g. I don’t need to filter by annotated result. If there are 0 participants, that’s ok, I just need 0 in annotated value.

The example from documentation doesn’t work here, because it excludes objects from query instead of annotating them with 0.

Update. Django 1.8 has new conditional expressions feature, so now we can do like this:

events = Event.objects.all().annotate(paid_participants=models.Sum(
    models.Case(
        models.When(participant__is_paid=True, then=1),
        default=0,
        output_field=models.IntegerField()
    )))

Update 2. Django 2.0 has new Conditional aggregation feature, see the accepted answer below.


回答 0

Django 2.0中的条件聚合可让您进一步减少过去的流量。这也将使用Postgres的filter逻辑,该逻辑比求和的情况要快一些(我见过像20-30%这样的数字被打乱)。

无论如何,就您的情况而言,我们正在研究以下简单内容:

from django.db.models import Q, Count
events = Event.objects.annotate(
    paid_participants=Count('participants', filter=Q(participants__is_paid=True))
)

在文档中有一个单独的部分,关于对注释进行过滤。它和条件聚合是一样的东西,但是更像上面的例子。无论哪种方式,这都比我以前做的粗糙子查询要健康得多。

Conditional aggregation in Django 2.0 allows you to further reduce the amount of faff this has been in the past. This will also use Postgres’ filter logic, which is somewhat faster than a sum-case (I’ve seen numbers like 20-30% bandied around).

Anyway, in your case, we’re looking at something as simple as:

from django.db.models import Q, Count
events = Event.objects.annotate(
    paid_participants=Count('participants', filter=Q(participants__is_paid=True))
)

There’s a separate section in the docs about filtering on annotations. It’s the same stuff as conditional aggregation but more like my example above. Either which way, this is a lot healthier than the gnarly subqueries I was doing before.


回答 1

刚刚发现Django 1.8具有新的条件表达式功能,因此现在我们可以这样做:

events = Event.objects.all().annotate(paid_participants=models.Sum(
    models.Case(
        models.When(participant__is_paid=True, then=1),
        default=0, output_field=models.IntegerField()
    )))

Just discovered that Django 1.8 has new conditional expressions feature, so now we can do like this:

events = Event.objects.all().annotate(paid_participants=models.Sum(
    models.Case(
        models.When(participant__is_paid=True, then=1),
        default=0, output_field=models.IntegerField()
    )))

回答 2

更新

Django 1.11现在通过subquery-expressions支持了我提到的子查询方法。

Event.objects.annotate(
    num_paid_participants=Subquery(
        Participant.objects.filter(
            is_paid=True,
            event=OuterRef('pk')
        ).values('event')
        .annotate(cnt=Count('pk'))
        .values('cnt'),
        output_field=models.IntegerField()
    )
)

我更喜欢这种方法而不是聚合(sum + case),因为它应该更快,更容易被优化(使用适当的索引)

对于较旧的版本,可以使用 .extra

Event.objects.extra(select={'num_paid_participants': "\
    SELECT COUNT(*) \
    FROM `myapp_participant` \
    WHERE `myapp_participant`.`is_paid` = 1 AND \
            `myapp_participant`.`event_id` = `myapp_event`.`id`"
})

UPDATE

The sub-query approach which I mention is now supported in Django 1.11 via subquery-expressions.

Event.objects.annotate(
    num_paid_participants=Subquery(
        Participant.objects.filter(
            is_paid=True,
            event=OuterRef('pk')
        ).values('event')
        .annotate(cnt=Count('pk'))
        .values('cnt'),
        output_field=models.IntegerField()
    )
)

I prefer this over aggregation (sum+case), because it should be faster and easier to be optimized (with proper indexing).

For older version, the same can be achieved using .extra

Event.objects.extra(select={'num_paid_participants': "\
    SELECT COUNT(*) \
    FROM `myapp_participant` \
    WHERE `myapp_participant`.`is_paid` = 1 AND \
            `myapp_participant`.`event_id` = `myapp_event`.`id`"
})

回答 3

我建议改用.values您的Participantqueryset 方法。

简而言之,您想要做的是:

Participant.objects\
    .filter(is_paid=True)\
    .values('event')\
    .distinct()\
    .annotate(models.Count('id'))

完整的示例如下:

  1. 创建2 Event秒:

    event1 = Event.objects.create(title='event1')
    event2 = Event.objects.create(title='event2')
    
  2. Participants 添加到他们:

    part1l = [Participant.objects.create(event=event1, is_paid=((_%2) == 0))\
              for _ in range(10)]
    part2l = [Participant.objects.create(event=event2, is_paid=((_%2) == 0))\
              for _ in range(50)]
    
  3. 将所有Participants按其event字段分组:

    Participant.objects.values('event')
    > <QuerySet [{'event': 1}, {'event': 1}, {'event': 1}, {'event': 1}, {'event': 1}, {'event': 1}, {'event': 1}, {'event': 1}, {'event': 1}, {'event': 1}, {'event': 2}, {'event': 2}, {'event': 2}, {'event': 2}, {'event': 2}, {'event': 2}, {'event': 2}, {'event': 2}, {'event': 2}, {'event': 2}, '...(remaining elements truncated)...']>
    

    这里需要与众不同:

    Participant.objects.values('event').distinct()
    > <QuerySet [{'event': 1}, {'event': 2}]>
    

    什么.values.distinct正在做的事情是,他们正在创造的两个水桶Participant用元的分组小号event。请注意,这些存储桶包含Participant

  4. 然后,您可以注释这些存储桶,因为它们包含原始集Participant。在这里,我们要计算的数量Participant,只需通过计算id这些存储区中的元素的s即可(因为它们是Participant):

    Participant.objects\
        .values('event')\
        .distinct()\
        .annotate(models.Count('id'))
    > <QuerySet [{'event': 1, 'id__count': 10}, {'event': 2, 'id__count': 50}]>
    
  5. 最后,您只Participant需要一个is_paidbeing True,您可以只在前一个表达式的前面添加一个过滤器,这将产生上面显示的表达式:

    Participant.objects\
        .filter(is_paid=True)\
        .values('event')\
        .distinct()\
        .annotate(models.Count('id'))
    > <QuerySet [{'event': 1, 'id__count': 5}, {'event': 2, 'id__count': 25}]>
    

唯一的缺点是Event您只能id从上面的方法中获取,因此您必须检索之后的内容。

I would suggest to use the .values method of your Participant queryset instead.

For short, what you want to do is given by:

Participant.objects\
    .filter(is_paid=True)\
    .values('event')\
    .distinct()\
    .annotate(models.Count('id'))

A complete example is as follow:

  1. Create 2 Events:

    event1 = Event.objects.create(title='event1')
    event2 = Event.objects.create(title='event2')
    
  2. Add Participants to them:

    part1l = [Participant.objects.create(event=event1, is_paid=((_%2) == 0))\
              for _ in range(10)]
    part2l = [Participant.objects.create(event=event2, is_paid=((_%2) == 0))\
              for _ in range(50)]
    
  3. Group all Participants by their event field:

    Participant.objects.values('event')
    > <QuerySet [{'event': 1}, {'event': 1}, {'event': 1}, {'event': 1}, {'event': 1}, {'event': 1}, {'event': 1}, {'event': 1}, {'event': 1}, {'event': 1}, {'event': 2}, {'event': 2}, {'event': 2}, {'event': 2}, {'event': 2}, {'event': 2}, {'event': 2}, {'event': 2}, {'event': 2}, {'event': 2}, '...(remaining elements truncated)...']>
    

    Here distinct is needed:

    Participant.objects.values('event').distinct()
    > <QuerySet [{'event': 1}, {'event': 2}]>
    

    What .values and .distinct are doing here is that they are creating two buckets of Participants grouped by their element event. Note that those buckets contain Participant.

  4. You can then annotate those buckets as they contain the set of original Participant. Here we want to count the number of Participant, this is simply done by counting the ids of the elements in those buckets (since those are Participant):

    Participant.objects\
        .values('event')\
        .distinct()\
        .annotate(models.Count('id'))
    > <QuerySet [{'event': 1, 'id__count': 10}, {'event': 2, 'id__count': 50}]>
    
  5. Finally you want only Participant with a is_paid being True, you may just add a filter in front of the previous expression, and this yield the expression shown above:

    Participant.objects\
        .filter(is_paid=True)\
        .values('event')\
        .distinct()\
        .annotate(models.Count('id'))
    > <QuerySet [{'event': 1, 'id__count': 5}, {'event': 2, 'id__count': 25}]>
    

The only drawback is that you have to retrieve the Event afterwards as you only have the id from the method above.


回答 4

我正在寻找什么结果:

  • 将任务添加到报告中的人员(受让人)。-唯一身份人员总数
  • 将任务添加到报告中但仅针对计费性大于0的任务的人员。

通常,我将不得不使用两个不同的查询:

Task.objects.filter(billable_efforts__gt=0)
Task.objects.all()

但我想在一个查询中两者。因此:

Task.objects.values('report__title').annotate(withMoreThanZero=Count('assignee', distinct=True, filter=Q(billable_efforts__gt=0))).annotate(totalUniqueAssignee=Count('assignee', distinct=True))

结果:

<QuerySet [{'report__title': 'TestReport', 'withMoreThanZero': 37, 'totalUniqueAssignee': 50}, {'report__title': 'Utilization_Report_April_2019', 'withMoreThanZero': 37, 'totalUniqueAssignee': 50}]>

What result I am looking for:

  • People (assignee) who have tasks added to a report. – Total Unique count of People
  • People who have tasks added to a report but, for task whose billability is more than 0 only.

In general, I would have to use two different queries:

Task.objects.filter(billable_efforts__gt=0)
Task.objects.all()

But I want both in one query. Hence:

Task.objects.values('report__title').annotate(withMoreThanZero=Count('assignee', distinct=True, filter=Q(billable_efforts__gt=0))).annotate(totalUniqueAssignee=Count('assignee', distinct=True))

Result:

<QuerySet [{'report__title': 'TestReport', 'withMoreThanZero': 37, 'totalUniqueAssignee': 50}, {'report__title': 'Utilization_Report_April_2019', 'withMoreThanZero': 37, 'totalUniqueAssignee': 50}]>

在django-rest-framework中禁用ViewSet中的方法

问题:在django-rest-framework中禁用ViewSet中的方法

ViewSets 具有自动列出,检索,创建,更新,删除,…的方法

我想禁用其中一些,我想出的解决方案可能不是一个好方法,因为OPTIONS仍然指出了允许的范围。

关于如何正确执行此操作的任何想法吗?

class SampleViewSet(viewsets.ModelViewSet):
    queryset = api_models.Sample.objects.all()
    serializer_class = api_serializers.SampleSerializer

    def list(self, request):
        return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)
    def create(self, request):
        return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)

ViewSets have automatic methods to list, retrieve, create, update, delete, …

I would like to disable some of those, and the solution I came up with is probably not a good one, since OPTIONS still states those as allowed.

Any idea on how to do this the right way?

class SampleViewSet(viewsets.ModelViewSet):
    queryset = api_models.Sample.objects.all()
    serializer_class = api_serializers.SampleSerializer

    def list(self, request):
        return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)
    def create(self, request):
        return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)

回答 0

的定义ModelViewSet是:

class ModelViewSet(mixins.CreateModelMixin, 
                   mixins.RetrieveModelMixin, 
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                   mixins.ListModelMixin,
                   GenericViewSet)

因此,除了扩展之外ModelViewSet,为什么不随便使用您需要的东西呢?因此,例如:

from rest_framework import viewsets, mixins

class SampleViewSet(mixins.RetrieveModelMixin,
                    mixins.UpdateModelMixin,
                    mixins.DestroyModelMixin,
                    viewsets.GenericViewSet):
    ...

使用这种方法,路由器应该只为所包含的方法生成路由。

参考

模型视图集

The definition of ModelViewSet is:

class ModelViewSet(mixins.CreateModelMixin, 
                   mixins.RetrieveModelMixin, 
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                   mixins.ListModelMixin,
                   GenericViewSet)

So rather than extending ModelViewSet, why not just use whatever you need? So for example:

from rest_framework import viewsets, mixins

class SampleViewSet(mixins.RetrieveModelMixin,
                    mixins.UpdateModelMixin,
                    mixins.DestroyModelMixin,
                    viewsets.GenericViewSet):
    ...

With this approach, the router should only generate routes for the included methods.

Reference:

ModelViewSet


回答 1

您可以继续使用viewsets.ModelViewSethttp_method_names在ViewSet上进行定义。

class SampleViewSet(viewsets.ModelViewSet):
    queryset = api_models.Sample.objects.all()
    serializer_class = api_serializers.SampleSerializer
    http_method_names = ['get', 'post', 'head']

一旦你加入http_method_names,你将无法做到putpatch了。

如果您想要put但不想要patch,您可以保留http_method_names = ['get', 'post', 'head', 'put']

在内部,DRF视图从Django CBV扩展。Django CBV具有一个名为http_method_names的属性。因此,您也可以在DRF视图中使用http_method_names。

[Shameless Plug]:如果此答案有用,您将喜欢我在DRF上的系列文章,网址https://www.agiliq.com/blog/2019/04/drf-polls/

You could keep using viewsets.ModelViewSet and define http_method_names on your ViewSet.

Example

class SampleViewSet(viewsets.ModelViewSet):
    queryset = api_models.Sample.objects.all()
    serializer_class = api_serializers.SampleSerializer
    http_method_names = ['get', 'post', 'head']

Once you add http_method_names, you will not be able to do put and patch anymore.

If you want put but don’t want patch, you can keep http_method_names = ['get', 'post', 'head', 'put']

Internally, DRF Views extend from Django CBV. Django CBV has an attribute called http_method_names. So you can use http_method_names with DRF views too.

[Shameless Plug]: If this answer was helpful, you will like my series of posts on DRF at https://www.agiliq.com/blog/2019/04/drf-polls/.


回答 2

尽管这篇文章已经有一段时间了,但我突然发现实际上它们是禁用这些功能的一种方法,您可以直接在views.py中对其进行编辑。

资料来源:https : //www.django-rest-framework.org/api-guide/viewsets/#viewset-actions

from rest_framework import viewsets, status
from rest_framework.response import Response

class NameWhateverYouWantViewSet(viewsets.ModelViewSet):

    def create(self, request):
        response = {'message': 'Create function is not offered in this path.'}
        return Response(response, status=status.HTTP_403_FORBIDDEN)

    def update(self, request, pk=None):
        response = {'message': 'Update function is not offered in this path.'}
        return Response(response, status=status.HTTP_403_FORBIDDEN)

    def partial_update(self, request, pk=None):
        response = {'message': 'Update function is not offered in this path.'}
        return Response(response, status=status.HTTP_403_FORBIDDEN)

    def destroy(self, request, pk=None):
        response = {'message': 'Delete function is not offered in this path.'}
        return Response(response, status=status.HTTP_403_FORBIDDEN)

Although it’s been a while for this post, I suddenly found out that actually there is a way to disable those functions, you can edit it in the views.py directly.

Source: https://www.django-rest-framework.org/api-guide/viewsets/#viewset-actions

from rest_framework import viewsets, status
from rest_framework.response import Response

class NameThisClassWhateverYouWantViewSet(viewsets.ModelViewSet):

    def create(self, request):
        response = {'message': 'Create function is not offered in this path.'}
        return Response(response, status=status.HTTP_403_FORBIDDEN)

    def update(self, request, pk=None):
        response = {'message': 'Update function is not offered in this path.'}
        return Response(response, status=status.HTTP_403_FORBIDDEN)

    def partial_update(self, request, pk=None):
        response = {'message': 'Update function is not offered in this path.'}
        return Response(response, status=status.HTTP_403_FORBIDDEN)

    def destroy(self, request, pk=None):
        response = {'message': 'Delete function is not offered in this path.'}
        return Response(response, status=status.HTTP_403_FORBIDDEN)

回答 3

如果尝试从DRF视图集中禁用PUT方法,则可以创建一个自定义路由器:

from rest_framework.routers import DefaultRouter

class NoPutRouter(DefaultRouter):
    """
    Router class that disables the PUT method.
    """
    def get_method_map(self, viewset, method_map):

        bound_methods = super().get_method_map(viewset, method_map)

        if 'put' in bound_methods.keys():
            del bound_methods['put']

        return bound_methods

通过在路由器上禁用该方法,您的api模式文档将是正确的。

If you are trying to disable the PUT method from a DRF viewset, you can create a custom router:

from rest_framework.routers import DefaultRouter

class NoPutRouter(DefaultRouter):
    """
    Router class that disables the PUT method.
    """
    def get_method_map(self, viewset, method_map):

        bound_methods = super().get_method_map(viewset, method_map)

        if 'put' in bound_methods.keys():
            del bound_methods['put']

        return bound_methods

By disabling the method at the router, your api schema documentation will be correct.


回答 4

如何在DRF中为ViewSet禁用“删除”方法

class YourViewSet(viewsets.ModelViewSet):
    def _allowed_methods(self):
        return [m for m in super(YourViewSet, self)._allowed_methods() if m not in ['DELETE']]

PS这比显式指定所有必需的方法更可靠,因此很少有机会忘记一些重要的方法OPTIONS,HEAD等

默认情况下,DPS的PPS具有 http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

How to disable “DELETE” method for ViewSet in DRF

class YourViewSet(viewsets.ModelViewSet):
    def _allowed_methods(self):
        return [m for m in super(YourViewSet, self)._allowed_methods() if m not in ['DELETE']]

P.S. This is more reliable than explicitly specifying all the necessary methods, so there is less chance of forgetting some of important methods OPTIONS, HEAD, etc

P.P.S. by default DRF has http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']


回答 5

在Django Rest Framework 3.xx中,您可以ModelViewSet通过将字典传递给as_view方法来简单地启用要启用的每个方法。在此字典中,键必须包含请求类型(GET,POST,DELETE等),并且值必须包含相应的方法名称(列表,检索,更新等)。例如,假设您要Sample创建或读取模型,但不希望对其进行修改。因此,这意味着你想listretrievecreate方法,是使(和你希望别人被禁用。)

您需要做的就是添加如下路径urlpatterns

path('sample/', SampleViewSet.as_view({
    'get': 'list',
    'post': 'create'
})),
path('sample/<pk>/', SampleViewSet.as_view({  # for get sample by id.
    'get': 'retrieve'
}))

如您所见,上述路由设置中没有no deleteputrequest,因此例如,如果您将put请求发送到url,它将以405响应您Method Not Allowed

{
    "detail": "Method \"PUT\" not allowed."
}

In Django Rest Framework 3.x.x you can simply enable every each method you want to be enabled for ModelViewSet, by passing a dictionary to as_view method. In this dictionary, the key must contain request type (GET, POST, DELETE, etc) and the value must contain corresponding method name (list, retrieve, update, etc). For example let say you want Sample model to be created or read but you don’t want it to be modified. So it means you want list, retrieve and create method to be enable (and you want others to be disabled.)

All you need to do is to add paths to urlpatterns like these:

path('sample/', SampleViewSet.as_view({
    'get': 'list',
    'post': 'create'
})),
path('sample/<pk>/', SampleViewSet.as_view({  # for get sample by id.
    'get': 'retrieve'
}))

As you can see there’s no delete and put request in above routing settings, so for example if you send a put request to the url, it response you with 405 Method Not Allowed:

{
    "detail": "Method \"PUT\" not allowed."
}

回答 6

如果您打算禁用放置/发布/销毁方法,则可以使用

viewsets.ReadOnlyModelViewSet https://www.django-rest-framework.org/tutorial/6-viewsets-and-routers/#refactoring-to-use-viewsets

If you are planning to disable put/post/destroy methods, you can use

viewsets.ReadOnlyModelViewSet https://www.django-rest-framework.org/tutorial/6-viewsets-and-routers/#refactoring-to-use-viewsets


如何将Django QuerySet转换为字典列表?

问题:如何将Django QuerySet转换为字典列表?

如何将Django QuerySet转换为字典列表?我没有找到答案,所以我想知道我是否缺少每个人都使用的某种通用帮助函数。

How can I convert a Django QuerySet into a list of dicts? I haven’t found an answer to this so I’m wondering if I’m missing some sort of common helper function that everyone uses.


回答 0

使用.values()方法:

>>> Blog.objects.values()
[{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}],
>>> Blog.objects.values('id', 'name')
[{'id': 1, 'name': 'Beatles Blog'}]

注意:结果是,QuerySet其行为基本上类似于列表,但实际上不是的实例list。使用list(Blog.objects.values(…))如果你真的需要的一个实例list

Use the .values() method:

>>> Blog.objects.values()
[{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}],
>>> Blog.objects.values('id', 'name')
[{'id': 1, 'name': 'Beatles Blog'}]

Note: the result is a QuerySet which mostly behaves like a list, but isn’t actually an instance of list. Use list(Blog.objects.values(…)) if you really need an instance of list.


回答 1

.values()方法将返回类型的结果,ValuesQuerySet这通常是大多数情况下所需的。

但是,如果您愿意,可以ValuesQuerySet使用Python列表理解功能将其转换为本地Python列表,如下例所示。

result = Blog.objects.values()             # return ValuesQuerySet object
list_result = [entry for entry in result]  # converts ValuesQuerySet into Python list
return list_result

我发现上面的帮助,如果你正在编写单元测试,并需要断言函数的预期收益值,实际的返回值匹配,在这种情况下,两个expected_resultactual_result必须是同一类型(例如字典)。

actual_result = some_function()
expected_result = {
    # dictionary content here ...
}
assert expected_result == actual_result

The .values() method will return you a result of type ValuesQuerySet which is typically what you need in most cases.

But if you wish, you could turn ValuesQuerySet into a native Python list using Python list comprehension as illustrated in the example below.

result = Blog.objects.values()             # return ValuesQuerySet object
list_result = [entry for entry in result]  # converts ValuesQuerySet into Python list
return list_result

I find the above helps if you are writing unit tests and need to assert that the expected return value of a function matches the actual return value, in which case both expected_result and actual_result must be of the same type (e.g. dictionary).

actual_result = some_function()
expected_result = {
    # dictionary content here ...
}
assert expected_result == actual_result

回答 2

如果出于某种原因(例如JSON序列化)而需要本机数据类型,这是我的快速“ n”处理方式:

data = [{'id': blog.pk, 'name': blog.name} for blog in blogs]

如您所见,在列表中构建字典并不是真正的DRY,所以如果有人知道更好的方法…

If you need native data types for some reason (e.g. JSON serialization) this is my quick ‘n’ dirty way to do it:

data = [{'id': blog.pk, 'name': blog.name} for blog in blogs]

As you can see building the dict inside the list is not really DRY so if somebody knows a better way …


回答 3

您没有完全定义字典的外观,但很可能是您所指的QuerySet.values()。从官方的django文档中

返回一个ValuesQuerySetQuerySet子类,该子类在用作可迭代对象(而不是模型实例对象)时返回字典。

这些词典中的每一个都代表一个对象,其键对应于模型对象的属性名称。

You do not exactly define what the dictionaries should look like, but most likely you are referring to QuerySet.values(). From the official django documentation:

Returns a ValuesQuerySet — a QuerySet subclass that returns dictionaries when used as an iterable, rather than model-instance objects.

Each of those dictionaries represents an object, with the keys corresponding to the attribute names of model objects.


回答 4

输入类型到列表

    job_reports = JobReport.objects.filter(job_id=job_id, status=1).values('id', 'name')

    json.dumps(list(job_reports))

Type Cast to List

    job_reports = JobReport.objects.filter(job_id=job_id, status=1).values('id', 'name')

    json.dumps(list(job_reports))

回答 5

您可以values()在查询所依据的Django模型字段中使用dict上的方法,然后可以通过索引值轻松访问每个字段。

这样称呼它-

myList = dictOfSomeData.values()
itemNumberThree = myList[2] #If there's a value in that index off course...

You can use the values() method on the dict you got from the Django model field you make the queries on and then you can easily access each field by a index value.

Call it like this –

myList = dictOfSomeData.values()
itemNumberThree = myList[2] #If there's a value in that index off course...

回答 6

你需要DjangoJSONEncoderlist使您Querysetjson,参考:Python的JSON序列化一个小数对象

import json
from django.core.serializers.json import DjangoJSONEncoder


blog = Blog.objects.all().values()
json.dumps(list(blog), cls=DjangoJSONEncoder)

You need DjangoJSONEncoder and list to make your Queryset to json, ref: Python JSON serialize a Decimal object

import json
from django.core.serializers.json import DjangoJSONEncoder


blog = Blog.objects.all().values()
json.dumps(list(blog), cls=DjangoJSONEncoder)

回答 7

简单地说list(yourQuerySet)

Simply put list(yourQuerySet).


回答 8

您可以使用model_to_dict定义一个函数,如下所示:

def queryset_to_dict(qs,fields=None, exclude=None):
    my_array=[]
    for x in qs:
        my_array.append(model_to_dict(x,fields=fields,exclude=exclude))
    return my_array

You could define a function using model_to_dict as follows:

def queryset_to_dict(qs,fields=None, exclude=None):
    my_array=[]
    for x in qs:
        my_array.append(model_to_dict(x,fields=fields,exclude=exclude))
    return my_array

CSV新行字符出现在未引用字段错误

问题:CSV新行字符出现在未引用字段错误

以下代码一直工作到今天,当我从Windows机器导入并出现此错误时:

在不带引号的字段中看到换行符-您是否需要在通用换行模式下打开文件?

import csv

class CSV:


    def __init__(self, file=None):
        self.file = file

    def read_file(self):
        data = []
        file_read = csv.reader(self.file)
        for row in file_read:
            data.append(row)
        return data

    def get_row_count(self):
        return len(self.read_file())

    def get_column_count(self):
        new_data = self.read_file()
        return len(new_data[0])

    def get_data(self, rows=1):
        data = self.read_file()

        return data[:rows]

如何解决此问题?

def upload_configurator(request, id=None):
    """
    A view that allows the user to configurator the uploaded CSV.
    """
    upload = Upload.objects.get(id=id)
    csvobject = CSV(upload.filepath)

    upload.num_records = csvobject.get_row_count()
    upload.num_columns = csvobject.get_column_count()
    upload.save()

    form = ConfiguratorForm()

    row_count = csvobject.get_row_count()
    colum_count = csvobject.get_column_count()
    first_row = csvobject.get_data(rows=1)
    first_two_rows = csvobject.get_data(rows=5)

the following code worked until today when I imported from a Windows machine and got this error:

new-line character seen in unquoted field – do you need to open the file in universal-newline mode?

import csv

class CSV:


    def __init__(self, file=None):
        self.file = file

    def read_file(self):
        data = []
        file_read = csv.reader(self.file)
        for row in file_read:
            data.append(row)
        return data

    def get_row_count(self):
        return len(self.read_file())

    def get_column_count(self):
        new_data = self.read_file()
        return len(new_data[0])

    def get_data(self, rows=1):
        data = self.read_file()

        return data[:rows]

How can I fix this issue?

def upload_configurator(request, id=None):
    """
    A view that allows the user to configurator the uploaded CSV.
    """
    upload = Upload.objects.get(id=id)
    csvobject = CSV(upload.filepath)

    upload.num_records = csvobject.get_row_count()
    upload.num_columns = csvobject.get_column_count()
    upload.save()

    form = ConfiguratorForm()

    row_count = csvobject.get_row_count()
    colum_count = csvobject.get_column_count()
    first_row = csvobject.get_data(rows=1)
    first_two_rows = csvobject.get_data(rows=5)

回答 0

最好先查看csv文件本身,但这可能对您有用,请尝试一下,替换:

file_read = csv.reader(self.file)

与:

file_read = csv.reader(self.file, dialect=csv.excel_tab)

或者,使用打开文件universal newline mode并将其传递给csv.reader,例如:

reader = csv.reader(open(self.file, 'rU'), dialect=csv.excel_tab)

或者,splitlines()像这样使用:

def read_file(self):
    with open(self.file, 'r') as f:
        data = [row for row in csv.reader(f.read().splitlines())]
    return data

It’ll be good to see the csv file itself, but this might work for you, give it a try, replace:

file_read = csv.reader(self.file)

with:

file_read = csv.reader(self.file, dialect=csv.excel_tab)

Or, open a file with universal newline mode and pass it to csv.reader, like:

reader = csv.reader(open(self.file, 'rU'), dialect=csv.excel_tab)

Or, use splitlines(), like this:

def read_file(self):
    with open(self.file, 'r') as f:
        data = [row for row in csv.reader(f.read().splitlines())]
    return data

回答 1

我意识到这是一篇过时的文章,但是遇到了同样的问题,但没有找到正确的答案,因此我将尝试一下

Python错误:

_csv.Error: new-line character seen in unquoted field

试图读取Macintosh(OS X之前的格式)的CSV文件引起的。这些是使用CR作为行尾的文本文件。如果使用MS Office,请确保选择纯CSV格式或CSV(MS-DOS)不要使用CSV(Macintosh)作为另存为类型。

我首选的EOL版本是LF(Unix / Linux / Apple),但我不认为MS Office提供了以这种格式保存的选项。

I realize this is an old post, but I ran into the same problem and don’t see the correct answer so I will give it a try

Python Error:

_csv.Error: new-line character seen in unquoted field

Caused by trying to read Macintosh (pre OS X formatted) CSV files. These are text files that use CR for end of line. If using MS Office make sure you select either plain CSV format or CSV (MS-DOS). Do not use CSV (Macintosh) as save-as type.

My preferred EOL version would be LF (Unix/Linux/Apple), but I don’t think MS Office provides the option to save in this format.


回答 2

对于Mac OS X,请以“ Windows逗号分隔(.csv)”格式保存CSV文件。

For Mac OS X, save your CSV file in “Windows Comma Separated (.csv)” format.


回答 3

如果您在Mac上遇到了这种情况(就像对我一样):

  1. 将文件另存为 CSV (MS-DOS Comma-Separated)
  2. 运行以下脚本

    with open(csv_filename, 'rU') as csvfile:
        csvreader = csv.reader(csvfile)
        for row in csvreader:
            print ', '.join(row)
    

If this happens to you on mac (as it did to me):

  1. Save the file as CSV (MS-DOS Comma-Separated)
  2. Run the following script

    with open(csv_filename, 'rU') as csvfile:
        csvreader = csv.reader(csvfile)
        for row in csvreader:
            print ', '.join(row)
    

回答 4

尝试先dos2unix在Windows导入的文件上运行

Try to run dos2unix on your windows imported files first


回答 5

这是我遇到的错误。我已将.csv文件保存在MAC OSX中。

保存时,将其另存为“ Windows逗号分隔值(.csv)”,此问题已解决。

This is an error that I faced. I had saved .csv file in MAC OSX.

While saving, save it as “Windows Comma Separated Values (.csv)” which resolved the issue.


回答 6

这在OSX上对我有用。

# allow variable to opened as files
from io import StringIO

# library to map other strange (accented) characters back into UTF-8
from unidecode import unidecode

# cleanse input file with Windows formating to plain UTF-8 string
with open(filename, 'rb') as fID:
    uncleansedBytes = fID.read()
    # decode the file using the correct encoding scheme
    # (probably this old windows one) 
    uncleansedText = uncleansedBytes.decode('Windows-1252')

    # replace carriage-returns with new-lines
    cleansedText = uncleansedText.replace('\r', '\n')

    # map any other non UTF-8 characters into UTF-8
    asciiText = unidecode(cleansedText)

# read each line of the csv file and store as an array of dicts, 
# use first line as field names for each dict. 
reader = csv.DictReader(StringIO(cleansedText))
for line_entry in reader:
    # do something with your read data 

This worked for me on OSX.

# allow variable to opened as files
from io import StringIO

# library to map other strange (accented) characters back into UTF-8
from unidecode import unidecode

# cleanse input file with Windows formating to plain UTF-8 string
with open(filename, 'rb') as fID:
    uncleansedBytes = fID.read()
    # decode the file using the correct encoding scheme
    # (probably this old windows one) 
    uncleansedText = uncleansedBytes.decode('Windows-1252')

    # replace carriage-returns with new-lines
    cleansedText = uncleansedText.replace('\r', '\n')

    # map any other non UTF-8 characters into UTF-8
    asciiText = unidecode(cleansedText)

# read each line of the csv file and store as an array of dicts, 
# use first line as field names for each dict. 
reader = csv.DictReader(StringIO(cleansedText))
for line_entry in reader:
    # do something with your read data 

回答 7

我知道这个问题已经回答了很长时间,但并不能解决我的问题。由于其他一些复杂性,我正在使用DictReader和StringIO进行csv读取。通过显式替换定界符,我能够更简单地解决问题:

with urllib.request.urlopen(q) as response:
    raw_data = response.read()
    encoding = response.info().get_content_charset('utf8') 
    data = raw_data.decode(encoding)
    if '\r\n' not in data:
        # proably a windows delimited thing...try to update it
        data = data.replace('\r', '\r\n')

对于庞大的CSV文件来说可能并不合理,但对于我的用例来说效果很好。

I know this has been answered for quite some time but not solve my problem. I am using DictReader and StringIO for my csv reading due to some other complications. I was able to solve problem more simply by replacing delimiters explicitly:

with urllib.request.urlopen(q) as response:
    raw_data = response.read()
    encoding = response.info().get_content_charset('utf8') 
    data = raw_data.decode(encoding)
    if '\r\n' not in data:
        # proably a windows delimited thing...try to update it
        data = data.replace('\r', '\r\n')

Might not be reasonable for enormous CSV files, but worked well for my use case.


回答 8

替代快速解决方案:我遇到了同样的错误。我在lubuntu机器上的GNUMERIC中重新打开了“奇怪的” csv文件,并将该文件导出为csv文件。这解决了问题。

Alternative and fast solution : I faced the same error. I reopened the “wierd” csv file in GNUMERIC on my lubuntu machine and exported the file as csv file. This corrected the issue.


Django-DB-Migrations:无法更改表,因为它具有未决的触发事件

问题:Django-DB-Migrations:无法更改表,因为它具有未决的触发事件

我想从TextField中删除null = True:

-    footer=models.TextField(null=True, blank=True)
+    footer=models.TextField(blank=True, default='')

我创建了一个架构迁移:

manage.py schemamigration fooapp --auto

由于某些页脚列包含,NULL因此error在运行迁移时会得到以下信息:

django.db.utils.IntegrityError:“页脚”列包含空值

我将其添加到架构迁移中:

    for sender in orm['fooapp.EmailSender'].objects.filter(footer=None):
        sender.footer=''
        sender.save()

现在我得到:

django.db.utils.DatabaseError: cannot ALTER TABLE "fooapp_emailsender" because it has pending trigger events

怎么了?

I want to remove null=True from a TextField:

-    footer=models.TextField(null=True, blank=True)
+    footer=models.TextField(blank=True, default='')

I created a schema migration:

manage.py schemamigration fooapp --auto

Since some footer columns contain NULL I get this error if I run the migration:

django.db.utils.IntegrityError: column “footer” contains null values

I added this to the schema migration:

    for sender in orm['fooapp.EmailSender'].objects.filter(footer=None):
        sender.footer=''
        sender.save()

Now I get:

django.db.utils.DatabaseError: cannot ALTER TABLE "fooapp_emailsender" because it has pending trigger events

What is wrong?


回答 0

造成这种情况的另一个原因可能是因为您尝试将一列设置为NOT NULL实际上已经具有NULL值的时间。

Another reason for this maybe because you try to set a column to NOT NULL when it actually already has NULL values.


回答 1

每次迁移都在事务内部。在PostgreSQL中,您不得在一个事务中更新表然后更改表模式。

您需要拆分数据迁移和架构迁移。首先使用以下代码创建数据迁移:

 for sender in orm['fooapp.EmailSender'].objects.filter(footer=None):
    sender.footer=''
    sender.save()

然后创建架构迁移:

manage.py schemamigration fooapp --auto

现在,您有两个事务,并且应该在两个步骤中进行迁移。

Every migration is inside a transaction. In PostgreSQL you must not update the table and then alter the table schema in one transaction.

You need to split the data migration and the schema migration. First create the data migration with this code:

 for sender in orm['fooapp.EmailSender'].objects.filter(footer=None):
    sender.footer=''
    sender.save()

Then create the schema migration:

manage.py schemamigration fooapp --auto

Now you have two transactions and the migration in two steps should work.


回答 2

刚刚遇到这个问题。您还可以在模式迁移中使用db.start_transaction()和db.commit_transaction()将数据更改与模式更改分开。可能不那么干净,无法进行单独的数据迁移,但是在我的情况下,我需要架构,数据,然后再进行另一种架构迁移,因此我决定一次完成所有操作。

Have just hit this problem. You can also use db.start_transaction() and db.commit_transaction() in the schema migration to separate data changes from schema changes. Probably not so clean as to have a separate data migration but in my case I would need schema, data, and then another schema migration so I decided to do it all at once.


回答 3

在操作中,我将SET约束:

operations = [
    migrations.RunSQL('SET CONSTRAINTS ALL IMMEDIATE;'),
    migrations.RunPython(migration_func),
    migrations.RunSQL('SET CONSTRAINTS ALL DEFERRED;'),
]

At the operations I put SET CONSTRAINTS:

operations = [
    migrations.RunSQL('SET CONSTRAINTS ALL IMMEDIATE;'),
    migrations.RunPython(migration_func),
    migrations.RunSQL('SET CONSTRAINTS ALL DEFERRED;'),
]

回答 4

您正在更改列架构。该页脚列不能再包含空白值。该列中很可能已经有空白值存储在数据库中。Django将使用migration命令将数据库中的空白行从空白更新为现在的默认值。Django尝试更新页脚列为空值的行,并在看起来相同的同时更改架构(我不确定)。

问题是您无法更改试图同时更新其值的列模式。

一种解决方案是删除迁移文件以更新架构。然后,运行脚本以将所有这些值更新为默认值。然后重新运行迁移以更新架构。这样,更新已完成。Django迁移仅更改架构。

You are altering the column schema. That footer column can no longer contain a blank value. There are most likely blank values already stored in the DB for that column. Django is going to update those blank rows in your DB from blank to the now default value with the migrate command. Django tries to update the rows where footer column has a blank value and change the schema at the same time it seems (I’m not sure).

The problem is you can’t alter the same column schema you are trying to update the values for at the same time.

One solution would be to delete the migrations file updating the schema. Then, run a script to update all those values to your default value. Then re-run the migration to update the schema. This way, the update is already done. Django migration is only altering the schema.