标签归档:Django

UnicodeDecodeError:’ascii’编解码器无法解码位置2的字节0xd1:序数不在范围内(128)

问题:UnicodeDecodeError:’ascii’编解码器无法解码位置2的字节0xd1:序数不在范围内(128)

我正在尝试使用其中包含一些非标准字符的超大型数据集。根据工作规范,我需要使用unicode,但我感到困惑。(这很可能做错了。)

我使用以下方式打开CSV:

 15     ncesReader = csv.reader(open('geocoded_output.csv', 'rb'), delimiter='\t', quotechar='"')

然后,我尝试使用以下代码对其进行编码:

name=school_name.encode('utf-8'), street=row[9].encode('utf-8'), city=row[10].encode('utf-8'), state=row[11].encode('utf-8'), zip5=row[12], zip4=row[13],county=row[25].encode('utf-8'), lat=row[22], lng=row[23])

我正在对除lat和lng以外的所有内容进行编码,因为它们需要发送到API。当我运行程序以将数据集解析为可以使用的内容时,将获得以下Traceback。

Traceback (most recent call last):
  File "push_into_db.py", line 80, in <module>
    main()
  File "push_into_db.py", line 74, in main
    district_map = buildDistrictSchoolMap()
  File "push_into_db.py", line 32, in buildDistrictSchoolMap
    county=row[25].encode('utf-8'), lat=row[22], lng=row[23])
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 2: ordinal not in range(128)

我想我应该告诉你我正在使用python 2.7.2,这是在django 1.4上构建的应用程序的一部分。我已经阅读了有关此主题的几篇文章,但似乎没有一篇直接适用。任何帮助将不胜感激。

您可能还想知道导致问题的一些非标准字符是Ñ,甚至是É。

I am attempting to work with a very large dataset that has some non-standard characters in it. I need to use unicode, as per the job specs, but I am baffled. (And quite possibly doing it all wrong.)

I open the CSV using:

 15     ncesReader = csv.reader(open('geocoded_output.csv', 'rb'), delimiter='\t', quotechar='"')

Then, I attempt to encode it with:

name=school_name.encode('utf-8'), street=row[9].encode('utf-8'), city=row[10].encode('utf-8'), state=row[11].encode('utf-8'), zip5=row[12], zip4=row[13],county=row[25].encode('utf-8'), lat=row[22], lng=row[23])

I’m encoding everything except the lat and lng because those need to be sent out to an API. When I run the program to parse the dataset into what I can use, I get the following Traceback.

Traceback (most recent call last):
  File "push_into_db.py", line 80, in <module>
    main()
  File "push_into_db.py", line 74, in main
    district_map = buildDistrictSchoolMap()
  File "push_into_db.py", line 32, in buildDistrictSchoolMap
    county=row[25].encode('utf-8'), lat=row[22], lng=row[23])
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 2: ordinal not in range(128)

I think I should tell you that I’m using python 2.7.2, and this is part of an app build on django 1.4. I’ve read several posts on this topic, but none of them seem to directly apply. Any help will be greatly appreciated.

You might also want to know that some of the non-standard characters causing the issue are Ñ and possibly É.


回答 0

Unicode不等于UTF-8。后者只是前者的编码

您做错了方法。您正在读取 UTF-8 编码的数据,因此必须将UTF-8编码的字符串解码为unicode字符串。

因此,只需替换.encode.decode,它就可以工作(如果您的.csv是UTF-8编码的)。

没什么可羞耻的。我敢打赌,五分之三的程序员最初很难理解这一点,如果不是更多的话;)

更新:如果您的输入数据不是 UTF-8编码的,那么您当然必须.decode()使用适当的编码。如果未提供任何内容,则python会假定使用ASCII,这显然会在非ASCII字符上失败。

Unicode is not equal to UTF-8. The latter is just an encoding for the former.

You are doing it the wrong way around. You are reading UTF-8-encoded data, so you have to decode the UTF-8-encoded String into a unicode string.

So just replace .encode with .decode, and it should work (if your .csv is UTF-8-encoded).

Nothing to be ashamed of, though. I bet 3 in 5 programmers had trouble at first understanding this, if not more ;)

Update: If your input data is not UTF-8 encoded, then you have to .decode() with the appropriate encoding, of course. If nothing is given, python assumes ASCII, which obviously fails on non-ASCII-characters.


回答 1

只需将以下行添加到您的代码中:

import sys
reload(sys)
sys.setdefaultencoding('utf-8')

Just add this lines to your codes :

import sys
reload(sys)
sys.setdefaultencoding('utf-8')

回答 2

适用于Python 3用户。你可以做

with open(csv_name_here, 'r', encoding="utf-8") as f:
    #some codes

它也可以与烧瓶一起工作:)

for Python 3 users. you can do

with open(csv_name_here, 'r', encoding="utf-8") as f:
    #some codes

it works with flask too :)


回答 3

错误的主要原因是python假定的默认编码为ASCII。因此,如果要编码的字符串数据encode('utf8')包含ASCII范围之外的字符(例如,类似“ hgvcj터파크387”的字符串),则python将抛出错误,因为该字符串未采用预期的编码格式。

如果您使用的Python版本早于3.5版,则可靠的解决方法是将python假定的默认编码设置为utf8

import sys
reload(sys)
sys.setdefaultencoding('utf8')
name = school_name.encode('utf8')

这样,python就能预见ASCII范围之外的字符串中的字符。

但是,如果您使用的是python 3.5或更高版本,则reload()函数不可用,因此您必须使用解码来修复它,例如

name = school_name.decode('utf8').encode('utf8')

The main reason for the error is that the default encoding assumed by python is ASCII. Hence, if the string data to be encoded by encode('utf8') contains character that is outside of ASCII range e.g. for a string like ‘hgvcj터파크387’, python would throw error because the string is not in the expected encoding format.

If you are using python version earlier than version 3.5, a reliable fix would be to set the default encoding assumed by python to utf8:

import sys
reload(sys)
sys.setdefaultencoding('utf8')
name = school_name.encode('utf8')

This way python would be able to anticipate characters within a string that fall outside of ASCII range.

However, if you are using python version 3.5 or above, reload() function is not available, so you would have to fix it using decode e.g.

name = school_name.decode('utf8').encode('utf8')

回答 4

对于Python 3用户:

将编码从“ ascii”更改为“ latin1”起作用。

另外,您可以尝试使用以下代码段读取前10000个字节来自动查找编码:

import chardet  
with open("dataset_path", 'rb') as rawdata:  
            result = chardet.detect(rawdata.read(10000))  
print(result)

For Python 3 users:

changing the encoding from ‘ascii’ to ‘latin1’ works.

Also, you can try finding the encoding automatically by reading the top 10000 bytes using the below snippet:

import chardet  
with open("dataset_path", 'rb') as rawdata:  
            result = chardet.detect(rawdata.read(10000))  
print(result)

回答 5

我的计算机的语言环境设置错误。

我先做了

>>> import locale
>>> locale.getpreferredencoding(False)
'ANSI_X3.4-1968'

locale.getpreferredencoding(False)open()不提供编码时调用的函数。输出应该是'UTF-8',但是在这种情况下,它是ASCII的某种变体

然后我运行bash命令locale并获得此输出

$ locale
LANG=
LANGUAGE=
LC_CTYPE="POSIX"
LC_NUMERIC="POSIX"
LC_TIME="POSIX"
LC_COLLATE="POSIX"
LC_MONETARY="POSIX"
LC_MESSAGES="POSIX"
LC_PAPER="POSIX"
LC_NAME="POSIX"
LC_ADDRESS="POSIX"
LC_TELEPHONE="POSIX"
LC_MEASUREMENT="POSIX"
LC_IDENTIFICATION="POSIX"
LC_ALL=

因此,我使用的是默认的Ubuntu语言环境,这会导致Python将文件打开为ASCII而不是UTF-8。我必须将语言环境设置en_US.UTF-8

sudo apt install locales 
sudo locale-gen en_US en_US.UTF-8    
sudo dpkg-reconfigure locales

如果无法在整个系统范围内更改语言环境,则可以像下面这样调用所有Python代码:

PYTHONIOENCODING="UTF-8" python3 ./path/to/your/script.py

或做

export PYTHONIOENCODING="UTF-8"

在运行它的shell中设置它。

My computer had the wrong locale set.

I first did

>>> import locale
>>> locale.getpreferredencoding(False)
'ANSI_X3.4-1968'

locale.getpreferredencoding(False) is the function called by open() when you don’t provide an encoding. The output should be 'UTF-8', but in this case it’s some variant of ASCII.

Then I ran the bash command locale and got this output

$ locale
LANG=
LANGUAGE=
LC_CTYPE="POSIX"
LC_NUMERIC="POSIX"
LC_TIME="POSIX"
LC_COLLATE="POSIX"
LC_MONETARY="POSIX"
LC_MESSAGES="POSIX"
LC_PAPER="POSIX"
LC_NAME="POSIX"
LC_ADDRESS="POSIX"
LC_TELEPHONE="POSIX"
LC_MEASUREMENT="POSIX"
LC_IDENTIFICATION="POSIX"
LC_ALL=

So, I was using the default Ubuntu locale, which causes Python to open files as ASCII instead of UTF-8. I had to set my locale to en_US.UTF-8

sudo apt install locales 
sudo locale-gen en_US en_US.UTF-8    
sudo dpkg-reconfigure locales

If you can’t change the locale system wide, you can invoke all your Python code like this:

PYTHONIOENCODING="UTF-8" python3 ./path/to/your/script.py

or do

export PYTHONIOENCODING="UTF-8"

to set it in the shell you run that in.


回答 6

如果在创建或更新证书时运行certbot时遇到此问题,请使用以下方法

grep -r -P '[^\x00-\x7f]' /etc/apache2 /etc/letsencrypt /etc/nginx

该命令在注释的一个.conf文件中找到了令人反感的字符“´”。删除它(您可以根据需要编辑评论)并重新加载nginx之后,一切又恢复了。

来源:https : //github.com/certbot/certbot/issues/5236

if you get this issue while running certbot while creating or renewing certificate, Please use the following method

grep -r -P '[^\x00-\x7f]' /etc/apache2 /etc/letsencrypt /etc/nginx

That command found the offending character “´” in one .conf file in the comment. After removing it (you can edit comments as you wish) and reloading nginx, everything worked again.

Source :https://github.com/certbot/certbot/issues/5236


回答 7

或者,如果您使用Python处理文本(如果它是Unicode文本),请记下它是Unicode。

设置text=u'unicode text'只是text='unicode text'

在我看来,这是可行的。

Or when you deal with text in Python if it is a Unicode text, make a note it is Unicode.

Set text=u'unicode text' instead just text='unicode text'.

This worked in my case.


回答 8

由于纬度和经度而使用UTF 16编码打开。

with open(csv_name_here, 'r', encoding="utf-16") as f:

open with encoding UTF 16 because of lat and long.

with open(csv_name_here, 'r', encoding="utf-16") as f:

回答 9

它只是通过将参数’rb’读为二进制而不是’r’读而起作用

It does work by just taking the argument ‘rb’ read binary instead of ‘r’ read


在Django模板中按索引引用列表项?

问题:在Django模板中按索引引用列表项?

这可能很简单,但是我环顾四周,找不到答案。从Django模板引用列表中的单个项目的最佳方法是什么?

换句话说,{{ data[0] }}在模板语言中我该如何做?

谢谢。

This may be simple, but I looked around and couldn’t find an answer. What’s the best way to reference a single item in a list from a Django template?

In other words how do I do the equivalent of {{ data[0] }} within the template language?

Thanks.


回答 0

看起来像{{ data.0 }}。请参阅变量和查找

It looks like {{ data.0 }}. See Variables and lookups.


回答 1

更好的方法:自定义模板过滤器:https : //docs.djangoproject.com/en/dev/howto/custom-template-tags/

例如在模板中获取my_list [x]:

在模板中

{% load index %}
{{ my_list|index:x }}

templatetags / index.py

from django import template
register = template.Library()

@register.filter
def index(indexable, i):
    return indexable[i]

如果my_list = [['a','b','c'], ['d','e','f']],您可以{{ my_list|index:x|index:y }}在模板中使用my_list[x][y]

与“ for”一起正常工作

{{ my_list|index:forloop.counter0 }}

经过测试,效果很好^ _ ^

A better way: custom template filter: https://docs.djangoproject.com/en/dev/howto/custom-template-tags/

such as get my_list[x] in templates:

in template

{% load index %}
{{ my_list|index:x }}

templatetags/index.py

from django import template
register = template.Library()

@register.filter
def index(indexable, i):
    return indexable[i]

if my_list = [['a','b','c'], ['d','e','f']], you can use {{ my_list|index:x|index:y }} in template to get my_list[x][y]

It works fine with “for”

{{ my_list|index:forloop.counter0 }}

Tested and works well ^_^


回答 2

{{ data.0 }} 应该管用。

假设您写了data.objdjango try data.objdata.obj()。如果他们不起作用,它会尝试data["obj"]。你的情况data[0]可以写成{{ data.0 }}。但是我建议您data[0]插入视图并将其作为单独的变量发送。

{{ data.0 }} should work.

Let’s say you wrote data.obj django tries data.obj and data.obj(). If they don’t work it tries data["obj"]. In your case data[0] can be written as {{ data.0 }}. But I recommend you to pull data[0] in the view and send it as separate variable.


回答 3

@ jennifer06262016,您绝对可以添加另一个过滤器以返回Django Queryset中的对象。

@register.filter 
def get_item(Queryset):
    return Queryset.your_item_key

在这种情况下,您可以在模板中输入类似{{Queryset | index:x | get_item}}的内容,以访问某些字典对象。这个对我有用。

@jennifer06262016, you can definitely add another filter to return the objects inside a django Queryset.

@register.filter 
def get_item(Queryset):
    return Queryset.your_item_key

In that case, you would type something like this {{ Queryset|index:x|get_item }} into your template to access some dictionary object. It works for me.


Django,创建自定义500/404错误页面

问题:Django,创建自定义500/404错误页面

完全按照此处找到的教程进行操作,我无法创建自定义的500或404错误页面。如果我确实输入了错误的网址,则该页面会显示默认的错误页面。我应该检查哪些内容以防止显示自定义页面?

文件目录:

mysite/
    mysite/
        __init__.py
        __init__.pyc
        settings.py
        settings.pyc
        urls.py
        urls.pyc
        wsgi.py
        wsgi.pyc
    polls/
        templates/
            admin/
                base_site.html
            404.html
            500.html
            polls/
                detail.html
                index.html
        __init__.py
        __init__.pyc
        admin.py
        admin.pyc
        models.py
        models.pyc
        tests.py
        urls.py
        urls.pyc
        view.py
        views.pyc
    templates/
    manage.py

在mysite / settings.py中,我启用了以下功能:

DEBUG = False
TEMPLATE_DEBUG = DEBUG

#....

TEMPLATE_DIRS = (
    'C:/Users/Me/Django/mysite/templates', 
)

在mysite / polls / urls.py中:

from django.conf.urls import patterns, url

from polls import views

urlpatterns = patterns('',
    url(r'^$', views.index, name='index'),
    url(r'^(?P<poll_id>\d+)/$', views.detail, name='detail'),
    url(r'^(?P<poll_id>\d+)/results/$', views.results, name='results'),
    url(r'^(?P<poll_id>\d+)/vote/$', views.vote, name='vote'),
)

我可以发布任何其他必要的代码,但是如果我使用了错误的网址,应该如何更改以获得自定义500错误页面?

编辑

解决方案: 我还有一个

TEMPLATE_DIRS

在我的settings.py中,那是导致问题的原因

Following the tutorial found here exactly, I cannot create a custom 500 or 404 error page. If I do type in a bad url, the page gives me the default error page. Is there anything I should be checking for that would prevent a custom page from showing up?

File directories:

mysite/
    mysite/
        __init__.py
        __init__.pyc
        settings.py
        settings.pyc
        urls.py
        urls.pyc
        wsgi.py
        wsgi.pyc
    polls/
        templates/
            admin/
                base_site.html
            404.html
            500.html
            polls/
                detail.html
                index.html
        __init__.py
        __init__.pyc
        admin.py
        admin.pyc
        models.py
        models.pyc
        tests.py
        urls.py
        urls.pyc
        view.py
        views.pyc
    templates/
    manage.py

within mysite/settings.py I have these enabled:

DEBUG = False
TEMPLATE_DEBUG = DEBUG

#....

TEMPLATE_DIRS = (
    'C:/Users/Me/Django/mysite/templates', 
)

within mysite/polls/urls.py:

from django.conf.urls import patterns, url

from polls import views

urlpatterns = patterns('',
    url(r'^$', views.index, name='index'),
    url(r'^(?P<poll_id>\d+)/$', views.detail, name='detail'),
    url(r'^(?P<poll_id>\d+)/results/$', views.results, name='results'),
    url(r'^(?P<poll_id>\d+)/vote/$', views.vote, name='vote'),
)

I can post any other code necessary, but what should I be changing to get a custom 500 error page if I use a bad url?

Edit

SOLUTION: I had an additional

TEMPLATE_DIRS

within my settings.py and that was causing the problem


回答 0

在您的主目录下,views.py添加您自己的以下两个视图的自定义实现,然后只需设置要显示的模板404.html500.html

使用此解决方案,无需将自定义代码添加到 urls.py

这是代码:

from django.shortcuts import render_to_response
from django.template import RequestContext


def handler404(request, *args, **argv):
    response = render_to_response('404.html', {},
                                  context_instance=RequestContext(request))
    response.status_code = 404
    return response


def handler500(request, *args, **argv):
    response = render_to_response('500.html', {},
                                  context_instance=RequestContext(request))
    response.status_code = 500
    return response

更新资料

handler404handler500导出的Django字符串配置变量django/conf/urls/__init__.py。这就是上面的配置起作用的原因。

为了使上述配置生效,您应该在urls.py文件中定义以下变量,并将导出的Django变量指向定义这些Django功能视图的字符串Python路径,如下所示:

# project/urls.py

handler404 = 'my_app.views.handler404'
handler500 = 'my_app.views.handler500'

Django 2.0更新

处理程序视图的签名在Django 2.0中已更改:https : //docs.djangoproject.com/en/2.0/ref/views/#error-views

如果您使用上述视图,则handler404将失败并显示以下消息:

“ handler404()获得了意外的关键字参数’exception’”

在这种情况下,请修改您的视图,如下所示:

def handler404(request, exception, template_name="404.html"):
    response = render_to_response(template_name)
    response.status_code = 404
    return response

Under your main views.py add your own custom implementation of the following two views, and just set up the templates 404.html and 500.html with what you want to display.

With this solution, no custom code needs to be added to urls.py

Here’s the code:

from django.shortcuts import render_to_response
from django.template import RequestContext


def handler404(request, *args, **argv):
    response = render_to_response('404.html', {},
                                  context_instance=RequestContext(request))
    response.status_code = 404
    return response


def handler500(request, *args, **argv):
    response = render_to_response('500.html', {},
                                  context_instance=RequestContext(request))
    response.status_code = 500
    return response

Update

handler404 and handler500 are exported Django string configuration variables found in django/conf/urls/__init__.py. That is why the above config works.

To get the above config to work, you should define the following variables in your urls.py file and point the exported Django variables to the string Python path of where these Django functional views are defined, like so:

# project/urls.py

handler404 = 'my_app.views.handler404'
handler500 = 'my_app.views.handler500'

Update for Django 2.0

Signatures for handler views were changed in Django 2.0: https://docs.djangoproject.com/en/2.0/ref/views/#error-views

If you use views as above, handler404 will fail with message:

“handler404() got an unexpected keyword argument ‘exception'”

In such case modify your views like this:

def handler404(request, exception, template_name="404.html"):
    response = render_to_response(template_name)
    response.status_code = 404
    return response

回答 1

官方回答:

这是有关如何设置自定义错误视图的官方文档的链接:

https://docs.djangoproject.com/zh-CN/stable/topics/http/views/#customizing-error-views

它说在URLconf中添加这样的行(在其他任何地方设置它们都无效):

handler404 = 'mysite.views.my_custom_page_not_found_view'
handler500 = 'mysite.views.my_custom_error_view'
handler403 = 'mysite.views.my_custom_permission_denied_view'
handler400 = 'mysite.views.my_custom_bad_request_view'

您还可以通过修改设置来自定义CSRF错误视图CSRF_FAILURE_VIEW

默认错误处理程序:

这是值得一读的默认错误处理程序的文档page_not_foundserver_errorpermission_deniedbad_request。默认情况下,他们使用这些模板,如果他们可以分别找到他们,: ,404.html500.html403.html400.html

因此,如果您要做的只是创建漂亮的错误页面,只需在TEMPLATE_DIRS目录中创建这些文件,则根本不需要编辑URLConf。阅读文档以查看可用的上下文变量。

在Django 1.10及更高版本中,默认的CSRF错误视图使用template 403_csrf.html

陷阱:

不要忘记DEBUG必须将它们设置为False才能起作用,否则,将使用常规的调试处理程序。

Official answer:

Here is the link to the official documentation on how to set up custom error views:

https://docs.djangoproject.com/en/stable/topics/http/views/#customizing-error-views

It says to add lines like these in your URLconf (setting them anywhere else will have no effect):

handler404 = 'mysite.views.my_custom_page_not_found_view'
handler500 = 'mysite.views.my_custom_error_view'
handler403 = 'mysite.views.my_custom_permission_denied_view'
handler400 = 'mysite.views.my_custom_bad_request_view'

You can also customise the CSRF error view by modifying the setting CSRF_FAILURE_VIEW.

Default error handlers:

It’s worth reading the documentation of the default error handlers, page_not_found, server_error, permission_denied and bad_request. By default, they use these templates if they can find them, respectively: 404.html, 500.html, 403.html, and 400.html.

So if all you want to do is make pretty error pages, just create those files in a TEMPLATE_DIRS directory, you don’t need to edit URLConf at all. Read the documentation to see which context variables are available.

In Django 1.10 and later, the default CSRF error view uses the template 403_csrf.html.

Gotcha:

Don’t forget that DEBUG must be set to False for these to work, otherwise, the normal debug handlers will be used.


回答 2

将这些行添加到urls.py中

urls.py

from django.conf.urls import (
handler400, handler403, handler404, handler500
)

handler400 = 'my_app.views.bad_request'
handler403 = 'my_app.views.permission_denied'
handler404 = 'my_app.views.page_not_found'
handler500 = 'my_app.views.server_error'

# ...

并在views.py中实现我们的自定义视图。

views.py

from django.shortcuts import (
render_to_response
)
from django.template import RequestContext

# HTTP Error 400
def bad_request(request):
    response = render_to_response(
        '400.html',
        context_instance=RequestContext(request)
        )

        response.status_code = 400

        return response

# ...

Add these lines in urls.py

urls.py

from django.conf.urls import (
handler400, handler403, handler404, handler500
)

handler400 = 'my_app.views.bad_request'
handler403 = 'my_app.views.permission_denied'
handler404 = 'my_app.views.page_not_found'
handler500 = 'my_app.views.server_error'

# ...

and implement our custom views in views.py.

views.py

from django.shortcuts import (
render_to_response
)
from django.template import RequestContext

# HTTP Error 400
def bad_request(request):
    response = render_to_response(
        '400.html',
        context_instance=RequestContext(request)
        )

        response.status_code = 400

        return response

# ...

回答 3

从您引用的页面:

当您从视图中引发Http404时,Django将加载一个专用于处理404错误的特殊视图。它通过在根URLconf中(仅在根URLconf中;在其他任何位置设置handler404都无效)中查找变量handler404来找到它,这是Python点分语法的字符串–与普通URLconf回调使用的格式相同。404视图本身没有什么特别的:它只是一个普通视图。

因此,我相信您需要在urls.py中添加以下内容:

handler404 = 'views.my_404_view'

和handler500类似。

From the page you referenced:

When you raise Http404 from within a view, Django will load a special view devoted to handling 404 errors. It finds it by looking for the variable handler404 in your root URLconf (and only in your root URLconf; setting handler404 anywhere else will have no effect), which is a string in Python dotted syntax – the same format the normal URLconf callbacks use. A 404 view itself has nothing special: It’s just a normal view.

So I believe you need to add something like this to your urls.py:

handler404 = 'views.my_404_view'

and similar for handler500.


回答 4

如果您需要的是在时显示自定义页面,其中包含您网站的一些错误消息DEBUG = False,则在模板目录中添加两个名为404.html和500.html的模板,当404或500时,它将自动提取此自定义页面被提出。

If all you need is to show custom pages which have some fancy error messages for your site when DEBUG = False, then add two templates named 404.html and 500.html in your templates directory and it will automatically pick up this custom pages when a 404 or 500 is raised.


回答 5

Django 2. *中,您可以在views.py中使用此构造

def handler404(request, exception):
    return render(request, 'errors/404.html', locals())

settings.py中

DEBUG = False

if DEBUG is False:
    ALLOWED_HOSTS = [
        '127.0.0.1:8000',
        '*',
    ]

if DEBUG is True:
    ALLOWED_HOSTS = []

urls.py中

# https://docs.djangoproject.com/en/2.0/topics/http/views/#customizing-error-views
handler404 = 'YOUR_APP_NAME.views.handler404'

通常我创建default_app并处理站点范围的错误,并在其中处理上下文。

In Django 2.* you can use this construction in views.py

def handler404(request, exception):
    return render(request, 'errors/404.html', locals())

In settings.py

DEBUG = False

if DEBUG is False:
    ALLOWED_HOSTS = [
        '127.0.0.1:8000',
        '*',
    ]

if DEBUG is True:
    ALLOWED_HOSTS = []

In urls.py

# https://docs.djangoproject.com/en/2.0/topics/http/views/#customizing-error-views
handler404 = 'YOUR_APP_NAME.views.handler404'

Usually i creating default_app and handle site-wide errors, context processors in it.


回答 6

settings.py:

DEBUG = False
TEMPLATE_DEBUG = DEBUG
ALLOWED_HOSTS = ['localhost']  #provide your host name

并将您的404.html500.html页面添加到模板文件夹中。删除404.html500.html从模板中投票应用程序。

settings.py:

DEBUG = False
TEMPLATE_DEBUG = DEBUG
ALLOWED_HOSTS = ['localhost']  #provide your host name

and just add your 404.html and 500.html pages in templates folder. remove 404.html and 500.html from templates in polls app.


回答 7

出错,在错误页面上找到django从何处加载模板。我的意思是路径堆栈。在基本template_dir中添加这些html页面500.html404.html。发生这些错误时,将自动加载相应的模板文件。

您也可以为其他错误代码添加页面,例如400403

希望这个帮助!

Make an error, On the error page find out from where django is loading templates.I mean the path stack.In base template_dir add these html pages 500.html , 404.html. When these errors occur the respective template files will be automatically loaded.

You can add pages for other error codes too, like 400 and 403.

Hope this help !!!


回答 8

在Django中3.x,接受的答案将不起作用,因为render_to_response自从接受的版本适用于该版本以来,它已被完全删除以及进行了一些其他更改。

还有其他一些答案,但我提供的答案更简洁:

在您的主urls.py文件中:

handler404 = 'yourapp.views.handler404'
handler500 = 'yourapp.views.handler500'

yourapp/views.py文件中:

def handler404(request, exception):
    context = {}
    response = render(request, "pages/errors/404.html", context=context)
    response.status_code = 404
    return response


def handler500(request):
    context = {}
    response = render(request, "pages/errors/500.html", context=context)
    response.status_code = 500
    return response

请确保您已导入render()yourapp/views.py文件:

from django.shortcuts import render

旁注:render_to_response()在Django中已弃用,2.x在verision中已完全删除3.x

In Django 3.x, the accepted answer won’t work because render_to_response has been removed completely as well as some more changes have been made since the version the accepted answer worked for.

Some other answers are also there but I’m presenting a little cleaner answer:

In your main urls.py file:

handler404 = 'yourapp.views.handler404'
handler500 = 'yourapp.views.handler500'

In yourapp/views.py file:

def handler404(request, exception):
    context = {}
    response = render(request, "pages/errors/404.html", context=context)
    response.status_code = 404
    return response


def handler500(request):
    context = {}
    response = render(request, "pages/errors/500.html", context=context)
    response.status_code = 500
    return response

Ensure that you have imported render() in yourapp/views.py file:

from django.shortcuts import render

Side note: render_to_response() was deprecated in Django 2.x and it has been completely removed in verision 3.x.


回答 9

作为一行(对于404通用页面):

from django.shortcuts import render_to_response
from django.template import RequestContext

return render_to_response('error/404.html', {'exception': ex},
                                      context_instance=RequestContext(request), status=404)

As one single line (for 404 generic page):

from django.shortcuts import render_to_response
from django.template import RequestContext

return render_to_response('error/404.html', {'exception': ex},
                                      context_instance=RequestContext(request), status=404)

回答 10

# views.py
def handler404(request, exception):
    context = RequestContext(request)
    err_code = 404
    response = render_to_response('404.html', {"code":err_code}, context)
    response.status_code = 404
    return response

# <project_folder>.urls.py
handler404 = 'todo.views.handler404' 

这适用于Django 2.0

确保将您的自定义内容404.html包含在应用程序模板文件夹中。

# views.py
def handler404(request, exception):
    context = RequestContext(request)
    err_code = 404
    response = render_to_response('404.html', {"code":err_code}, context)
    response.status_code = 404
    return response

# <project_folder>.urls.py
handler404 = 'todo.views.handler404' 

This works on django 2.0

Be sure to include your custom 404.html inside the app templates folder.


回答 11

Django 3.0

这是链接如何自定义错误视图

这是链接如何渲染视图

urls.py(主文件夹中的项目文件夹中)中,放入:

handler404 = 'my_app_name.views.custom_page_not_found_view'
handler500 = 'my_app_name.views.custom_error_view'
handler403 = 'my_app_name.views.custom_permission_denied_view'
handler400 = 'my_app_name.views.custom_bad_request_view'

并在该应用(my_app_name)中放入views.py

def custom_page_not_found_view(request, exception):
    return render(request, "errors/404.html", {})

def custom_error_view(request, exception=None):
    return render(request, "errors/500.html", {})

def custom_permission_denied_view(request, exception=None):
    return render(request, "errors/403.html", {})

def custom_bad_request_view(request, exception=None):
    return render(request, "errors/400.html", {})

注意:error/404.html如果您将文件放置到项目(而不是应用程序)模板文件夹中templates/errors/404.html,则为路径,因此请将文件放置在所需位置并编写正确的路径。

注2:页面重新加载后,如果仍然看到旧模板,请更改settings.py DEBUG=True,保存它,然后再次更改为False(重新启动服务器并收集新文件)。

Django 3.0

here is link how to customize error views

here is link how to render a view

in the urls.py (the main one, in project folder), put:

handler404 = 'my_app_name.views.custom_page_not_found_view'
handler500 = 'my_app_name.views.custom_error_view'
handler403 = 'my_app_name.views.custom_permission_denied_view'
handler400 = 'my_app_name.views.custom_bad_request_view'

and in that app (my_app_name) put in the views.py:

def custom_page_not_found_view(request, exception):
    return render(request, "errors/404.html", {})

def custom_error_view(request, exception=None):
    return render(request, "errors/500.html", {})

def custom_permission_denied_view(request, exception=None):
    return render(request, "errors/403.html", {})

def custom_bad_request_view(request, exception=None):
    return render(request, "errors/400.html", {})

NOTE: error/404.html is the path if you place your files into the projects (not the apps) template foldertemplates/errors/404.html so please place the files where you want and write the right path.

NOTE 2: After page reload, if you still see the old template, change in settings.py DEBUG=True, save it, and then again to False (to restart the server and collect the new files).


回答 12

不需要其他视图。https://docs.djangoproject.com/zh-CN/3.0/ref/views/

只需将错误文件放在模板目录的根目录中

  • 404.html
  • 400.html
  • 403.html
  • 500.html

当debug为False时,它应该使用您的错误页面

No additional view is required. https://docs.djangoproject.com/en/3.0/ref/views/

Just put the error files in the root of templates directory

  • 404.html
  • 400.html
  • 403.html
  • 500.html

And it should use your error page when debug is False


回答 13

尝试将错误模板移至.../Django/mysite/templates/

我注意到这一点,但是我认为这些对于网站来说必须是“全球性的”。

Try moving your error templates to .../Django/mysite/templates/ ?

I’m note sure about this one, but i think these need to be “global” to the website.


Django-“没有名为django.core.management的模块”

问题:Django-“没有名为django.core.management的模块”

尝试从命令行运行Django时出现以下错误。

File manage.py, line 8, in <module>
     from django.core.management import execute_from_command_line
ImportError: No module named django.core.management

关于如何解决这个问题的任何想法?

I get the following error when trying to run Django from the command line.

File manage.py, line 8, in <module>
     from django.core.management import execute_from_command_line
ImportError: No module named django.core.management

Any ideas on how to solve this?


回答 0

听起来您没有安装django。您应该检查此命令生成的目录:

python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"

看那里是否有django软件包。

如果站点软件包中没有django文件夹,则说明您没有安装django(至少对于该版本的python)。

可能您安装了多个版本的python,而django位于另一版本中。如果键入python然后按TAB键,则可以找出python的所有版本。这是我拥有的所有不同的python。

$python
python            python2-config    python2.6         python2.7-config  pythonw2.5
python-config     python2.5         python2.6-config  pythonw           pythonw2.6
python2           python2.5-config  python2.7         pythonw2          pythonw2.7

您可以对每个python版本执行上述命令,并查看每个版本的site-packages目录以查看其中是否安装了django。例如:

python2.5 -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"
python2.6 -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"

如果您碰巧在python2.6中找到django,请尝试使用以下原始命令

python2.6 manage.py ...

It sounds like you do not have django installed. You should check the directory produced by this command:

python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"

To see if you have the django packages in there.

If there’s no django folder inside of site-packages, then you do not have django installed (at least for that version of python).

It is possible you have more than one version of python installed and django is inside of another version. You can find out all the versions of python if you type python and then press TAB. Here are all the different python’s I have.

$python
python            python2-config    python2.6         python2.7-config  pythonw2.5
python-config     python2.5         python2.6-config  pythonw           pythonw2.6
python2           python2.5-config  python2.7         pythonw2          pythonw2.7

You can do the above command for each version of python and look inside the site-packages directory of each to see if any of them have django installed. For example:

python2.5 -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"
python2.6 -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"

If you happen to find django inside of say python2.6, try your original command with

python2.6 manage.py ...

回答 1

sudo pip install django --upgrade 

为我做了把戏。

sudo pip install django --upgrade 

did the trick for me.


回答 2

我遇到了相同的错误,并以这种方式修复了该错误:

我必须使用以下命令激活我的虚拟环境

source python2.7/bin/activate

I got the same error and I fixed it in this manner:

I had to activate my virtual environment using the following command

source python2.7/bin/activate

回答 3

manage.py第一行很可能以!/usr/bin/python它开头,这意味着您正在使用系统全局python,而不是虚拟环境中的python。

所以更换

/usr/bin/python

~/projectpath/venv/bin/python

你应该很好

Most probably in your manage.py the first line starts with !/usr/bin/python which means you are using the system global python rather than the one in your virtual environment.

so replace

/usr/bin/python

with

~/projectpath/venv/bin/python

and you should be good.


回答 4

好吧,我在安装virtualenv和django之后今天遇到了同样的错误。对我来说,是我使用sudo(sudo pip install django)来安装django,而我试图在不使用sudo的情况下运行manage.py runserver。我刚刚添加了sudo,它起作用了。:)

well, I faced the same error today after installing virtualenv and django. For me it was that I had used sudo (sudo pip install django) for installing django, and I was trying to run the manage.py runserver without sudo. I just added sudo and it worked. :)


回答 5

您是否正在使用带有Virtual Wrapper的虚拟环境?您在Mac上吗?

如果是这样,请尝试以下操作:

在命令行中输入以下内容以启动虚拟环境,然后对其进行处理

1.)

source virtualenvwrapper.sh

要么

source /usr/local/bin/virtualenvwrapper.sh

2.)

workon [environment name]

注意(来自新手)-请勿在您的环境名称前使用方括号

Are you using a Virtual Environment with Virtual Wrapper? Are you on a Mac?

If so try this:

Enter the following into your command line to start up the virtual environment and then work on it

1.)

source virtualenvwrapper.sh

or

source /usr/local/bin/virtualenvwrapper.sh

2.)

workon [environment name]

Note (from a newbie) – do not put brackets around your environment name


回答 6

我在执行命令时遇到同样的问题-

python manage.py startapp <应用程序名称>

但是我的问题是我在虚拟环境之外运行了该命令。因此,请先激活您的虚拟环境,然后再次运行该命令-

I am having the same problem while running the command-

python manage.py startapp < app_name >

but problem with me is that i was running that command out of virtual environment.So just activate your virtual environment first and run the command again –


回答 7

当您的计算机上未安装django时,会发生此问题。如果未安装django,则意味着也未安装django.core.management模块。因此,它找不到此模块,并给出了错误。
为了解决这个问题,我们应该使用pip安装django。打开命令行cmd(在Windows上)并输入

pip install django

此命令将在您的计算机上安装django。如果您没有安装pip。你应该安装点子。这里如何在Windows上安装pip

This problem occurs when django is not installed on your computer. When django is not installed which means django.core.management module is also is not installed. So it didn’t find this module and it gives error.
For solving this problem we should install django using pip. Open comand line cmd(on windows) and type as

pip install django

This command will install django in your computer. If you don’t have install pip. you should install pip. Here how to install pip on windows


回答 8

我遇到同样的事情,这就是我所做的。

首先我的安装

点安装-r requirements.txt

不在我的活动环境中。所以我要做的是激活我的环境,然后再次运行

点安装-r requirements.txt

I experience the same thing and this is what I do.

First my installation of

pip install -r requirements.txt

is not on my active environment. So I did is activate my environment then run again the

pip install -r requirements.txt


回答 9

好的,它像这样:

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

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

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

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

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

使用pip的命令:pip install django

然后这样做:

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

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

希望这可以帮助。

Okay so it goes like this:

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

go through this for further assistance:

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

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

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

Command using pip: pip install django

then do this:

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

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

Hope this helps.


回答 10

如果这对其他人有帮助…我有这个问题,因为我的virtualenv默认为python2.7,而我在使用Ubuntu时使用Python3调用Django。

检查我的virtualenv使用的是哪个python:

$ which python3
>> /usr/bin/python3

使用指定的python3创建了新的virtualenv(使用virtualenv包装器https://virtualenvwrapper.readthedocs.org/en/latest/):

$ mkvirtualenv --python=/usr/bin/python3 ENV_NAME

python路径现在应该指向virtualenv python:

$ which python3
>> /home/user/.virtualenvs/ENV_NAME/bin/python3

In case this is helpful to others… I had this issue because my virtualenv defaulted to python2.7 and I was calling Django using Python3 while using Ubuntu.

to check which python my virtualenv was using:

$ which python3
>> /usr/bin/python3

created new virtualenv with python3 specified (using virtualenv wrapper https://virtualenvwrapper.readthedocs.org/en/latest/):

$ mkvirtualenv --python=/usr/bin/python3 ENV_NAME

the python path should now point to the virtualenv python:

$ which python3
>> /home/user/.virtualenvs/ENV_NAME/bin/python3

回答 11

如果您更改python项目的目录结构,也会发生这种情况(我是这样做的,然后对行为的变化感到困惑)。如果这样做,则需要在/ bin / activate文件中更改一行。所以,说您的项目在

/User/me/CodeProjects/coolApp/

并且您的激活文件位于

/User/me/CodeProjects/coolApp/venv/bin/activate

设置项目时,将项目更改为

/User/me/CodeProjects/v1-coolApp/

或者其他的东西。然后,您需要打开

/User/me/CodeProjects/v1-coolApp/venv/bin/activate

找到它说的那一行

VIRTUAL_ENV="/User/me/CodeProjects/coolApp"
export VIRTUAL_ENV

并将其更改为

VIRTUAL_ENV="/User/me/CodeProjects/v1-coolApp"

重新激活之前

This also happens if you change the directory structure of your python project (I did this, and then puzzled over the change in behavior). If you do so, you’ll need to change a line in your /bin/activate file. So, say your project was at

/User/me/CodeProjects/coolApp/

and your activate file is at

/User/me/CodeProjects/coolApp/venv/bin/activate

when you set up your project, then you changed your project to

/User/me/CodeProjects/v1-coolApp/

or something. You would then need to open

/User/me/CodeProjects/v1-coolApp/venv/bin/activate

find the line where it says

VIRTUAL_ENV="/User/me/CodeProjects/coolApp"
export VIRTUAL_ENV

and change it to

VIRTUAL_ENV="/User/me/CodeProjects/v1-coolApp"

before reactivating


回答 12

就我而言,我正在使用Ubuntu。问题可能是我没有以普通用户身份写入该文件夹的权限。您只需sudo在命令前添加即可,它应该可以正常运行。就我而言sudo python manage.py syncdb

In my case, I am using Ubuntu. The problem can be that I don’t have the permission to write to that folder as a normal user. You can simply add the sudo before your command and it should work perfectly. In my case sudo python manage.py syncdb.


回答 13

我有同样的问题,收到此消息的原因是因为我正在执行“ manage.py runserver”,而在执行“ python manage.py runserver”时已将其修复。

I had the same issue and the reason I was getting this message was because I was doing “manage.py runserver” whereas doing “python manage.py runserver” fixed it.


回答 14

我遇到了同样的问题,下面的工作很好,您应该在项目中浏览主文件夹,而不要键入:

source bin/activate 

I had the same problem and following worked good, you should navigate main folder in your project than type:

source bin/activate 

回答 15

具有相同的问题。以root身份运行命令’python manage.py migration’。可以与root访问一起正常工作(sudo python manage.py migrate)

had the same problem.run command ‘python manage.py migrate’ as root. works fine with root access (sudo python manage.py migrate )


回答 16

我的情况是在Mac上使用pyCharm 5。我也遇到这个问题,运行此命令后,我的问题解决了

sudo pip install django --upgrade 

My case I used pyCharm 5 on mac. I also had this problem and after running this command my problem was solved

sudo pip install django --upgrade 

回答 17

您可以这样尝试:(python3 manage.py migrate使sur位于src/目录中)

您也可以尝试使用pip install -r requirements.txt(使您在迁移后输入requirements.txt时看到文件ls

如果毕竟还是不行,请尝试 pip install django

希望能帮助到你

You can try it like so : python3 manage.py migrate (make sur to be in the src/ directory)

You can also try with pip install -r requirements.txt (make sur you see the requirements.txt file when you type ls after the migrate

If after all it still won’t work try pip install django

Hope it helps


回答 18

您必须先选择项目,workon your_project_name 然后再运行服务器,然后 键入 python manage.py runserver

You must choose your Project first before running the server , type this workon your_project_name then python manage.py runserver


回答 19

文件和目录所有权冲突将在此处引起问题。确保项目下目录和文件的所有权属于当前用户。(您可以使用带有-R选项的chown命令来更改它们。)尝试重新运行该命令:这在通过“ First Django App”示例运行时为我解决了问题:

python manage.py startapp polls

File and Directory ownership conflict will cause issues here. Make sure the ownership of the directories and files under the project are to the current user. (You can change them using the chown command with the -R option.) Try rerunning the command: this solved the problem for me when running through the “First Django App” sample:

python manage.py startapp polls

回答 20

我在尝试使用python manage.py runserver时遇到了同样的问题。就我而言,我只使用sudo su。将终端机用作根用户,然后重试一次,可以部分使用。因此,我使用 python manage.py migration comand进行了修复。

I got the same problem trying to use the python manage.py runserver. In my case I just use sudo su. Use the terminal as a root and try it again an it works partially. So I use python manage.py migrate comand and it fix it.


如何从Django框架的表单字段中获取价值?

问题:如何从Django框架的表单字段中获取价值?

如何从Django框架的表单字段中获取值?我想在视图中执行此操作,而不是在模板中执行此操作…

How do I get values from form fields in the django framework? I want to do this in views, not in templates…


回答 0

在视图中使用表单几乎可以解释这一点。

在视图中处理表单的标准模式如下所示:

def contact(request):
    if request.method == 'POST': # If the form has been submitted...
        form = ContactForm(request.POST) # A form bound to the POST data
        if form.is_valid(): # All validation rules pass
            # Process the data in form.cleaned_data
            # ...

            print form.cleaned_data['my_form_field_name']

            return HttpResponseRedirect('/thanks/') # Redirect after POST
    else:
        form = ContactForm() # An unbound form

    return render_to_response('contact.html', {
        'form': form,
    })

Using a form in a view pretty much explains it.

The standard pattern for processing a form in a view looks like this:

def contact(request):
    if request.method == 'POST': # If the form has been submitted...
        form = ContactForm(request.POST) # A form bound to the POST data
        if form.is_valid(): # All validation rules pass
            # Process the data in form.cleaned_data
            # ...

            print form.cleaned_data['my_form_field_name']

            return HttpResponseRedirect('/thanks/') # Redirect after POST
    else:
        form = ContactForm() # An unbound form

    return render_to_response('contact.html', {
        'form': form,
    })

回答 1

选择:

def my_view(request):

    if request.method == 'POST':
        print request.POST.get('my_field')

        form = MyForm(request.POST)

        print form['my_field'].value()
        print form.data['my_field']

        if form.is_valid():

            print form.cleaned_data['my_field']
            print form.instance.my_field

            form.save()
            print form.instance.id  # now this one can access id/pk

注意:该字段可用时将立即对其进行访问。

Take your pick:

def my_view(request):

    if request.method == 'POST':
        print request.POST.get('my_field')

        form = MyForm(request.POST)

        print form['my_field'].value()
        print form.data['my_field']

        if form.is_valid():

            print form.cleaned_data['my_field']
            print form.instance.my_field

            form.save()
            print form.instance.id  # now this one can access id/pk

Note: the field is accessed as soon as it’s available.


回答 2

您可以在验证数据后执行此操作。

if myform.is_valid():
  data = myform.cleaned_data
  field = data['field']

另外,请阅读django文档。他们是完美的。

You can do this after you validate your data.

if myform.is_valid():
  data = myform.cleaned_data
  field = data['field']

Also, read the django docs. They are perfect.


回答 3

要从发送过帐请求的表单中检索数据,您可以像这样

def login_view(request):
    if(request.POST):
        login_data = request.POST.dict()
        username = login_data.get("username")
        password = login_data.get("password")
        user_type = login_data.get("user_type")
        print(user_type, username, password)
        return HttpResponse("This is a post request")
    else:
        return render(request, "base.html")

To retrieve data from form which send post request you can do it like this

def login_view(request):
    if(request.POST):
        login_data = request.POST.dict()
        username = login_data.get("username")
        password = login_data.get("password")
        user_type = login_data.get("user_type")
        print(user_type, username, password)
        return HttpResponse("This is a post request")
    else:
        return render(request, "base.html")

回答 4

我使用django 1.7+和python 2.7+,以上解决方案不起作用。表格中的输入值可以使用POST如下获取(使用与上面相同的表格):

if form.is_valid():
  data = request.POST.get('my_form_field_name')
  print data

希望这可以帮助。

I use django 1.7+ and python 2.7+, the solution above dose not work. And the input value in the form can be got use POST as below (use the same form above):

if form.is_valid():
  data = request.POST.get('my_form_field_name')
  print data

Hope this helps.


如何在Django中动态组成OR查询过滤器?

问题:如何在Django中动态组成OR查询过滤器?

从一个示例中,您可以看到一个多重或查询过滤器:

Article.objects.filter(Q(pk=1) | Q(pk=2) | Q(pk=3))

例如,这导致:

[<Article: Hello>, <Article: Goodbye>, <Article: Hello and goodbye>]

但是,我想从列表中创建此查询过滤器。怎么做?

例如 [1, 2, 3] -> Article.objects.filter(Q(pk=1) | Q(pk=2) | Q(pk=3))

From an example you can see a multiple OR query filter:

Article.objects.filter(Q(pk=1) | Q(pk=2) | Q(pk=3))

For example, this results in:

[<Article: Hello>, <Article: Goodbye>, <Article: Hello and goodbye>]

However, I want to create this query filter from a list. How to do that?

e.g. [1, 2, 3] -> Article.objects.filter(Q(pk=1) | Q(pk=2) | Q(pk=3))


回答 0

您可以按以下方式链接查询:

values = [1,2,3]

# Turn list of values into list of Q objects
queries = [Q(pk=value) for value in values]

# Take one Q object from the list
query = queries.pop()

# Or the Q object with the ones remaining in the list
for item in queries:
    query |= item

# Query the model
Article.objects.filter(query)

You could chain your queries as follows:

values = [1,2,3]

# Turn list of values into list of Q objects
queries = [Q(pk=value) for value in values]

# Take one Q object from the list
query = queries.pop()

# Or the Q object with the ones remaining in the list
for item in queries:
    query |= item

# Query the model
Article.objects.filter(query)

回答 1

要构建更复杂的查询,还可以选择使用内置Q()对象的常量Q.OR和Q.AND以及add()方法,如下所示:

list = [1, 2, 3]
# it gets a bit more complicated if we want to dynamically build
# OR queries with dynamic/unknown db field keys, let's say with a list
# of db fields that can change like the following
# list_with_strings = ['dbfield1', 'dbfield2', 'dbfield3']

# init our q objects variable to use .add() on it
q_objects = Q(id__in=[])

# loop trough the list and create an OR condition for each item
for item in list:
    q_objects.add(Q(pk=item), Q.OR)
    # for our list_with_strings we can do the following
    # q_objects.add(Q(**{item: 1}), Q.OR)

queryset = Article.objects.filter(q_objects)

# sometimes the following is helpful for debugging (returns the SQL statement)
# print queryset.query

To build more complex queries there is also the option to use built in Q() object’s constants Q.OR and Q.AND together with the add() method like so:

list = [1, 2, 3]
# it gets a bit more complicated if we want to dynamically build
# OR queries with dynamic/unknown db field keys, let's say with a list
# of db fields that can change like the following
# list_with_strings = ['dbfield1', 'dbfield2', 'dbfield3']

# init our q objects variable to use .add() on it
q_objects = Q(id__in=[])

# loop trough the list and create an OR condition for each item
for item in list:
    q_objects.add(Q(pk=item), Q.OR)
    # for our list_with_strings we can do the following
    # q_objects.add(Q(**{item: 1}), Q.OR)

queryset = Article.objects.filter(q_objects)

# sometimes the following is helpful for debugging (returns the SQL statement)
# print queryset.query

回答 2

使用python的reduce函数编写Dave Webb答案的更短方法:

# For Python 3 only
from functools import reduce

values = [1,2,3]

# Turn list of values into one big Q objects  
query = reduce(lambda q,value: q|Q(pk=value), values, Q())  

# Query the model  
Article.objects.filter(query)  

A shorter way of writing Dave Webb’s answer using python’s reduce function:

# For Python 3 only
from functools import reduce

values = [1,2,3]

# Turn list of values into one big Q objects  
query = reduce(lambda q,value: q|Q(pk=value), values, Q())  

# Query the model  
Article.objects.filter(query)  

回答 3

from functools import reduce
from operator import or_
from django.db.models import Q

values = [1, 2, 3]
query = reduce(or_, (Q(pk=x) for x in values))
from functools import reduce
from operator import or_
from django.db.models import Q

values = [1, 2, 3]
query = reduce(or_, (Q(pk=x) for x in values))

回答 4

也许最好使用sql IN语句。

Article.objects.filter(id__in=[1, 2, 3])

请参阅queryset api参考

如果您确实需要使用动态逻辑进行查询,则可以执行以下操作(丑陋且未经测试):

query = Q(field=1)
for cond in (2, 3):
    query = query | Q(field=cond)
Article.objects.filter(query)

Maybe it’s better to use sql IN statement.

Article.objects.filter(id__in=[1, 2, 3])

See queryset api reference.

If you really need to make queries with dynamic logic, you can do something like this (ugly + not tested):

query = Q(field=1)
for cond in (2, 3):
    query = query | Q(field=cond)
Article.objects.filter(query)

回答 5

文档

>>> Blog.objects.in_bulk([1])
{1: <Blog: Beatles Blog>}
>>> Blog.objects.in_bulk([1, 2])
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>}
>>> Blog.objects.in_bulk([])
{}

请注意,此方法仅适用于主键查找,但这似乎就是您要尝试的方法。

因此,您想要的是:

Article.objects.in_bulk([1, 2, 3])

See the docs:

>>> Blog.objects.in_bulk([1])
{1: <Blog: Beatles Blog>}
>>> Blog.objects.in_bulk([1, 2])
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>}
>>> Blog.objects.in_bulk([])
{}

Note that this method only works for primary key lookups, but that seems to be what you’re trying to do.

So what you want is:

Article.objects.in_bulk([1, 2, 3])

回答 6

如果我们要以编程方式设置要查询的数据库字段:

import operator
questions = [('question__contains', 'test'), ('question__gt', 23 )]
q_list = [Q(x) for x in questions]
Poll.objects.filter(reduce(operator.or_, q_list))

In case we want to programmatically set what db field we want to query:

import operator
questions = [('question__contains', 'test'), ('question__gt', 23 )]
q_list = [Q(x) for x in questions]
Poll.objects.filter(reduce(operator.or_, q_list))

回答 7

使用reduceor_运算符按乘法字段进行过滤的解决方案。

from functools import reduce
from operator import or_
from django.db.models import Q

filters = {'field1': [1, 2], 'field2': ['value', 'other_value']}

qs = Article.objects.filter(
   reduce(or_, (Q(**{f'{k}__in': v}) for k, v in filters.items()))
)

ps f是一种新的格式字符串文字。它是在python 3.6中引入的

Solution which use reduce and or_ operators to filter by multiply fields.

from functools import reduce
from operator import or_
from django.db.models import Q

filters = {'field1': [1, 2], 'field2': ['value', 'other_value']}

qs = Article.objects.filter(
   reduce(or_, (Q(**{f'{k}__in': v}) for k, v in filters.items()))
)

p.s. f is a new format strings literal. It was introduced in python 3.6


回答 8

您可以使用| =运算符来使用Q对象以编程方式更新查询。

You can use the |= operator to programmatically update a query using Q objects.


回答 9

这是动态pk列表:

pk_list = qs.values_list('pk', flat=True)  # i.e [] or [1, 2, 3]

if len(pk_list) == 0:
    Article.objects.none()

else:
    q = None
    for pk in pk_list:
        if q is None:
            q = Q(pk=pk)
        else:
            q = q | Q(pk=pk)

    Article.objects.filter(q)

This one is for dynamic pk list:

pk_list = qs.values_list('pk', flat=True)  # i.e [] or [1, 2, 3]

if len(pk_list) == 0:
    Article.objects.none()

else:
    q = None
    for pk in pk_list:
        if q is None:
            q = Q(pk=pk)
        else:
            q = q | Q(pk=pk)

    Article.objects.filter(q)

回答 10

另一种选择我是不知道的直到最近- QuerySet还覆盖了&|~,等运营商。OR Q对象的其他答案是对该问题的更好解决方案,但是出于兴趣/观点的考虑,您可以执行以下操作:

id_list = [1, 2, 3]
q = Article.objects.filter(pk=id_list[0])
for i in id_list[1:]:
    q |= Article.objects.filter(pk=i)

str(q.query)将返回一个查询,其中包含WHERE子句中的所有过滤器。

Another option I wasn’t aware of until recently – QuerySet also overrides the &, |, ~, etc, operators. The other answers that OR Q objects are a better solution to this question, but for the sake of interest/argument, you can do:

id_list = [1, 2, 3]
q = Article.objects.filter(pk=id_list[0])
for i in id_list[1:]:
    q |= Article.objects.filter(pk=i)

str(q.query) will return one query with all the filters in the WHERE clause.


回答 11

对于循环:

values = [1, 2, 3]
q = Q(pk__in=[]) # generic "always false" value
for val in values:
    q |= Q(pk=val)
Article.objects.filter(q)

减少:

from functools import reduce
from operator import or_

values = [1, 2, 3]
q_objects = [Q(pk=val) for val in values]
q = reduce(or_, q_objects, Q(pk__in=[]))
Article.objects.filter(q)

这两个都相当于 Article.objects.filter(pk__in=values)

values空着时要考虑什么很重要。许多Q()以起始值开头的答案将返回所有内容Q(pk__in=[])是一个更好的起点。这是一个始终失败的Q对象,优化器可以很好地处理它(即使对于复杂的方程式)。

Article.objects.filter(Q(pk__in=[]))  # doesn't hit DB
Article.objects.filter(Q(pk=None))    # hits DB and returns nothing
Article.objects.none()                # doesn't hit DB
Article.objects.filter(Q())           # returns everything

如果values为空时返回所有内容,则应进行AND操作~Q(pk__in=[])以确保该行为:

values = []
q = Q()
for val in values:
    q |= Q(pk=val)
Article.objects.filter(q)                     # everything
Article.objects.filter(q | author="Tolkien")  # only Tolkien

q &= ~Q(pk__in=[])
Article.objects.filter(q)                     # everything
Article.objects.filter(q | author="Tolkien")  # everything

重要的是要记住,什么都不Q()是,不是一个总是成功的Q对象。涉及此操作的任何操作都会将其完全删除。

For loop:

values = [1, 2, 3]
q = Q(pk__in=[]) # generic "always false" value
for val in values:
    q |= Q(pk=val)
Article.objects.filter(q)

Reduce:

from functools import reduce
from operator import or_

values = [1, 2, 3]
q_objects = [Q(pk=val) for val in values]
q = reduce(or_, q_objects, Q(pk__in=[]))
Article.objects.filter(q)

Both of these are equivalent to Article.objects.filter(pk__in=values)

It’s important to consider what you want when values is empty. Many answers with Q() as a starting value will return everything. Q(pk__in=[]) is a better starting value. It’s an always-failing Q object that’s handled nicely by the optimizer (even for complex equations).

Article.objects.filter(Q(pk__in=[]))  # doesn't hit DB
Article.objects.filter(Q(pk=None))    # hits DB and returns nothing
Article.objects.none()                # doesn't hit DB
Article.objects.filter(Q())           # returns everything

If you want to return everything when values is empty, you should AND with ~Q(pk__in=[]) to ensure that behaviour:

values = []
q = Q()
for val in values:
    q |= Q(pk=val)
Article.objects.filter(q)                     # everything
Article.objects.filter(q | author="Tolkien")  # only Tolkien

q &= ~Q(pk__in=[])
Article.objects.filter(q)                     # everything
Article.objects.filter(q | author="Tolkien")  # everything

It’s important to remember that Q() is nothing, not an always-succeeding Q object. Any operation involving it will just drop it completely.


回答 12

easy ..
from django.db.models import Q import your model args =(Q(visibility = 1)|(Q(visibility = 0)&Q(user = self.user)))#元组参数= {} #dic顺序=’create_at’限制= 10

Models.objects.filter(*args,**parameters).order_by(order)[:limit]

easy..
from django.db.models import Q import you model args = (Q(visibility=1)|(Q(visibility=0)&Q(user=self.user))) #Tuple parameters={} #dic order = ‘create_at’ limit = 10

Models.objects.filter(*args,**parameters).order_by(order)[:limit]

使Django的login_required为默认值的最佳方法

问题:使Django的login_required为默认值的最佳方法

我正在开发一个大型Django应用程序,其中绝大多数需要登录才能访问。这意味着我们在整个应用程序中都花了很多钱:

@login_required
def view(...):

很好,只要我们记得将其添加到任何地方,它就可以很好地工作!可悲的是,有时我们忘记了,而且失败往往不是很明显。如果到视图的唯一链接是在@login_required页面上,则您不太可能注意到实际上无需登录即可进入该视图。但是,坏人可能会注意到,这是一个问题。

我的想法是反转系统。不必在任何地方键入@login_required,而是有类似以下内容:

@public
def public_view(...):

仅用于公共物品。我尝试使用一些中间件来实现它,但似乎无法使它正常工作。我认为,我尝试的所有内容都与我们正在使用的其他中间件进行了严重的交互。接下来,我尝试编写一些内容来遍历URL模式,以检查是否所有非@public都标记为@login_required-至少如果忘记了某些内容,我们将很快得到错误提示。但是后来我不知道如何判断@login_required是否已应用于视图…

那么,什么是正确的方法呢?谢谢您的帮助!

I’m working on a large Django app, the vast majority of which requires a login to access. This means that all throughout our app we’ve sprinkled:

@login_required
def view(...):

That’s fine, and it works great as long as we remember to add it everywhere! Sadly sometimes we forget, and the failure often isn’t terribly evident. If the only link to a view is on a @login_required page then you’re not likely to notice that you can actually reach that view without logging in. But the bad guys might notice, which is a problem.

My idea was to reverse the system. Instead of having to type @login_required everywhere, instead I’d have something like:

@public
def public_view(...):

Just for the public stuff. I tried to implement this with some middleware and I couldn’t seem to get it to work. Everything I tried interacted badly with other middleware we’re using, I think. Next up I tried writing something to traverse the URL patterns to check that everything that’s not @public was marked @login_required – at least then we’d get a quick error if we forgot something. But then I couldn’t figure out how to tell if @login_required had been applied to a view…

So, what’s the right way to do this? Thanks for the help!


回答 0

中间件可能是您最好的选择。我过去使用过这段代码,是在其他地方的代码段中进行了修改:

import re

from django.conf import settings
from django.contrib.auth.decorators import login_required


class RequireLoginMiddleware(object):
    """
    Middleware component that wraps the login_required decorator around
    matching URL patterns. To use, add the class to MIDDLEWARE_CLASSES and
    define LOGIN_REQUIRED_URLS and LOGIN_REQUIRED_URLS_EXCEPTIONS in your
    settings.py. For example:
    ------
    LOGIN_REQUIRED_URLS = (
        r'/topsecret/(.*)$',
    )
    LOGIN_REQUIRED_URLS_EXCEPTIONS = (
        r'/topsecret/login(.*)$',
        r'/topsecret/logout(.*)$',
    )
    ------
    LOGIN_REQUIRED_URLS is where you define URL patterns; each pattern must
    be a valid regex.

    LOGIN_REQUIRED_URLS_EXCEPTIONS is, conversely, where you explicitly
    define any exceptions (like login and logout URLs).
    """
    def __init__(self):
        self.required = tuple(re.compile(url) for url in settings.LOGIN_REQUIRED_URLS)
        self.exceptions = tuple(re.compile(url) for url in settings.LOGIN_REQUIRED_URLS_EXCEPTIONS)

    def process_view(self, request, view_func, view_args, view_kwargs):
        # No need to process URLs if user already logged in
        if request.user.is_authenticated():
            return None

        # An exception match should immediately return None
        for url in self.exceptions:
            if url.match(request.path):
                return None

        # Requests matching a restricted URL pattern are returned
        # wrapped with the login_required decorator
        for url in self.required:
            if url.match(request.path):
                return login_required(view_func)(request, *view_args, **view_kwargs)

        # Explicitly return None for all non-matching requests
        return None

然后在settings.py中,列出您要保护的基本URL:

LOGIN_REQUIRED_URLS = (
    r'/private_stuff/(.*)$',
    r'/login_required/(.*)$',
)

只要您的站点遵循要求身份验证的页面的URL约定,此模型就可以工作。如果这不是一对一的适合,您可以选择修改中间件以更紧密地适应您的情况。

我喜欢这种方法-除了消除了用@login_required修饰符乱填充代码库的必要性外,还在于,如果身份验证方案发生更改,那么您还有一个地方可以进行全局更改。

Middleware may be your best bet. I’ve used this piece of code in the past, modified from a snippet found elsewhere:

import re

from django.conf import settings
from django.contrib.auth.decorators import login_required


class RequireLoginMiddleware(object):
    """
    Middleware component that wraps the login_required decorator around
    matching URL patterns. To use, add the class to MIDDLEWARE_CLASSES and
    define LOGIN_REQUIRED_URLS and LOGIN_REQUIRED_URLS_EXCEPTIONS in your
    settings.py. For example:
    ------
    LOGIN_REQUIRED_URLS = (
        r'/topsecret/(.*)$',
    )
    LOGIN_REQUIRED_URLS_EXCEPTIONS = (
        r'/topsecret/login(.*)$',
        r'/topsecret/logout(.*)$',
    )
    ------
    LOGIN_REQUIRED_URLS is where you define URL patterns; each pattern must
    be a valid regex.

    LOGIN_REQUIRED_URLS_EXCEPTIONS is, conversely, where you explicitly
    define any exceptions (like login and logout URLs).
    """
    def __init__(self):
        self.required = tuple(re.compile(url) for url in settings.LOGIN_REQUIRED_URLS)
        self.exceptions = tuple(re.compile(url) for url in settings.LOGIN_REQUIRED_URLS_EXCEPTIONS)

    def process_view(self, request, view_func, view_args, view_kwargs):
        # No need to process URLs if user already logged in
        if request.user.is_authenticated():
            return None

        # An exception match should immediately return None
        for url in self.exceptions:
            if url.match(request.path):
                return None

        # Requests matching a restricted URL pattern are returned
        # wrapped with the login_required decorator
        for url in self.required:
            if url.match(request.path):
                return login_required(view_func)(request, *view_args, **view_kwargs)

        # Explicitly return None for all non-matching requests
        return None

Then in settings.py, list the base URLs you want to protect:

LOGIN_REQUIRED_URLS = (
    r'/private_stuff/(.*)$',
    r'/login_required/(.*)$',
)

As long as your site follows URL conventions for the pages requiring authentication, this model will work. If this isn’t a one-to-one fit, you may choose to modify the middleware to suit your circumstances more closely.

What I like about this approach – besides removing the necessity of littering the codebase with @login_required decorators – is that if the authentication scheme changes, you have one place to go to make global changes.


回答 1

除了在每个视图函数上放置装饰器之外,还有另一种方法。您也可以将login_required()装饰器放入urls.py文件中。尽管这仍然是一项手动任务,但至少您将所有功能都集中在一个地方,这使得审核更加容易。

例如,

    从my_views导入home_view

    urlpatterns = pattern('',
        #“首页”:
        (r'^ $',login_required(home_view),dict(template_name ='my_site / home.html',items_per_page = 20)),
    )

请注意,视图函数是直接命名和导入的,而不是字符串。

还要注意,这适用于任何可调用的视图对象,包括类。

There is an alternative to putting a decorator on each view function. You can also put the login_required() decorator in the urls.py file. While this is still a manual task, at least you have it all in one place, which makes it easier to audit.

e.g.,

    from my_views import home_view

    urlpatterns = patterns('',
        # "Home":
        (r'^$', login_required(home_view), dict(template_name='my_site/home.html', items_per_page=20)),
    )

Note that view functions are named and imported directly, not as strings.

Also note that this works with any callable view object, including classes.


回答 2

在Django 2.1中,我们可以使用以下方法装饰类中的所有方法

from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView

@method_decorator(login_required, name='dispatch')
class ProtectedView(TemplateView):
    template_name = 'secret.html'

更新: 我还发现以下工作:

from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import TemplateView

class ProtectedView(LoginRequiredMixin, TemplateView):
    template_name = 'secret.html'

LOGIN_URL = '/accounts/login/'在您的settings.py中进行设置

In Django 2.1, we can decorate all methods in a class with:

from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView

@method_decorator(login_required, name='dispatch')
class ProtectedView(TemplateView):
    template_name = 'secret.html'

UPDATE: I have also found the following to work:

from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import TemplateView

class ProtectedView(LoginRequiredMixin, TemplateView):
    template_name = 'secret.html'

and set LOGIN_URL = '/accounts/login/' in your settings.py


回答 3

如果不修改url传递给视图函数的方式,就很难更改Django中的内置假设。

您可以使用审计来代替Django内部的混乱。只需检查每个视图功能。

import os
import re

def view_modules( root ):
    for path, dirs, files in os.walk( root ):
        for d in dirs[:]:
            if d.startswith("."):
                dirs.remove(d)
        for f in files:
            name, ext = os.path.splitext(f)
            if ext == ".py":
                if name == "views":
                    yield os.path.join( path, f )

def def_lines( root ):
    def_pat= re.compile( "\n(\S.*)\n+(^def\s+.*:$)", re.MULTILINE )
    for v in view_modules( root ):
        with open(v,"r") as source:
            text= source.read()
            for p in def_pat.findall( text ):
                yield p

def report( root ):
    for decorator, definition in def_lines( root ):
        print decorator, definition

运行此命令,并在def没有适当修饰符的情况下检查输出的。

It’s hard to change the built-in assumptions in Django without reworking the way url’s are handed off to view functions.

Instead of mucking about in Django internals, here’s an audit you can use. Simply check each view function.

import os
import re

def view_modules( root ):
    for path, dirs, files in os.walk( root ):
        for d in dirs[:]:
            if d.startswith("."):
                dirs.remove(d)
        for f in files:
            name, ext = os.path.splitext(f)
            if ext == ".py":
                if name == "views":
                    yield os.path.join( path, f )

def def_lines( root ):
    def_pat= re.compile( "\n(\S.*)\n+(^def\s+.*:$)", re.MULTILINE )
    for v in view_modules( root ):
        with open(v,"r") as source:
            text= source.read()
            for p in def_pat.findall( text ):
                yield p

def report( root ):
    for decorator, definition in def_lines( root ):
        print decorator, definition

Run this and examine the output for defs without appropriate decorators.


回答 4

这是Django 1.10+的中间件解决方案

必须使用django 1.10+中的新方式编写其中的中间件。

import re

from django.conf import settings
from django.contrib.auth.decorators import login_required


class RequireLoginMiddleware(object):

    def __init__(self, get_response):
         # One-time configuration and initialization.
        self.get_response = get_response

        self.required = tuple(re.compile(url)
                              for url in settings.LOGIN_REQUIRED_URLS)
        self.exceptions = tuple(re.compile(url)
                                for url in settings.LOGIN_REQUIRED_URLS_EXCEPTIONS)

    def __call__(self, request):

        response = self.get_response(request)
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):

        # No need to process URLs if user already logged in
        if request.user.is_authenticated:
            return None

        # An exception match should immediately return None
        for url in self.exceptions:
            if url.match(request.path):
                return None

        # Requests matching a restricted URL pattern are returned
        # wrapped with the login_required decorator
        for url in self.required:
            if url.match(request.path):
                return login_required(view_func)(request, *view_args, **view_kwargs)

        # Explicitly return None for all non-matching requests
        return None

安装

  1. 将代码复制到您的项目文件夹中,并另存为middleware.py
  2. 添加到MIDDLEWARE

    MIDDLEWARE = […’.middleware.RequireLoginMiddleware’,#要求登录]

  3. 添加到您的settings.py:
LOGIN_REQUIRED_URLS = (
    r'(.*)',
)
LOGIN_REQUIRED_URLS_EXCEPTIONS = (
    r'/admin(.*)$',
)
LOGIN_URL = '/admin'

资料来源:

  1. Daniel Naab的答案

  2. Max Goodridge的Django中间件教程

  3. Django中间件文档

Here is a middleware solution for django 1.10+

The middlewares in have to be written in a new way in django 1.10+.

Code

import re

from django.conf import settings
from django.contrib.auth.decorators import login_required


class RequireLoginMiddleware(object):

    def __init__(self, get_response):
         # One-time configuration and initialization.
        self.get_response = get_response

        self.required = tuple(re.compile(url)
                              for url in settings.LOGIN_REQUIRED_URLS)
        self.exceptions = tuple(re.compile(url)
                                for url in settings.LOGIN_REQUIRED_URLS_EXCEPTIONS)

    def __call__(self, request):

        response = self.get_response(request)
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):

        # No need to process URLs if user already logged in
        if request.user.is_authenticated:
            return None

        # An exception match should immediately return None
        for url in self.exceptions:
            if url.match(request.path):
                return None

        # Requests matching a restricted URL pattern are returned
        # wrapped with the login_required decorator
        for url in self.required:
            if url.match(request.path):
                return login_required(view_func)(request, *view_args, **view_kwargs)

        # Explicitly return None for all non-matching requests
        return None

Installation

  1. Copy the code into your project folder, and save as middleware.py
  2. Add to MIDDLEWARE

    MIDDLEWARE = [ … ‘.middleware.RequireLoginMiddleware’, # Require login ]

  3. Add to your settings.py:
LOGIN_REQUIRED_URLS = (
    r'(.*)',
)
LOGIN_REQUIRED_URLS_EXCEPTIONS = (
    r'/admin(.*)$',
)
LOGIN_URL = '/admin'

Sources:

  1. This answer by Daniel Naab

  2. Django Middleware tutorial by Max Goodridge

  3. Django Middleware Docs


回答 5

受Ber的回答启发,我编写了一个小片段来替换该patterns函数,方法是将所有URL回调都包装在login_required装饰器中。这在Django 1.6中有效。

def login_required_patterns(*args, **kw):
    for pattern in patterns(*args, **kw):
        # This is a property that should return a callable, even if a string view name is given.
        callback = pattern.callback

        # No property setter is provided, so this will have to do.
        pattern._callback = login_required(callback)

        yield pattern

使用它的方式是这样的(list由于,必须调用yield)。

urlpatterns = list(login_required_patterns('', url(r'^$', home_view)))

Inspired by Ber’s answer I wrote a little snippet that replaces the patterns function, by wrapping all of the URL callbacks with the login_required decorator. This works in Django 1.6.

def login_required_patterns(*args, **kw):
    for pattern in patterns(*args, **kw):
        # This is a property that should return a callable, even if a string view name is given.
        callback = pattern.callback

        # No property setter is provided, so this will have to do.
        pattern._callback = login_required(callback)

        yield pattern

Using it works like this (the call to list is required because of the yield).

urlpatterns = list(login_required_patterns('', url(r'^$', home_view)))

回答 6

你不能真正赢得这场胜利。您只需必须做出的授权要求的声明。除了在视图函数中正确的位置之外,您还将把此声明放在哪里?

考虑用可调用对象替换视图函数。

class LoginViewFunction( object ):
    def __call__( self, request, *args, **kw ):
        p1 = self.login( request, *args, **kw )
        if p1 is not None:
            return p1
        return self.view( request, *args, **kw )
    def login( self, request )
        if not request.user.is_authenticated():
            return HttpResponseRedirect('/login/?next=%s' % request.path)
    def view( self, request, *args, **kw ):
        raise NotImplementedError

然后,将您的视图函数设为的子类LoginViewFunction

class MyRealView( LoginViewFunction ):
    def view( self, request, *args, **kw ):
        .... the real work ...

my_real_view = MyRealView()  

它不保存任何代码行。而且这对解决“我们忘记了”的问题没有帮助。您所要做的就是检查代码,以确保视图函数是对象。正确的阶级。

但是即使那样,您也永远不会真正知道 没有单元测试套件每个视图功能都是正确的。

You can’t really win this. You simply must make a declaration of the authorization requirements. Where else would you put this declaration except right by the view function?

Consider replacing your view functions with callable objects.

class LoginViewFunction( object ):
    def __call__( self, request, *args, **kw ):
        p1 = self.login( request, *args, **kw )
        if p1 is not None:
            return p1
        return self.view( request, *args, **kw )
    def login( self, request )
        if not request.user.is_authenticated():
            return HttpResponseRedirect('/login/?next=%s' % request.path)
    def view( self, request, *args, **kw ):
        raise NotImplementedError

You then make your view functions subclasses of LoginViewFunction.

class MyRealView( LoginViewFunction ):
    def view( self, request, *args, **kw ):
        .... the real work ...

my_real_view = MyRealView()  

It doesn’t save any lines of code. And it doesn’t help the “we forgot” problem. All you can do is examine the code to be sure that the view functions are objects. Of the right class.

But even then, you’ll never really know that every view function is correct without a unit test suite.


回答 7

可能会为所有包含一个单一起点urls,并使用此包https://github.com/vorujack/decorate_url装饰它。

Would be possible to have a single starting point for all the urls in a sort of include and that decorate it using this packages https://github.com/vorujack/decorate_url.


回答 8

有一个应用程序为此提供了即插即用的解决方案:

https://github.com/mgrouchy/django-stronghold

pip install django-stronghold
# settings.py

INSTALLED_APPS = (
    #...
    'stronghold',
)

MIDDLEWARE_CLASSES = (
    #...
    'stronghold.middleware.LoginRequiredMiddleware',
)

There’s an app that provides a plug-and-play solution to this:

https://github.com/mgrouchy/django-stronghold

pip install django-stronghold
# settings.py

INSTALLED_APPS = (
    #...
    'stronghold',
)

MIDDLEWARE_CLASSES = (
    #...
    'stronghold.middleware.LoginRequiredMiddleware',
)

如何在Django模板中进行数学运算?

问题:如何在Django模板中进行数学运算?

我想做这个:

100 - {{ object.article.rating_score }} 

因此,例如,输出将是20,如果{{ object.article.rating_score }}追平80

如何在模板级别执行此操作?我无权访问Python代码。

I want to do this:

100 - {{ object.article.rating_score }} 

So for example, the output would be 20 if {{ object.article.rating_score }} equaled 80.

How do I do this at the template level? I don’t have access to the Python code.


回答 0

您可以使用add过滤器:

{{ object.article.rating_score|add:"-100" }}

You can use the add filter:

{{ object.article.rating_score|add:"-100" }}

回答 1

使用django-mathfilters。除了内置的添加过滤器外,它还提供了过滤器以减去,相乘,除以和取绝对值。

对于上面的特定示例,您可以使用{{ 100|sub:object.article.rating_score }}

Use django-mathfilters. In addition to the built-in add filter, it provides filters to subtract, multiply, divide, and take the absolute value.

For the specific example above, you would use {{ 100|sub:object.article.rating_score }}.


回答 2

通常,建议您在视图中进行此计算。否则,您可以使用添加过滤器。

Generally it is recommended you do this calculation in your view. Otherwise, you could use the add filter.


ContentType和MimeType有什么区别

问题:ContentType和MimeType有什么区别

据我所知,它们是绝对平等的。但是,浏览一些django文档,我发现了这段代码:

HttpResponse.__init__(content='', mimetype=None, status=200, content_type='text/html')

令我惊讶的是两个人相处得很好。官方文档能够以实用的方式解决此问题:

content_type是mimetype的别名。从历史上讲,此参数仅称为mimetype,但是由于它实际上是HTTP Content-Type标头中包含的值,因此它还可以包含字符集编码,这使其不仅限于MIME类型规范。如果指定了mimetype(不是None),则使用该值。否则,将使用content_type。如果两者都不给出,则使用DEFAULT_CONTENT_TYPE设置。

但是,我认为它不够清楚。为什么我们为(几乎相同的)事物使用2种不同的命名?“ Content-Type”只是浏览器请求中使用的名称,而在其外部很少使用吗?

两者之间的主要区别是什么,什么时候可以打电话给对方mimetype而不是content-type?我是卑鄙的语法纳粹吗?

As far as I know, they are absolute equal. However, browsing some django docs, I’ve found this piece of code:

HttpResponse.__init__(content='', mimetype=None, status=200, content_type='text/html')

which surprise me the two getting along each other. The official docs was able to solve the issue in a pratical manner:

content_type is an alias for mimetype. Historically, this parameter was only called mimetype, but since this is actually the value included in the HTTP Content-Type header, it can also include the character set encoding, which makes it more than just a MIME type specification. If mimetype is specified (not None), that value is used. Otherwise, content_type is used. If neither is given, the DEFAULT_CONTENT_TYPE setting is used.

However, I don’t find it elucidating enough. Why we use 2 different naming for (almost the same) thing? Is “Content-Type” just a name used in browser requests, and with very little use outside it?

What’s the main difference between the each one, and when is right to call something mimetype as opposed to content-type ? Am I being pitty and grammar nazi?


回答 0

为什么我们为(几乎相同的)事物使用2种不同的命名?“ Content-Type”只是浏览器请求中使用的名称,而在其外部很少使用吗?

两者之间的主要区别是什么,何时称呼某种mimetype而不是content-type才是正确的?我是可怜的纳粹语法吗?

原因不仅是向后兼容,而且恐怕通常出色的Django文档对此有些不易理解。MIME(至少值得阅读Wikipedia条目确实很值得)起源于扩展Internet邮件,尤其是SMTP。从那里开始,MIME和受MIME启发的扩展设计已经在许多其他协议(例如此处的HTTP)中找到了应用,当需要在现有协议中传输新型元数据或数据时,它仍在使用。有数十个RFC讨论了用于多种目的的MIME。

具体来说,Content-Type:是几个MIME标头之一。“ Mimetype”确实确实过时了,但是对MIME本身的引用却不是。如果可以的话,将该部分称为后向兼容性。

[BTW,这纯粹是一个术语问题,与语法无关。提出“语法”下的每个用法问题都是我的宠儿。咕rr

Why we use 2 different naming for (almost the same) thing? Is “Content-Type” just a name used in browser requests, and with very little use outside it?

What’s the main difference between the each one, and when is right to call something mimetype as opposed to content-type ? Am i being pitty and grammar nazi?

The reason isn’t only backward compatibility, and I’m afraid the usually excellent Django documentation is a bit hand-wavy about it. MIME (it’s really worth reading at least the Wikipedia entry) has its origin in extending internet mail, and specifically SMTP. From there, the MIME and MIME-inspired extension design has found its way into a lot of other protocols (such as HTTP here), and is still being used when new kinds of metadata or data need to be transmitted in an existing protocol. There are dozens of RFCs that discuss MIME used for a plethora of purposes.

Specifically, Content-Type: is one among several MIME headers. “Mimetype” does indeed sound obsolete, but a reference to MIME itself isn’t. Call that part backward-compatibility, if you will.

[BTW, this is purely a terminology problem which has nothing whatsoever to do with grammar. Filing every usage question under “grammar” is a pet peeve of mine. Grrrr.]


回答 1

我一直将contentType视为mimeType的超集。唯一的区别是可选字符集编码。如果contentType不包含可选字符集编码,则它与mimeType相同。否则,mimeType是字符集编码序列之前的数据。

例如 text/html; charset=UTF-8

text/html是mimeType
;是附加参数指示符
charset=UTF-8是字符集编码参数

例如 application/msword

application/msword是mimeType,
它不能具有字符集编码,因为它描述的格式octet-stream不直接包含字符。

I’ve always viewed contentType to be a superset of mimeType. The only difference being the optional character set encoding. If the contentType does not include an optional character set encoding then it is identical to a mimeType. Otherwise, the mimeType is the data prior to the character set encoding sequence.

E.G. text/html; charset=UTF-8

text/html is the mimeType
; is the additional parameters indicator
charset=UTF-8 is the character set encoding parameter

E.G. application/msword

application/msword is the mimeType
It cannot have a character set encoding as it describes a well formed octet-stream not comprising characters directly.


回答 2

如果您想了解详细信息,请参阅票证3526

引用:

向HttpResponse构造函数添加了content_type作为mimetype的别名。这是一个稍微准确的名称。基于Simon Willison的补丁。完全向后兼容。

If you want to know the details see ticket 3526.

Quote:

Added content_type as an alias for mimetype to the HttpResponse constructor. It’s a slightly more accurate name. Based on a patch from Simon Willison. Fully backwards compatible.


回答 3

为什么我们为(几乎相同的)事物使用2种不同的命名?

向后兼容性,基于您在文档中的报价。

Why we use 2 different naming for (almost the same) thing?

Backwards compatibility, based on your quote from the documentation.


何时在Django中创建新应用(使用startapp)?

问题:何时在Django中创建新应用(使用startapp)?

我已经为此进行了搜索,但是在Django定义为“应用程序”方面仍然遇到麻烦。

我是否应该为站点中的每个功能创建一个新应用,即使该应用使用了主项目中的模型?

你们对何时拆分新应用程序以及何时将功能与“主项目”或其他应用程序保持在一起有很好的经验法则吗?

I’ve googled around for this, but I still have trouble relating to what Django defines as “apps”.

Should I create a new app for each piece of functionality in a site, even though it uses models from the main project?

Do you guys have good rule of thumb of when to split off a new app, and when to keep functionality together with the “main project” or other apps?


回答 0

詹姆斯·本内特(James Bennett)提供了一系列精彩的幻灯片,介绍了如何在Django中组织可重复使用的应用程序。

James Bennett has a wonderful set of slides on how to organize reusable apps in Django.


回答 1

我更喜欢将Django应用程序视为可重用的模块或组件,而不是“应用程序”。

这有助于我将某些功能相互封装和解耦,如果我决定与整个社区共享特定的“应用”,则可以提高可重用性,并具有可维护性。

我的一般方法是将特定功能或功能集存储到“应用程序”中,就像我要公开发布它们一样。这里最困难的部分是弄清楚每个存储桶有多大。

我使用的一个好技巧是想象如果我的应用程序公开发布后将如何使用。这通常鼓励我缩水缩水,更清楚地定义其“目的”。

I prefer to think of Django applications as reusable modules or components than as “applications”.

This helps me encapsulate and decouple certain features from one another, improving re-usability should I decide to share a particular “app” with the community at large, and maintainability.

My general approach is to bucket up specific features or feature sets into “apps” as though I were going to release them publicly. The hard part here is figuring out how big each bucket is.

A good trick I use is to imagine how my apps would be used if they were released publicly. This often encourages me to shrink the buckets and more clearly define its “purpose”.


回答 2

这是2008年9月6日更新的演示文稿。

DjangoCon 2008:可重用应用@ 7:53

幻灯片:Reusable_apps.pdf

取自幻灯片

这应该是它自己的应用程序吗?

  • 它与应用程序的关注点完全无关吗?
  • 它与我正在做的其他事情正交吗?
  • 我在其他站点上是否需要类似的功能?

如果其中任何一个是“是”?然后最好将其分解为一个单独的应用程序。

Here is the updated presentation on 6 September 2008.

DjangoCon 2008: Reusable Apps @7:53

Slide: Reusable_apps.pdf

Taken from the slide

Should this be its own application?

  • Is it completely unrelated to the app’s focus?
  • Is it orthogonal to whatever else I’m doing?
  • Will I need similar functionality on other sites?

If any of them is “Yes”? Then best to break it into a separate application.


回答 3

我倾向于为每个逻辑上分离的模型集创建新的应用程序。例如:

  • 用户资料
  • 论坛帖子
  • 博客文章

I tend to create new applications for each logically separate set of models. e.g.:

  • User Profiles
  • Forum Posts
  • Blog posts

回答 4

我遵循的规则是,如果我想在其他项目中重用该功能,则它应该是一个新应用。

如果需要对项目中的模型有深入的了解,则将其与模型结合在一起可能会更有凝聚力。

The rule I follow is it should be a new app if I want to reuse the functionality in a different project.

If it needs deep understanding of the models in your project, it’s probably more cohesive to stick it with the models.


回答 5

我在网上发现的这个问题的两个最佳答案是:

  1. 其他答案中也提到了可重复使用的应用程序对话(幻灯片)(视频)。Bennett是Django的作者和撰稿人,他定期发布供他人使用的应用程序,并对许多小型应用程序有很强的见解。
  2. Doordash的《面向Django的技巧》给出了相反的建议,并表示在从许多单独的应用程序开始后,他们迁移到了一个应用程序。他们在应用之间的迁移依赖关系图中遇到了问题。

两种消息来源都同意您在以下情况下应创建一个单独的应用程序:

  • 如果您打算在另一个Django项目中重用您的应用程序(尤其是如果您打算将其发布以供其他人重用)。
  • 该应用程序与另一个应用程序之间的依赖关系很少或没有。在这里,您可能可以想象将来有一个应用程序将作为其自己的微服务运行。

The two best answers to this question I’ve found around the web are:

  1. The Reusable Apps Talk (slides)(video) also mentioned in other answers. Bennett, the author and Django contributor, regularly publishes apps for others to use and has a strong viewpoint towards many small apps.
  2. Doordash’s Tips for Django at Scale which gives the opposite advice and says in their case they migrated to one single app after starting with many separate apps. They ran into problems with the migration dependency graph between apps.

Both sources agree that you should create a separate app in the following situations:

  • If you plan to reuse your app in another Django project (especially if you plan to publish it for others to reuse).
  • If the app has few or no dependencies between it and another app. Here you might be able to imagine an app running as its own microservice in the future.

回答 6

一个“应用程序”可能有很多不同的东西,这一切真的都让人联想到。例如,假设您正在构建博客。您的应用程序可以是整个博客,也可以有一个“管理员”应用程序,一个用于所有公共视图的“站点”应用程序,一个“ rss”应用程序,一个“服务”应用程序,以便开发人员可以在其博客中与该博客进行交互自己的方式等

我个人将使博客本身成为该应用程序,并扩展其中的功能。然后可以很轻松地在其他网站中重复使用该博客。

Django的优点在于,它将目录树中任何级别的所有models.py文件都识别为包含Django模型的文件。因此,将功能分解为“应用程序”本身中较小的“子应用程序”不会带来任何困难。

An ‘app’ could be many different things, it all really comes down to taste. For example, let’s say you are building a blog. Your app could be the entire blog, or you could have an ‘admin’ app, a ‘site’ app for all of the public views, an ‘rss’ app, a ‘services’ app so developers can interface with the blog in their own ways, etc.

I personally would make the blog itself the app, and break out the functionality within it. The blog could then be reused rather easily in other websites.

The nice thing about Django is that it will recognize any models.py file within any level of your directory tree as a file containing Django models. So breaking your functionality out into smaller ‘sub apps’ within an ‘app’ itself won’t make anything more difficult.