标签归档:Django

如何检查用户是否已登录(如何正确使用user.is_authenticated)?

问题:如何检查用户是否已登录(如何正确使用user.is_authenticated)?

我正在看这个网站,但似乎无法弄清楚该怎么做,因为它不起作用。我需要检查当前站点用户是否已登录(已认证),并且正在尝试:

request.user.is_authenticated

尽管确定用户已登录,但它仅返回:

>

我能够执行其他请求(来自上述网址的第一部分),例如:

request.user.is_active

这将返回成功的响应。

I am looking over this website but just can’t seem to figure out how to do this as it’s not working. I need to check if the current site user is logged in (authenticated), and am trying:

request.user.is_authenticated

despite being sure that the user is logged in, it returns just:

>

I’m able to do other requests (from the first section in the url above), such as:

request.user.is_active

which returns a successful response.


回答 0

Django 1.10+更新is_authenticated现在是Django 1.10中的属性。为了向后兼容,该方法仍然存在,但在Django 2.0中将被删除。

对于Django 1.9及更早版本

is_authenticated是一个功能。你应该这样称呼它

if request.user.is_authenticated():
    # do something if the user is authenticated

正如Peter Rowell所指出的那样,可能让您感到困扰的是,在默认的Django模板语言中,您无需附加括号即可调用函数。因此,您可能已经在模板代码中看到了以下内容:

{% if user.is_authenticated %}

但是,在Python代码中,它确实是User类中的方法。

Update for Django 1.10+:

is_authenticated is now an attribute in Django 1.10.

The method was removed in Django 2.0.

For Django 1.9 and older:

is_authenticated is a function. You should call it like

if request.user.is_authenticated():
    # do something if the user is authenticated

As Peter Rowell pointed out, what may be tripping you up is that in the default Django template language, you don’t tack on parenthesis to call functions. So you may have seen something like this in template code:

{% if user.is_authenticated %}

However, in Python code, it is indeed a method in the User class.


回答 1

Django 1.10+

使用属性,而不是方法:

if request.user.is_authenticated: # <-  no parentheses any more!
    # do something if the user is authenticated

Django 2.0中已弃用了同名的方法,并且Django文档中不再提及。


请注意,对于Django 1.10和1.11,该属性的值是a CallableBool而不是布尔值,这可能会导致一些奇怪的错误。例如,我有一个返回JSON的视图

return HttpResponse(json.dumps({
    "is_authenticated": request.user.is_authenticated()
}), content_type='application/json') 

在更新到属性request.user.is_authenticated后抛出异常TypeError: Object of type 'CallableBool' is not JSON serializable。解决方案是使用JsonResponse,它可以在序列化时正确处理CallableBool对象:

return JsonResponse({
    "is_authenticated": request.user.is_authenticated
})

Django 1.10+

Use an attribute, not a method:

if request.user.is_authenticated: # <-  no parentheses any more!
    # do something if the user is authenticated

The use of the method of the same name is deprecated in Django 2.0, and is no longer mentioned in the Django documentation.


Note that for Django 1.10 and 1.11, the value of the property is a CallableBool and not a boolean, which can cause some strange bugs. For example, I had a view that returned JSON
return HttpResponse(json.dumps({
    "is_authenticated": request.user.is_authenticated()
}), content_type='application/json') 

that after updated to the property request.user.is_authenticated was throwing the exception TypeError: Object of type 'CallableBool' is not JSON serializable. The solution was to use JsonResponse, which could handle the CallableBool object properly when serializing:

return JsonResponse({
    "is_authenticated": request.user.is_authenticated
})

回答 2

以下块应该工作:

    {% if user.is_authenticated %}
        <p>Welcome {{ user.username }} !!!</p>       
    {% endif %}

Following block should work:

    {% if user.is_authenticated %}
        <p>Welcome {{ user.username }} !!!</p>       
    {% endif %}

回答 3

您认为:

{% if user.is_authenticated %}
<p>{{ user }}</p>
{% endif %}

在控制器函数中添加装饰器:

from django.contrib.auth.decorators import login_required
@login_required
def privateFunction(request):

In your view:

{% if user.is_authenticated %}
<p>{{ user }}</p>
{% endif %}

In you controller functions add decorator:

from django.contrib.auth.decorators import login_required
@login_required
def privateFunction(request):

回答 4

如果要在模板中检查经过身份验证的用户,则:

{% if user.is_authenticated %}
    <p>Authenticated user</p>
{% else %}
    <!-- Do something which you want to do with unauthenticated user -->
{% endif %}

If you want to check for authenticated users in your template then:

{% if user.is_authenticated %}
    <p>Authenticated user</p>
{% else %}
    <!-- Do something which you want to do with unauthenticated user -->
{% endif %}

回答 5

对于Django 2.0+版本,请使用:

    if request.auth:
       # Only for authenticated users.

有关更多信息,请访问https://www.django-rest-framework.org/api-guide/requests/#auth

在Django 2.0及更高版本中,request.user.is_authenticated()已被删除。

For Django 2.0+ versions use:

    if request.auth:
       # Only for authenticated users.

For more info visit https://www.django-rest-framework.org/api-guide/requests/#auth

request.user.is_authenticated() has been removed in Django 2.0+ versions.


如何在Django中按日期范围过滤查询对象?

问题:如何在Django中按日期范围过滤查询对象?

我在一个模型中有一个领域,例如:

class Sample(models.Model):
    date = fields.DateField(auto_now=False)

现在,我需要按日期范围过滤对象。

如何过滤日期在1-Jan-2011和之间的所有对象31-Jan-2011

I’ve got a field in one model like:

class Sample(models.Model):
    date = fields.DateField(auto_now=False)

Now, I need to filter the objects by a date range.

How do I filter all the objects that have a date between 1-Jan-2011 and 31-Jan-2011?


回答 0

Sample.objects.filter(date__range=["2011-01-01", "2011-01-31"])

或者,如果您只是想按月过滤:

Sample.objects.filter(date__year='2011', 
                      date__month='01')

编辑

正如伯恩哈德Vallant说,如果你想查询集去掉了specified range ends,你应该考虑自己的解决方案,它采用GT / LT(大于/小于号)。

Use

Sample.objects.filter(date__range=["2011-01-01", "2011-01-31"])

Or if you are just trying to filter month wise:

Sample.objects.filter(date__year='2011', 
                      date__month='01')

Edit

As Bernhard Vallant said, if you want a queryset which excludes the specified range ends you should consider his solution, which utilizes gt/lt (greater-than/less-than).


回答 1

您可以对对象使用djangofilterdatetime.date

import datetime
samples = Sample.objects.filter(sampledate__gte=datetime.date(2011, 1, 1),
                                sampledate__lte=datetime.date(2011, 1, 31))

You can use django’s filter with datetime.date objects:

import datetime
samples = Sample.objects.filter(sampledate__gte=datetime.date(2011, 1, 1),
                                sampledate__lte=datetime.date(2011, 1, 31))

回答 2

使用过滤器进行Django范围设置时,请确保您知道使用日期对象与日期时间对象之间的区别。__range是日期中包含的内容,但是如果您使用datetime对象作为结束日期,则如果未设置时间,它将不包括该天的条目。

    startdate = date.today()
    enddate = startdate + timedelta(days=6)
    Sample.objects.filter(date__range=[startdate, enddate])

返回从开始日期到结束日期的所有条目,包括那些日期的条目。不好的例子,因为这将在未来一周返回条目,但您会遇到麻烦。

    startdate = datetime.today()
    enddate = startdate + timedelta(days=6)
    Sample.objects.filter(date__range=[startdate, enddate])

根据日期字段的设置时间,将缺少24小时的输入值。

When doing django ranges with a filter make sure you know the difference between using a date object vs a datetime object. __range is inclusive on dates but if you use a datetime object for the end date it will not include the entries for that day if the time is not set.

    startdate = date.today()
    enddate = startdate + timedelta(days=6)
    Sample.objects.filter(date__range=[startdate, enddate])

returns all entries from startdate to enddate including entries on those dates. Bad example since this is returning entries a week into the future, but you get the drift.

    startdate = datetime.today()
    enddate = startdate + timedelta(days=6)
    Sample.objects.filter(date__range=[startdate, enddate])

will be missing 24 hours worth of entries depending on what the time for the date fields is set to.


回答 3

通过使用datetime.timedelta在范围中的最后一个日期添加日期,可以避免由于DateTimeField/date对象比较精度不足而导致的“阻抗不匹配”(如果使用范围,则可能发生)。其工作原理如下:

start = date(2012, 12, 11)
end = date(2012, 12, 18)
new_end = end + datetime.timedelta(days=1)

ExampleModel.objects.filter(some_datetime_field__range=[start, new_end])

如前所述,如果不这样做,记录将在最后一天被忽略。

进行编辑以避免使用datetime.combine-与a进行比较时,坚持日期实例似乎更合乎逻辑DateTimeField,而不是乱扔掉(且容易混淆)datetime对象。请参阅下面的注释中的进一步说明。

You can get around the “impedance mismatch” caused by the lack of precision in the DateTimeField/date object comparison — that can occur if using range — by using a datetime.timedelta to add a day to last date in the range. This works like:

start = date(2012, 12, 11)
end = date(2012, 12, 18)
new_end = end + datetime.timedelta(days=1)

ExampleModel.objects.filter(some_datetime_field__range=[start, new_end])

As discussed previously, without doing something like this, records are ignored on the last day.

Edited to avoid the use of datetime.combine — seems more logical to stick with date instances when comparing against a DateTimeField, instead of messing about with throwaway (and confusing) datetime objects. See further explanation in comments below.


回答 4

很简单

YourModel.objects.filter(YOUR_DATE_FIELD__date=timezone.now())

为我工作

Is simple,

YourModel.objects.filter(YOUR_DATE_FIELD__date=timezone.now())

Works for me


回答 5

为了使其更加灵活,可以设计如下的FilterBackend:

class AnalyticsFilterBackend(generic_filters.BaseFilterBackend):
    def filter_queryset(self, request, queryset, view):
        predicate = request.query_params # or request.data for POST

        if predicate.get('from_date', None) is not None and predicate.get('to_date', None) is not None:
            queryset = queryset.filter(your_date__range=(predicate['from_date'], predicate['to_date']))

        if predicate.get('from_date', None) is not None and predicate.get('to_date', None) is None:
            queryset = queryset.filter(your_date__gte=predicate['from_date'])

        if predicate.get('to_date', None) is not None and predicate.get('from_date', None) is None:
            queryset = queryset.filter(your_date__lte=predicate['to_date'])
        return queryset

To make it more flexible, you can design a FilterBackend as below:

class AnalyticsFilterBackend(generic_filters.BaseFilterBackend):
    def filter_queryset(self, request, queryset, view):
        predicate = request.query_params # or request.data for POST

        if predicate.get('from_date', None) is not None and predicate.get('to_date', None) is not None:
            queryset = queryset.filter(your_date__range=(predicate['from_date'], predicate['to_date']))

        if predicate.get('from_date', None) is not None and predicate.get('to_date', None) is None:
            queryset = queryset.filter(your_date__gte=predicate['from_date'])

        if predicate.get('to_date', None) is not None and predicate.get('from_date', None) is None:
            queryset = queryset.filter(your_date__lte=predicate['to_date'])
        return queryset

回答 6

今天仍然有意义。您也可以这样做:

import dateutil
import pytz

date = dateutil.parser.parse('02/11/2019').replace(tzinfo=pytz.UTC)

Still relevant today. You can also do:

import dateutil
import pytz

date = dateutil.parser.parse('02/11/2019').replace(tzinfo=pytz.UTC)

如何从Django Shell执行Python脚本?

问题:如何从Django Shell执行Python脚本?

我需要从Django Shell执行Python脚本。我试过了:

./manage.py shell << my_script.py

但这没有用。只是在等我写东西。

I need to execute a Python script from the Django shell. I tried:

./manage.py shell << my_script.py

But it didn’t work. It was just waiting for me to write something.


回答 0

<<部分有误,请<改用:

$ ./manage.py shell < myscript.py

您也可以这样做:

$ ./manage.py shell
...
>>> execfile('myscript.py')

对于python3,您需要使用

>>> exec(open('myscript.py').read())

The << part is wrong, use < instead:

$ ./manage.py shell < myscript.py

You could also do:

$ ./manage.py shell
...
>>> execfile('myscript.py')

For python3 you would need to use

>>> exec(open('myscript.py').read())

回答 1

你不建议这样做,从shell-这是为了你真不该从Django的环境中执行随机脚本(但也有解决这个办法,看到其他的答案)。

如果您要多次运行该脚本,则最好将其设置为自定义命令,

 $ ./manage.py my_command

要做到这一点创建一个子目录文件managementcommands你的app,即

my_app/
    __init__.py
    models.py
    management/
        __init__.py
        commands/
            __init__.py
            my_command.py
    tests.py
    views.py

并在此文件中定义您的自定义命令(确保文件名是您要从执行的命令的名称./manage.py

from django.core.management.base import BaseCommand

class Command(BaseCommand):
    def handle(self, **options):
        # now do the things that you want with your models here

You’re not recommended to do that from the shell – and this is intended as you shouldn’t really be executing random scripts from the django environment (but there are ways around this, see the other answers).

If this is a script that you will be running multiple times, it’s a good idea to set it up as a custom command ie

 $ ./manage.py my_command

to do this create a file in a subdir of management and commands of your app, ie

my_app/
    __init__.py
    models.py
    management/
        __init__.py
        commands/
            __init__.py
            my_command.py
    tests.py
    views.py

and in this file define your custom command (ensuring that the name of the file is the name of the command you want to execute from ./manage.py)

from django.core.management.base import BaseCommand

class Command(BaseCommand):
    def handle(self, **options):
        # now do the things that you want with your models here

回答 2

对于使用Django 1.7+的任何人,似乎仅仅导入settings模块是不够的。

经过一番挖掘,我找到了这个堆栈溢出的答案:https : //stackoverflow.com/a/23241093

您现在需要:

import os, django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myapp.settings")
django.setup()
# now your code can go here...

没有执行上述操作,我得到了一个django.core.exceptions.AppRegistryNoReady错误。

我的脚本文件与django项目位于同一目录(即,与manage.py位于同一文件夹)

For anyone using Django 1.7+, it seems that simply import the settings module is not enough.

After some digging, I found this Stack Overflow answer: https://stackoverflow.com/a/23241093

You now need to:

import os, django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myapp.settings")
django.setup()
# now your code can go here...

Without doing the above, I was getting a django.core.exceptions.AppRegistryNoReady error.

My script file is in the same directory as my django project (ie. in the same folder as manage.py)


回答 3

我参加聚会很晚,但希望我的回复对某人有帮助:您可以在Python脚本中执行以下操作:

import sys, os
sys.path.append('/path/to/your/django/app')
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
from django.conf import settings

其余的东西都在这里….

I’m late for the party but I hope that my response will help someone: You can do this in your Python script:

import sys, os
sys.path.append('/path/to/your/django/app')
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
from django.conf import settings

the rest of your stuff goes here ….


回答 4

runscript来自django-extensions

python manage.py runscript scripty.py

一个样本script.py进行测试:

from django.contrib.auth.models import User
print(User.objects.values())

提及于:http : //django-extensions.readthedocs.io/en/latest/command_extensions.html,并记录在:

python manage.py runscript --help

也有一个教程

在Django 1.9.6和django-extensions 1.6.7上进行了测试。

runscript from django-extensions

python manage.py runscript scripty.py

A sample script.py to test it out:

from django.contrib.auth.models import User
print(User.objects.values())

Mentioned at: http://django-extensions.readthedocs.io/en/latest/command_extensions.html and documented at:

python manage.py runscript --help

There is a tutorial too.

Tested on Django 1.9.6, django-extensions 1.6.7.


回答 5

如果IPython可用(pip install ipython),./manage.py shell它将自动使用它的外壳,然后可以使用magic命令%run

%run my_script.py

If IPython is available (pip install ipython) then ./manage.py shell will automatically use it’s shell and then you can use the magic command %run:

%run my_script.py

回答 6

您可以仅在DJANGO_SETTINGS_MODULE设置了环境变量的情况下运行脚本。这就是设置Django-shell环境所需的全部。

这适用于Django> = 1.4

You can just run the script with the DJANGO_SETTINGS_MODULE environment variable set. That’s all it takes to set up Django-shell environment.

This works in Django >= 1.4


回答 7

@AtulVarma在无法接受的答案下提供了非常有用的评论:

echo 'import myscript' | python manage.py shell

@AtulVarma provided a very useful comment under the not-working accepted answer:

echo 'import myscript' | python manage.py shell

回答 8

如果脚本中没有很多命令,请使用它:

manage.py shell --command="import django; print(django.__version__)"

Django文档

if you have not a lot commands in your script use it:

manage.py shell --command="import django; print(django.__version__)"

Django docs


回答 9

正如其他答案指出但未明确指出的那样,您实际需要的不一定是从Django Shell执行脚本,而是在不使用Django Shell的情况下访问应用程序。

Django版本与Django版本有很大不同。如果在该线程上找不到解决方案,请在此处回答 -Django脚本无需使用manage.py shell即可访问模型对象 -或类似的搜索可能会对您有所帮助。

我必须以my_command.py开始

import os,sys
sys.path.append('/path/to/myproject')
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.file")
import django
django.setup()

import project.app.models
#do things with my models, yay

然后跑 python3 my_command.py

(Django 2.0.2)

As other answers indicate but don’t explicitly state, what you may actually need is not necessarily to execute your script from the Django shell, but to access your apps without using the Django shell.

This differs a lot Django version to Django version. If you do not find your solution on this thread, answers here — Django script to access model objects without using manage.py shell — or similar searches may help you.

I had to begin my_command.py with

import os,sys
sys.path.append('/path/to/myproject')
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.file")
import django
django.setup()

import project.app.models
#do things with my models, yay

and then ran python3 my_command.py

(Django 2.0.2)


回答 10

import os, sys, django
os.environ["DJANGO_SETTINGS_MODULE"] = "settings"
sys.path.insert(0, os.getcwd())

django.setup()
import os, sys, django
os.environ["DJANGO_SETTINGS_MODULE"] = "settings"
sys.path.insert(0, os.getcwd())

django.setup()

回答 11

请注意,此方法已被django的最新版本淘汰!(> 1.3)

一个替代答案,您可以将其添加到 my_script.py

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

my_script.py仅在您所在的目录中使用python 执行,settings.py但这有点麻烦。

$ python my_script.py

Note, this method has been deprecated for more recent versions of django! (> 1.3)

An alternative answer, you could add this to the top of my_script.py

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

and execute my_script.py just with python in the directory where you have settings.py but this is a bit hacky.

$ python my_script.py

回答 12

如果您想更好地在BG中运行:

nohup echo 'exec(open("my_script.py").read())' | python manage.py shell &

输出将在 nohup.out

If you want to run in in BG even better:

nohup echo 'exec(open("my_script.py").read())' | python manage.py shell &

The output will be in nohup.out


回答 13

我刚刚发现有趣的是Django Scripts,它允许您编写要使用python manage.py runscript foobar运行的脚本。有关实现和结构的更多详细信息,请参见http://django-extensions.readthedocs.org/en/latest/index.html

Something I just found to be interesting is Django Scripts, which allows you to write scripts to be run with python manage.py runscript foobar. More detailed information on implementation and scructure can be found here, http://django-extensions.readthedocs.org/en/latest/index.html


回答 14

如果您使用的是虚拟环境,请尝试以下操作:

python manage.py shell

要使用这些命令,您必须位于虚拟环境中。为此用途:

工作vir_env_name

例如 :-

dc@dc-comp-4:~/mysite$ workon jango
(jango)dc@dc-comp-4:~/mysite$ python manage.py shell
Python 2.7.6 (default, Mar 22 2014, 22:59:56) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> 

注意:-这里的mysite是我的网站名称,而jango是我的虚拟环境名称

Try this if you are using virtual enviroment :-

python manage.py shell

for using those command you must be inside virtual enviroment. for this use :-

workon vir_env_name

for example :-

dc@dc-comp-4:~/mysite$ workon jango
(jango)dc@dc-comp-4:~/mysite$ python manage.py shell
Python 2.7.6 (default, Mar 22 2014, 22:59:56) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> 

Note :- Here mysite is my website name and jango is my virtual enviroment name


回答 15

来到这里的是与OP相同的问题,我发现我最喜欢的答案恰好是问题中的错误,这在Python 3中也适用:

./manage.py shell <<EOF
import my_script
my_script.main()
EOF

came here with the same question as the OP, and I found my favourite answer precisely in the mistake within the question, which works also in Python 3:

./manage.py shell <<EOF
import my_script
my_script.main()
EOF

回答 16

另一种执行此方法的方法:

echo 'execfile("/path_to/myscript.py")' | python manage.py shell --settings=config.base

这适用于Python2.7和Django1.9

Other way it’s execute this one:

echo 'execfile("/path_to/myscript.py")' | python manage.py shell --settings=config.base

This is working on Python2.7 and Django1.9


回答 17

如果要执行启动脚本(例如,导入一些django模型以交互方式使用它们)并保留在django shell中:

PYTHONSTARTUP=my_script.py python manage.py shell

If you want to execute startup script (e.g. import some django models to work with them interactively) and remain in django shell:

PYTHONSTARTUP=my_script.py python manage.py shell

回答 18

django shell是在django环境中执行python模块的好方法,但是手动导入模块和执行函数并不总是那么容易且麻烦,尤其是在没有自动完成的情况下。为了解决这个问题,我创建了一个小的shell脚本“ runscript.sh”,使您可以充分利用Linux控制台的自动完成功能和日志历史记录。

注意:将runscript.sh复制到根项目并设置执行权限(chmod + x)

例如:我想在myapp / do_folder /中的do_somethings.py模块中运行名为show(a,b,c)的python函数。

django的标准方式(manage.py shell):

python3 manage.py shell
 > from myapp.do_folder import do_somethings
 > do_somethings.show("p1", "p2"  , 3.14159)

使用脚本(runscript.sh):

./runscript.sh myapp/do_folder/do_somethings.py show p1 p2 3.14159

脚本的参数数量不受限制。但是,仅支持基本类型的参数(int,float,string)

The django shell is the good way to execute a python module with the django environment, but it is not always easy and tiresome to import modules and execute functions manually especially without auto-completion. To resolve this, I created a small shell script “runscript.sh” that allows you to take full advantage of the auto-completion and the log history of the Linux console.

NB: Copy runscript.sh to the root project and set the execute right (chmod +x)

For example: I want to run python function named show(a, b, c) in module do_somethings.py in myapp/do_folder/

The standard django way (manage.py shell):

python3 manage.py shell
 > from myapp.do_folder import do_somethings
 > do_somethings.show("p1", "p2"  , 3.14159)

With script (runscript.sh):

./runscript.sh myapp/do_folder/do_somethings.py show p1 p2 3.14159

The script is not limited in number of arguments. However only arguments of primitive types are supported (int, float, string)


回答 19

晚会。但这可能对某人有用。

您只需要脚本并django-extensions安装。

只需运行shell_plus可用的django_extensions并导入您编写的脚本即可。

如果脚本scpt.py位于文件夹中fol,则可以按以下方式运行脚本。

python manage.py shell_plus

并按如下所示将您的脚本导入外壳。

>>> from fol import scpt

Late to the party. But this might be helpful for someone.

All you need is your script and django-extensions installed.

Just run the shell_plus available in django_extensions and import the script that you’ve written.

If your script is scpt.py and it’s inside a folder fol you can run the script as follows.

python manage.py shell_plus

and just import your script inside the shell as follows.

>>> from fol import scpt

回答 20

django.setup()似乎不起作用。

似乎也不是必需的。

仅此而已。

import os, django, glob, sys, shelve
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myProject.settings")

django.setup() does not seem to work.

does not seem to be required either.

this alone worked.

import os, django, glob, sys, shelve
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myProject.settings")

NumPy数组不可JSON序列化

问题:NumPy数组不可JSON序列化

创建NumPy数组并将其另存为Django上下文变量后,加载网页时出现以下错误:

array([   0,  239,  479,  717,  952, 1192, 1432, 1667], dtype=int64) is not JSON serializable

这是什么意思?

After creating a NumPy array, and saving it as a Django context variable, I receive the following error when loading the webpage:

array([   0,  239,  479,  717,  952, 1192, 1432, 1667], dtype=int64) is not JSON serializable

What does this mean?


回答 0

我经常“ jsonify” np.arrays。尝试首先在数组上使用“ .tolist()”方法,如下所示:

import numpy as np
import codecs, json 

a = np.arange(10).reshape(2,5) # a 2 by 5 array
b = a.tolist() # nested lists with same data, indices
file_path = "/path.json" ## your path variable
json.dump(b, codecs.open(file_path, 'w', encoding='utf-8'), separators=(',', ':'), sort_keys=True, indent=4) ### this saves the array in .json format

为了“ unjsonify”数组使用:

obj_text = codecs.open(file_path, 'r', encoding='utf-8').read()
b_new = json.loads(obj_text)
a_new = np.array(b_new)

I regularly “jsonify” np.arrays. Try using the “.tolist()” method on the arrays first, like this:

import numpy as np
import codecs, json 

a = np.arange(10).reshape(2,5) # a 2 by 5 array
b = a.tolist() # nested lists with same data, indices
file_path = "/path.json" ## your path variable
json.dump(b, codecs.open(file_path, 'w', encoding='utf-8'), separators=(',', ':'), sort_keys=True, indent=4) ### this saves the array in .json format

In order to “unjsonify” the array use:

obj_text = codecs.open(file_path, 'r', encoding='utf-8').read()
b_new = json.loads(obj_text)
a_new = np.array(b_new)

回答 1

将numpy.ndarray或任何嵌套列表组合作为JSON存储。

class NumpyEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, np.ndarray):
            return obj.tolist()
        return json.JSONEncoder.default(self, obj)

a = np.array([[1, 2, 3], [4, 5, 6]])
print(a.shape)
json_dump = json.dumps({'a': a, 'aa': [2, (2, 3, 4), a], 'bb': [2]}, cls=NumpyEncoder)
print(json_dump)

将输出:

(2, 3)
{"a": [[1, 2, 3], [4, 5, 6]], "aa": [2, [2, 3, 4], [[1, 2, 3], [4, 5, 6]]], "bb": [2]}

要从JSON还原:

json_load = json.loads(json_dump)
a_restored = np.asarray(json_load["a"])
print(a_restored)
print(a_restored.shape)

将输出:

[[1 2 3]
 [4 5 6]]
(2, 3)

Store as JSON a numpy.ndarray or any nested-list composition.

class NumpyEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, np.ndarray):
            return obj.tolist()
        return json.JSONEncoder.default(self, obj)

a = np.array([[1, 2, 3], [4, 5, 6]])
print(a.shape)
json_dump = json.dumps({'a': a, 'aa': [2, (2, 3, 4), a], 'bb': [2]}, cls=NumpyEncoder)
print(json_dump)

Will output:

(2, 3)
{"a": [[1, 2, 3], [4, 5, 6]], "aa": [2, [2, 3, 4], [[1, 2, 3], [4, 5, 6]]], "bb": [2]}

To restore from JSON:

json_load = json.loads(json_dump)
a_restored = np.asarray(json_load["a"])
print(a_restored)
print(a_restored.shape)

Will output:

[[1 2 3]
 [4 5 6]]
(2, 3)

回答 2

您可以使用Pandas

import pandas as pd
pd.Series(your_array).to_json(orient='values')

You can use Pandas:

import pandas as pd
pd.Series(your_array).to_json(orient='values')

回答 3

如果您在字典中嵌套了numpy数组,我找到了最佳解决方案:

import json
import numpy as np

class NumpyEncoder(json.JSONEncoder):
    """ Special json encoder for numpy types """
    def default(self, obj):
        if isinstance(obj, np.integer):
            return int(obj)
        elif isinstance(obj, np.floating):
            return float(obj)
        elif isinstance(obj, np.ndarray):
            return obj.tolist()
        return json.JSONEncoder.default(self, obj)

dumped = json.dumps(data, cls=NumpyEncoder)

with open(path, 'w') as f:
    json.dump(dumped, f)

感谢这个家伙

I found the best solution if you have nested numpy arrays in a dictionary:

import json
import numpy as np

class NumpyEncoder(json.JSONEncoder):
    """ Special json encoder for numpy types """
    def default(self, obj):
        if isinstance(obj, np.integer):
            return int(obj)
        elif isinstance(obj, np.floating):
            return float(obj)
        elif isinstance(obj, np.ndarray):
            return obj.tolist()
        return json.JSONEncoder.default(self, obj)

dumped = json.dumps(data, cls=NumpyEncoder)

with open(path, 'w') as f:
    json.dump(dumped, f)

Thanks to this guy.


回答 4

使用json.dumps defaultkwarg:

default应该是一个为无法序列化的对象调用的函数。

default函数中,检查对象是否来自numpy模块,如果是,则将其ndarray.tolist用于ndarray或将其.item用于任何其他特定于numpy的类型。

import numpy as np

def default(obj):
    if type(obj).__module__ == np.__name__:
        if isinstance(obj, np.ndarray):
            return obj.tolist()
        else:
            return obj.item()
    raise TypeError('Unknown type:', type(obj))

dumped = json.dumps(data, default=default)

Use the json.dumps default kwarg:

default should be a function that gets called for objects that can’t otherwise be serialized. … or raise a TypeError

In the default function check if the object is from the module numpy, if so either use ndarray.tolist for a ndarray or use .item for any other numpy specific type.

import numpy as np

def default(obj):
    if type(obj).__module__ == np.__name__:
        if isinstance(obj, np.ndarray):
            return obj.tolist()
        else:
            return obj.item()
    raise TypeError('Unknown type:', type(obj))

dumped = json.dumps(data, default=default)

回答 5

默认情况下不支持此功能,但是您可以使其轻松工作!如果您想返回完全相同的数据,则需要对几件事进行编码:

  • 数据本身,您可以获得 obj.tolist() @travelingbones。有时这可能已经足够了。
  • 数据类型。我觉得在某些情况下这很重要。
  • 如果您假设输入确实始终是“矩形”网格,则可以从上面得出尺寸(不一定是2D)。
  • 内存顺序(行或列为主)。这通常并不重要,但有时却很重要(例如性能),那么为什么不保存所有内容呢?

此外,您的numpy数组可能是数据结构的一部分,例如,您有一个包含一些矩阵的列表。为此,您可以使用基本上完成上述操作的自定义编码器。

这应该足以实施解决方案。或者,您可以使用json-tricks来做到这一点(并支持其他各种类型)(免责声明:我做到了)。

pip install json-tricks

然后

data = [
    arange(0, 10, 1, dtype=int).reshape((2, 5)),
    datetime(year=2017, month=1, day=19, hour=23, minute=00, second=00),
    1 + 2j,
    Decimal(42),
    Fraction(1, 3),
    MyTestCls(s='ub', dct={'7': 7}),  # see later
    set(range(7)),
]
# Encode with metadata to preserve types when decoding
print(dumps(data))

This is not supported by default, but you can make it work quite easily! There are several things you’ll want to encode if you want the exact same data back:

  • The data itself, which you can get with obj.tolist() as @travelingbones mentioned. Sometimes this may be good enough.
  • The data type. I feel this is important in quite some cases.
  • The dimension (not necessarily 2D), which could be derived from the above if you assume the input is indeed always a ‘rectangular’ grid.
  • The memory order (row- or column-major). This doesn’t often matter, but sometimes it does (e.g. performance), so why not save everything?

Furthermore, your numpy array could part of your data structure, e.g. you have a list with some matrices inside. For that you could use a custom encoder which basically does the above.

This should be enough to implement a solution. Or you could use json-tricks which does just this (and supports various other types) (disclaimer: I made it).

pip install json-tricks

Then

data = [
    arange(0, 10, 1, dtype=int).reshape((2, 5)),
    datetime(year=2017, month=1, day=19, hour=23, minute=00, second=00),
    1 + 2j,
    Decimal(42),
    Fraction(1, 3),
    MyTestCls(s='ub', dct={'7': 7}),  # see later
    set(range(7)),
]
# Encode with metadata to preserve types when decoding
print(dumps(data))

回答 6

嵌套字典中有一些numpy.ndarrays,我也遇到类似的问题。

def jsonify(data):
    json_data = dict()
    for key, value in data.iteritems():
        if isinstance(value, list): # for lists
            value = [ jsonify(item) if isinstance(item, dict) else item for item in value ]
        if isinstance(value, dict): # for nested lists
            value = jsonify(value)
        if isinstance(key, int): # if key is integer: > to string
            key = str(key)
        if type(value).__module__=='numpy': # if value is numpy.*: > to python list
            value = value.tolist()
        json_data[key] = value
    return json_data

I had a similar problem with a nested dictionary with some numpy.ndarrays in it.

def jsonify(data):
    json_data = dict()
    for key, value in data.iteritems():
        if isinstance(value, list): # for lists
            value = [ jsonify(item) if isinstance(item, dict) else item for item in value ]
        if isinstance(value, dict): # for nested lists
            value = jsonify(value)
        if isinstance(key, int): # if key is integer: > to string
            key = str(key)
        if type(value).__module__=='numpy': # if value is numpy.*: > to python list
            value = value.tolist()
        json_data[key] = value
    return json_data

回答 7

您还可以使用default参数例如:

def myconverter(o):
    if isinstance(o, np.float32):
        return float(o)

json.dump(data, default=myconverter)

You could also use default argument for example:

def myconverter(o):
    if isinstance(o, np.float32):
        return float(o)

json.dump(data, default=myconverter)

回答 8

另外,关于Python中的列表和数组,还有一些非常有趣的信息〜> Python中的列表与数组的 Python列表与数组-何时使用?

可以注意到,在将数组保存到JSON文件之前将其转换为列表之后,无论如何,现在无论如何在我的部署中,一旦读取该JSON文件以备后用,我就可以继续以列表形式使用它(如而不是将其转换回数组)。

这样,与屏幕上的列表(逗号分隔)和数组(非逗号分隔)相比,实际上它看起来更好(在我看来)。

使用上面的@travelingbones的.tolist()方法,我已经这样使用了(也发现了一些我发现的错误):

保存词典

def writeDict(values, name):
    writeName = DIR+name+'.json'
    with open(writeName, "w") as outfile:
        json.dump(values, outfile)

阅读词典

def readDict(name):
    readName = DIR+name+'.json'
    try:
        with open(readName, "r") as infile:
            dictValues = json.load(infile)
            return(dictValues)
    except IOError as e:
        print(e)
        return('None')
    except ValueError as e:
        print(e)
        return('None')

希望这可以帮助!

Also, some very interesting information further on lists vs. arrays in Python ~> Python List vs. Array – when to use?

It could be noted that once I convert my arrays into a list before saving it in a JSON file, in my deployment right now anyways, once I read that JSON file for use later, I can continue to use it in a list form (as opposed to converting it back to an array).

AND actually looks nicer (in my opinion) on the screen as a list (comma seperated) vs. an array (not-comma seperated) this way.

Using @travelingbones’s .tolist() method above, I’ve been using as such (catching a few errors I’ve found too):

SAVE DICTIONARY

def writeDict(values, name):
    writeName = DIR+name+'.json'
    with open(writeName, "w") as outfile:
        json.dump(values, outfile)

READ DICTIONARY

def readDict(name):
    readName = DIR+name+'.json'
    try:
        with open(readName, "r") as infile:
            dictValues = json.load(infile)
            return(dictValues)
    except IOError as e:
        print(e)
        return('None')
    except ValueError as e:
        print(e)
        return('None')

Hope this helps!


回答 9

这是一个对我有用的实现,并删除了所有nan(假设它们是简单的对象(列表或字典)):

from numpy import isnan

def remove_nans(my_obj, val=None):
    if isinstance(my_obj, list):
        for i, item in enumerate(my_obj):
            if isinstance(item, list) or isinstance(item, dict):
                my_obj[i] = remove_nans(my_obj[i], val=val)

            else:
                try:
                    if isnan(item):
                        my_obj[i] = val
                except Exception:
                    pass

    elif isinstance(my_obj, dict):
        for key, item in my_obj.iteritems():
            if isinstance(item, list) or isinstance(item, dict):
                my_obj[key] = remove_nans(my_obj[key], val=val)

            else:
                try:
                    if isnan(item):
                        my_obj[key] = val
                except Exception:
                    pass

    return my_obj

Here is an implementation that work for me and removed all nans (assuming these are simple object (list or dict)):

from numpy import isnan

def remove_nans(my_obj, val=None):
    if isinstance(my_obj, list):
        for i, item in enumerate(my_obj):
            if isinstance(item, list) or isinstance(item, dict):
                my_obj[i] = remove_nans(my_obj[i], val=val)

            else:
                try:
                    if isnan(item):
                        my_obj[i] = val
                except Exception:
                    pass

    elif isinstance(my_obj, dict):
        for key, item in my_obj.iteritems():
            if isinstance(item, list) or isinstance(item, dict):
                my_obj[key] = remove_nans(my_obj[key], val=val)

            else:
                try:
                    if isnan(item):
                        my_obj[key] = val
                except Exception:
                    pass

    return my_obj

回答 10

这是一个不同的答案,但这可能有助于帮助试图保存数据然后再次读取的人们。
有一个比泡菜快和容易的hi。
我试图保存并在泡菜转储中阅读它,但是阅读时有很多问题,浪费了一个小时,尽管我正在处理自己的数据以创建聊天机器人,但仍然找不到解决方案。

vec_x并且vec_y是numpy数组:

data=[vec_x,vec_y]
hkl.dump( data, 'new_data_file.hkl' )

然后,您只需阅读并执行以下操作:

data2 = hkl.load( 'new_data_file.hkl' )

This is a different answer, but this might help to help people who are trying to save data and then read it again.
There is hickle which is faster than pickle and easier.
I tried to save and read it in pickle dump but while reading there were lot of problems and wasted an hour and still didn’t find solution though I was working on my own data to create a chat bot.

vec_x and vec_y are numpy arrays:

data=[vec_x,vec_y]
hkl.dump( data, 'new_data_file.hkl' )

Then you just read it and perform the operations:

data2 = hkl.load( 'new_data_file.hkl' )

回答 11

可以使用检查类型来简化循环:

with open("jsondontdoit.json", 'w') as fp:
    for key in bests.keys():
        if type(bests[key]) == np.ndarray:
            bests[key] = bests[key].tolist()
            continue
        for idx in bests[key]:
            if type(bests[key][idx]) == np.ndarray:
                bests[key][idx] = bests[key][idx].tolist()
    json.dump(bests, fp)
    fp.close()

May do simple for loop with checking types:

with open("jsondontdoit.json", 'w') as fp:
    for key in bests.keys():
        if type(bests[key]) == np.ndarray:
            bests[key] = bests[key].tolist()
            continue
        for idx in bests[key]:
            if type(bests[key][idx]) == np.ndarray:
                bests[key][idx] = bests[key][idx].tolist()
    json.dump(bests, fp)
    fp.close()

回答 12

使用NumpyEncoder它将成功处理json转储。不抛出-NumPy数组不是JSON可序列化的

import numpy as np
import json
from numpyencoder import NumpyEncoder
arr = array([   0,  239,  479,  717,  952, 1192, 1432, 1667], dtype=int64) 
json.dumps(arr,cls=NumpyEncoder)

use NumpyEncoder it will process json dump successfully.without throwing – NumPy array is not JSON serializable

import numpy as np
import json
from numpyencoder import NumpyEncoder
arr = array([   0,  239,  479,  717,  952, 1192, 1432, 1667], dtype=int64) 
json.dumps(arr,cls=NumpyEncoder)

回答 13

TypeError:array([[0.46872085,0.67374235,1.0218339,0.13210179,0.5440686,0.9140083,0.58720225,0.2199381]],dtype = float32)不是JSON可序列化的

当我期望以json格式响应时,尝试将数据列表传递给model.predict()时,抛出了上述错误。

> 1        json_file = open('model.json','r')
> 2        loaded_model_json = json_file.read()
> 3        json_file.close()
> 4        loaded_model = model_from_json(loaded_model_json)
> 5        #load weights into new model
> 6        loaded_model.load_weights("model.h5")
> 7        loaded_model.compile(optimizer='adam', loss='mean_squared_error')
> 8        X =  [[874,12450,678,0.922500,0.113569]]
> 9        d = pd.DataFrame(X)
> 10       prediction = loaded_model.predict(d)
> 11       return jsonify(prediction)

但幸运的是找到了解决抛出错误的提示对象的序列化仅适用于以下转换映射应采用以下方式object-dict array-list string-string integer-integer

如果您向上滚动以查看第10行的代码,则这行代码将生成array数据类型的输出,当您尝试将array转换为json格式时,这是不可能的。

最终我找到了解决方案,只需通过遵循以下几行代码将获得的输出转换为类型列表即可

预测=加载模型。预测(d)
列表类型=预测。列表()返回jsonify(列表类型)

hoo!终于得到了预期的输出,

TypeError: array([[0.46872085, 0.67374235, 1.0218339 , 0.13210179, 0.5440686 , 0.9140083 , 0.58720225, 0.2199381 ]], dtype=float32) is not JSON serializable

The above-mentioned error was thrown when i tried to pass of list of data to model.predict() when i was expecting the response in json format.

> 1        json_file = open('model.json','r')
> 2        loaded_model_json = json_file.read()
> 3        json_file.close()
> 4        loaded_model = model_from_json(loaded_model_json)
> 5        #load weights into new model
> 6        loaded_model.load_weights("model.h5")
> 7        loaded_model.compile(optimizer='adam', loss='mean_squared_error')
> 8        X =  [[874,12450,678,0.922500,0.113569]]
> 9        d = pd.DataFrame(X)
> 10       prediction = loaded_model.predict(d)
> 11       return jsonify(prediction)

But luckily found the hint to resolve the error that was throwing The serializing of the objects is applicable only for the following conversion Mapping should be in following way object – dict array – list string – string integer – integer

If you scroll up to see the line number 10 prediction = loaded_model.predict(d) where this line of code was generating the output of type array datatype , when you try to convert array to json format its not possible

Finally i found the solution just by converting obtained output to the type list by following lines of code

prediction = loaded_model.predict(d)
listtype = prediction.tolist() return jsonify(listtype)

Bhoom! finally got the expected output,


让Django提供可下载文件

问题:让Django提供可下载文件

我希望站点上的用户能够下载路径被遮盖的文件,以便不能直接下载它们。

例如,我希望URL如下所示: http://example.com/download/?f=somefile.txt

在服务器上,我知道所有可下载文件都位于文件夹中/home/user/files/

有没有一种方法可以使Django提供该文件供下载,而不是尝试查找URL和查看以显示该文件?

I want users on the site to be able to download files whose paths are obscured so they cannot be directly downloaded.

For instance, I’d like the URL to be something like this: http://example.com/download/?f=somefile.txt

And on the server, I know that all downloadable files reside in the folder /home/user/files/.

Is there a way to make Django serve that file for download as opposed to trying to find a URL and View to display it?


回答 0

对于“两全其美”,您可以将S.Lott的解决方案与xsendfile模块结合使用:django生成文件(或文件本身)的路径,但是实际的文件服务由Apache / Lighttpd处理。设置mod_xsendfile后,与视图集成将需要几行代码:

from django.utils.encoding import smart_str

response = HttpResponse(mimetype='application/force-download') # mimetype is replaced by content_type for django 1.7
response['Content-Disposition'] = 'attachment; filename=%s' % smart_str(file_name)
response['X-Sendfile'] = smart_str(path_to_file)
# It's usually a good idea to set the 'Content-Length' header too.
# You can also set any other required headers: Cache-Control, etc.
return response

当然,只有在您可以控制服务器或托管公司已经设置了mod_xsendfile的情况下,这才起作用。

编辑:

django 1.7将mimetype替换为content_type

response = HttpResponse(content_type='application/force-download')  

编辑: 对于nginx检查,它使用X-Accel-Redirect而不是apacheX-Sendfile标头。

For the “best of both worlds” you could combine S.Lott’s solution with the xsendfile module: django generates the path to the file (or the file itself), but the actual file serving is handled by Apache/Lighttpd. Once you’ve set up mod_xsendfile, integrating with your view takes a few lines of code:

from django.utils.encoding import smart_str

response = HttpResponse(mimetype='application/force-download') # mimetype is replaced by content_type for django 1.7
response['Content-Disposition'] = 'attachment; filename=%s' % smart_str(file_name)
response['X-Sendfile'] = smart_str(path_to_file)
# It's usually a good idea to set the 'Content-Length' header too.
# You can also set any other required headers: Cache-Control, etc.
return response

Of course, this will only work if you have control over your server, or your hosting company has mod_xsendfile already set up.

EDIT:

mimetype is replaced by content_type for django 1.7

response = HttpResponse(content_type='application/force-download')  

EDIT: For nginx check this, it uses X-Accel-Redirect instead of apache X-Sendfile header.


回答 1

“下载”只是HTTP标头更改。

请参阅http://docs.djangoproject.com/en/dev/ref/request-response/#telling-the-browser-to-treat-the-response-as-a-file-attachment了解如何通过下载进行响应。

您只需要一个URL定义即可"/download"

请求GETPOST字典将包含该"f=somefile.txt"信息。

您的视图函数将简单地将基本路径与“ f”值合并,打开文件,创建并返回响应对象。它应该少于12行代码。

A “download” is simply an HTTP header change.

See http://docs.djangoproject.com/en/dev/ref/request-response/#telling-the-browser-to-treat-the-response-as-a-file-attachment for how to respond with a download.

You only need one URL definition for "/download".

The request’s GET or POST dictionary will have the "f=somefile.txt" information.

Your view function will simply merge the base path with the “f” value, open the file, create and return a response object. It should be less than 12 lines of code.


回答 2

对于一个非常简单但效率不高或可扩展的解决方案,您可以仅使用内置的django serve视图。这对于快速原型或一次性工作非常有用,但是正如在整个问题中已经提到的那样,在生产中应该使用apache或nginx之类的东西。

from django.views.static import serve
filepath = '/some/path/to/local/file.txt'
return serve(request, os.path.basename(filepath), os.path.dirname(filepath))

For a very simple but not efficient or scalable solution, you can just use the built in django serve view. This is excellent for quick prototypes or one-off work, but as has been mentioned throughout this question, you should use something like apache or nginx in production.

from django.views.static import serve
filepath = '/some/path/to/local/file.txt'
return serve(request, os.path.basename(filepath), os.path.dirname(filepath))

回答 3

S.Lott具有“良好” /简单的解决方案,而elo80ka具有“最佳” /高效的解决方案。这是一个“更好” /中间的解决方案-没有服务器设置,但是对于大型文件,比简单的修复更有效率:

http://djangosnippets.org/snippets/365/

基本上,Django仍会处理文件的提供,但不会立即将整个内容加载到内存中。这使您的服务器可以(缓慢地)提供一个大文件,而不会增加内存使用量。

同样,S.Lott的X-SendFile对于较大的文件仍然更好。但是,如果您不能或不想为此烦恼,那么此中间解决方案将为您带来更高的效率,而无需麻烦。

S.Lott has the “good”/simple solution, and elo80ka has the “best”/efficient solution. Here is a “better”/middle solution – no server setup, but more efficient for large files than the naive fix:

http://djangosnippets.org/snippets/365/

Basically, Django still handles serving the file but does not load the whole thing into memory at once. This allows your server to (slowly) serve a big file without ramping up the memory usage.

Again, S.Lott’s X-SendFile is still better for larger files. But if you can’t or don’t want to bother with that, then this middle solution will gain you better efficiency without the hassle.


回答 4

尝试过@Rocketmonkeys解决方案,但下载的文件存储为* .bin并具有随机名称。那当然不好。从@ elo80ka添加另一行解决了该问题。
这是我现在使用的代码:

from wsgiref.util import FileWrapper
from django.http import HttpResponse

filename = "/home/stackoverflow-addict/private-folder(not-porn)/image.jpg"
wrapper = FileWrapper(file(filename))
response = HttpResponse(wrapper, content_type='text/plain')
response['Content-Disposition'] = 'attachment; filename=%s' % os.path.basename(filename)
response['Content-Length'] = os.path.getsize(filename)
return response

现在,您可以将文件存储在私有目录中(不在/ media或/ public_html内部),并通过django将它们公开给某些用户或在某些情况下。
希望能帮助到你。

感谢@ elo80ka,@ S.Lott和@Rocketmonkeys的答案,得到了结合所有这些的完美解决方案=)

Tried @Rocketmonkeys solution but downloaded files were being stored as *.bin and given random names. That’s not fine of course. Adding another line from @elo80ka solved the problem.
Here is the code I’m using now:

from wsgiref.util import FileWrapper
from django.http import HttpResponse

filename = "/home/stackoverflow-addict/private-folder(not-porn)/image.jpg"
wrapper = FileWrapper(file(filename))
response = HttpResponse(wrapper, content_type='text/plain')
response['Content-Disposition'] = 'attachment; filename=%s' % os.path.basename(filename)
response['Content-Length'] = os.path.getsize(filename)
return response

You can now store files in a private directory (not inside /media nor /public_html) and expose them via django to certain users or under certain circumstances.
Hope it helps.

Thanks to @elo80ka, @S.Lott and @Rocketmonkeys for the answers, got the perfect solution combining all of them =)


回答 5

仅提及Django 1.10中可用的FileResponse对象

编辑:在搜索通过Django流文件的简单方法时遇到了我自己的答案,所以这是一个更完整的示例(对我而言)。假定FileField名称为imported_file

views.py

from django.views.generic.detail import DetailView   
from django.http import FileResponse
class BaseFileDownloadView(DetailView):
  def get(self, request, *args, **kwargs):
    filename=self.kwargs.get('filename', None)
    if filename is None:
      raise ValueError("Found empty filename")
    some_file = self.model.objects.get(imported_file=filename)
    response = FileResponse(some_file.imported_file, content_type="text/csv")
    # https://docs.djangoproject.com/en/1.11/howto/outputting-csv/#streaming-large-csv-files
    response['Content-Disposition'] = 'attachment; filename="%s"'%filename
    return response

class SomeFileDownloadView(BaseFileDownloadView):
    model = SomeModel

urls.py

...
url(r'^somefile/(?P<filename>[-\w_\\-\\.]+)$', views.SomeFileDownloadView.as_view(), name='somefile-download'),
...

Just mentioning the FileResponse object available in Django 1.10

Edit: Just ran into my own answer while searching for an easy way to stream files via Django, so here is a more complete example (to future me). It assumes that the FileField name is imported_file

views.py

from django.views.generic.detail import DetailView   
from django.http import FileResponse
class BaseFileDownloadView(DetailView):
  def get(self, request, *args, **kwargs):
    filename=self.kwargs.get('filename', None)
    if filename is None:
      raise ValueError("Found empty filename")
    some_file = self.model.objects.get(imported_file=filename)
    response = FileResponse(some_file.imported_file, content_type="text/csv")
    # https://docs.djangoproject.com/en/1.11/howto/outputting-csv/#streaming-large-csv-files
    response['Content-Disposition'] = 'attachment; filename="%s"'%filename
    return response

class SomeFileDownloadView(BaseFileDownloadView):
    model = SomeModel

urls.py

...
url(r'^somefile/(?P<filename>[-\w_\\-\\.]+)$', views.SomeFileDownloadView.as_view(), name='somefile-download'),
...

回答 6

上面提到过,mod_xsendfile方法不允许文件名中包含非ASCII字符。

出于这个原因,我有一个可用于mod_xsendfile的补丁,只要名称是url编码的,它将允许发送任何文件,以及附加的标头:

X-SendFile-Encoding: url

也发送。

http://ben.timby.com/?p=149

It was mentioned above that the mod_xsendfile method does not allow for non-ASCII characters in filenames.

For this reason, I have a patch available for mod_xsendfile that will allow any file to be sent, as long as the name is url encoded, and the additional header:

X-SendFile-Encoding: url

Is sent as well.

http://ben.timby.com/?p=149


回答 7

试试:https//pypi.python.org/pypi/django-sendfile/

“一旦Django检查了权限,将文件上传到Web服务器(例如,带有mod_xsendfile的Apache)的抽象提取。”

Try: https://pypi.python.org/pypi/django-sendfile/

“Abstraction to offload file uploads to web-server (e.g. Apache with mod_xsendfile) once Django has checked permissions etc.”


回答 8

您应该使用流行服务器(例如 生产环境)apachenginx生产环境中提供的sendfile api 。多年以来,我一直在使用这些服务器的sendfile api保护文件。然后创建了一个简单的基于django的中间件应用程序,适合开发和生产目的。您可以在此处访问源代码。
更新:在新版本中,python提供程序使用django(FileResponse如果可用),并且还增加了对从lighthttp,caddy到hiawatha的许多服务器实现的支持

用法

pip install django-fileprovider
  • fileprovider应用添加到INSTALLED_APPS设置,
  • 添加fileprovider.middleware.FileProviderMiddlewareMIDDLEWARE_CLASSES设置
  • FILEPROVIDER_NAME设置设置为生产nginxapache在生产中使用,默认情况下是python出于开发目的。

在基于类或函数的视图中,将响应头X-File值设置为文件的绝对路径。例如,

def hello(request):  
   // code to check or protect the file from unauthorized access
   response = HttpResponse()  
   response['X-File'] = '/absolute/path/to/file'  
   return response  

django-fileprovider 以仅需最小程度修改代码的方式实现。

Nginx配置

为了防止文件直接访问,您可以将配置设置为

 location /files/ {
  internal;
  root   /home/sideffect0/secret_files/;
 }

在这里nginx设置位置网址/files/只供内部访问,如果您使用上述配置,则可以将X-File设置为

response['X-File'] = '/files/filename.extension' 

通过使用nginx配置执行此操作,文件将受到保护,您也可以从Django控制文件 views

You should use sendfile apis given by popular servers like apache or nginx in production. Many years i was using sendfile api of these servers for protecting files. Then created a simple middleware based django app for this purpose suitable for both development & production purpose.You can access the source code here.
UPDATE: in new version python provider uses django FileResponse if available and also adds support for many server implementations from lighthttp, caddy to hiawatha

Usage

pip install django-fileprovider
  • add fileprovider app to INSTALLED_APPS settings,
  • add fileprovider.middleware.FileProviderMiddleware to MIDDLEWARE_CLASSES settings
  • set FILEPROVIDER_NAME settings to nginx or apache in production, by default it is python for development purpose.

in your classbased or function views set response header X-File value to absolute path to the file. For example,

def hello(request):  
   // code to check or protect the file from unauthorized access
   response = HttpResponse()  
   response['X-File'] = '/absolute/path/to/file'  
   return response  

django-fileprovider impemented in a way that your code will need only minimum modification.

Nginx configuration

To protect file from direct access you can set the configuration as

 location /files/ {
  internal;
  root   /home/sideffect0/secret_files/;
 }

Here nginx sets a location url /files/ only access internaly, if you are using above configuration you can set X-File as,

response['X-File'] = '/files/filename.extension' 

By doing this with nginx configuration, the file will be protected & also you can control the file from django views


回答 9

Django建议您使用另一台服务器来提供静态媒体(在同一台计算机上运行的另一台服务器就可以了。)他们建议使用诸如lighttp这样的服务器。

设置非常简单。然而。如果“ somefile.txt”是根据请求生成的(内容是动态的),那么您可能希望django提供它。

Django Docs-静态文件

Django recommend that you use another server to serve static media (another server running on the same machine is fine.) They recommend the use of such servers as lighttp.

This is very simple to set up. However. if ‘somefile.txt’ is generated on request (content is dynamic) then you may want django to serve it.

Django Docs – Static Files


回答 10

def qrcodesave(request): 
    import urllib2;   
    url ="http://chart.apis.google.com/chart?cht=qr&chs=300x300&chl=s&chld=H|0"; 
    opener = urllib2.urlopen(url);  
    content_type = "application/octet-stream"
    response = HttpResponse(opener.read(), content_type=content_type)
    response["Content-Disposition"]= "attachment; filename=aktel.png"
    return response 
def qrcodesave(request): 
    import urllib2;   
    url ="http://chart.apis.google.com/chart?cht=qr&chs=300x300&chl=s&chld=H|0"; 
    opener = urllib2.urlopen(url);  
    content_type = "application/octet-stream"
    response = HttpResponse(opener.read(), content_type=content_type)
    response["Content-Disposition"]= "attachment; filename=aktel.png"
    return response 

回答 11

另一个要研究的项目:http: //readthedocs.org/docs/django-private-files/en/latest/usage.html看起来不错,我自己还没有测试过。

基本上,该项目抽象了mod_xsendfile配置,并允许您执行以下操作:

from django.db import models
from django.contrib.auth.models import User
from private_files import PrivateFileField

def is_owner(request, instance):
    return (not request.user.is_anonymous()) and request.user.is_authenticated and
                   instance.owner.pk = request.user.pk

class FileSubmission(models.Model):
    description = models.CharField("description", max_length = 200)
        owner = models.ForeignKey(User)
    uploaded_file = PrivateFileField("file", upload_to = 'uploads', condition = is_owner)

Another project to have a look at: http://readthedocs.org/docs/django-private-files/en/latest/usage.html Looks promissing, haven’t tested it myself yet tho.

Basically the project abstracts the mod_xsendfile configuration and allows you to do things like:

from django.db import models
from django.contrib.auth.models import User
from private_files import PrivateFileField

def is_owner(request, instance):
    return (not request.user.is_anonymous()) and request.user.is_authenticated and
                   instance.owner.pk = request.user.pk

class FileSubmission(models.Model):
    description = models.CharField("description", max_length = 200)
        owner = models.ForeignKey(User)
    uploaded_file = PrivateFileField("file", upload_to = 'uploads', condition = is_owner)

回答 12

我再一次遇到了同样的问题,因此使用xsendfile模块和django-filelibrary的 auth视图修饰符实现了该问题。随意将其用作您自己的解决方案的灵感。

https://github.com/danielsokolowski/django-filelibrary

I have faced the same problem more then once and so implemented using xsendfile module and auth view decorators the django-filelibrary. Feel free to use it as inspiration for your own solution.

https://github.com/danielsokolowski/django-filelibrary


回答 13

使用https://github.com/johnsensible/django-sendfile提供对静态html文件夹的受保护访问:https : //gist.github.com/iutinvg/9907731


回答 14

我做了一个项目。你可以看一下我的github仓库:

https://github.com/nishant-boro/django-rest-framework-download-expert

该模块提供了一种使用Apache模块Xsendfile在django rest框架中提供文件下载服务的简单方法。它还具有附加功能,仅向属于特定组的用户提供下载服务

I did a project on this. You can look at my github repo:

https://github.com/nishant-boro/django-rest-framework-download-expert

This module provides a simple way to serve files for download in django rest framework using Apache module Xsendfile. It also has an additional feature of serving downloads only to users belonging to a particular group


Django:显示选择值

问题:Django:显示选择值

models.py:

class Person(models.Model):
    name = models.CharField(max_length=200)
    CATEGORY_CHOICES = (
        ('M', 'Male'),
        ('F', 'Female'),
    )
    gender = models.CharField(max_length=200, choices=CATEGORY_CHOICES)
    to_be_listed = models.BooleanField(default=True)
    description = models.CharField(max_length=20000, blank=True)

views.py:

def index(request):
    latest_person_list2 = Person.objects.filter(to_be_listed=True)
    return object_list(request, template_name='polls/schol.html',
                       queryset=latest_person_list, paginate_by=5)

在模板上,当我调用时person.gender,我得到'M'or 'F'而不是'Male'or 'Female'

如何显示值('Male''Female')而不是代码('M'/ 'F')?

models.py:

class Person(models.Model):
    name = models.CharField(max_length=200)
    CATEGORY_CHOICES = (
        ('M', 'Male'),
        ('F', 'Female'),
    )
    gender = models.CharField(max_length=200, choices=CATEGORY_CHOICES)
    to_be_listed = models.BooleanField(default=True)
    description = models.CharField(max_length=20000, blank=True)

views.py:

def index(request):
    latest_person_list2 = Person.objects.filter(to_be_listed=True)
    return object_list(request, template_name='polls/schol.html',
                       queryset=latest_person_list, paginate_by=5)

On the template, when I call person.gender, I get 'M' or 'F' instead of 'Male' or 'Female'.

How to display the value ('Male' or 'Female') instead of the code ('M'/'F')?


回答 0

看来您处在正确的轨道上- get_FOO_display()无疑是您想要的:

模板中,您不包括()方法名称。请执行下列操作:

{{ person.get_gender_display }}

It looks like you were on the right track – get_FOO_display() is most certainly what you want:

In templates, you don’t include () in the name of a method. Do the following:

{{ person.get_gender_display }}

回答 1

对于每个设置了选项的字段,该对象将具有get_FOO_display()方法,其中FOO是字段的名称。此方法返回该字段的“人类可读”值。

在视图中

person = Person.objects.filter(to_be_listed=True)
context['gender'] = person.get_gender_display()

在模板中

{{ person.get_gender_display }}

get_FOO_display()的文档

For every field that has choices set, the object will have a get_FOO_display() method, where FOO is the name of the field. This method returns the “human-readable” value of the field.

In Views

person = Person.objects.filter(to_be_listed=True)
context['gender'] = person.get_gender_display()

In Template

{{ person.get_gender_display }}

Documentation of get_FOO_display()


回答 2

其他人指出,您需要的是get_FOO_display方法。我正在使用这个:

def get_type(self):
    return [i[1] for i in Item._meta.get_field('type').choices if i[0] == self.type][0]

遍历特定项目的所有选择,直到找到与项目类型匹配的项目

Others have pointed out that a get_FOO_display method is what you need. I’m using this:

def get_type(self):
    return [i[1] for i in Item._meta.get_field('type').choices if i[0] == self.type][0]

which iterates over all of the choices that a particular item has until it finds the one that matches the items type


您需要安装postgresql-server-dev-XY来构建服务器端扩展,或者安装libpq-dev来构建客户端应用程序

问题:您需要安装postgresql-server-dev-XY来构建服务器端扩展,或者安装libpq-dev来构建客户端应用程序

我正在使用virtualenv处理Django项目,并将其连接到本地postgres数据库。当我运行项目时说,

ImportError: No module named psycopg2.extensions

然后我用这个命令来安装

pip install psycopg2

然后在安装过程中会出现以下错误。

Downloading/unpacking psycopg2==2.4.4
  Downloading psycopg2-2.4.4.tar.gz (648kB): 648kB downloaded
  Running setup.py (path:/home/muhammadtaqi/Projects/MyProjects/OnlineElectionCampaign/venv/build/psycopg2/setup.py) egg_info for package psycopg2

    Error: You need to install postgresql-server-dev-X.Y for building a server-side extension or libpq-dev for building a client-side application.

    Complete output from command python setup.py egg_info:
    running egg_info

creating pip-egg-info/psycopg2.egg-info

writing pip-egg-info/psycopg2.egg-info/PKG-INFO

writing top-level names to pip-egg-info/psycopg2.egg-info/top_level.txt

writing dependency_links to pip-egg-info/psycopg2.egg-info/dependency_links.txt

writing manifest file 'pip-egg-info/psycopg2.egg-info/SOURCES.txt'

warning: manifest_maker: standard file '-c' not found



Error: You need to install postgresql-server-dev-X.Y for building a server-side extension or libpq-dev for building a client-side application.



----------------------------------------
Cleaning up...
Command python setup.py egg_info failed with error code 1 in /home/muhammadtaqi/Projects/MyProjects/OnlineElectionCampaign/venv/build/psycopg2
Storing debug log for failure in /home/muhammadtaqi/.pip/pip.log

I am working on Django project with virtualenv and connect it to local postgres database. when i run the project is says,

ImportError: No module named psycopg2.extensions

then i used this command to install

pip install psycopg2

then during the installation it gives following error.

Downloading/unpacking psycopg2==2.4.4
  Downloading psycopg2-2.4.4.tar.gz (648kB): 648kB downloaded
  Running setup.py (path:/home/muhammadtaqi/Projects/MyProjects/OnlineElectionCampaign/venv/build/psycopg2/setup.py) egg_info for package psycopg2

    Error: You need to install postgresql-server-dev-X.Y for building a server-side extension or libpq-dev for building a client-side application.

    Complete output from command python setup.py egg_info:
    running egg_info

creating pip-egg-info/psycopg2.egg-info

writing pip-egg-info/psycopg2.egg-info/PKG-INFO

writing top-level names to pip-egg-info/psycopg2.egg-info/top_level.txt

writing dependency_links to pip-egg-info/psycopg2.egg-info/dependency_links.txt

writing manifest file 'pip-egg-info/psycopg2.egg-info/SOURCES.txt'

warning: manifest_maker: standard file '-c' not found



Error: You need to install postgresql-server-dev-X.Y for building a server-side extension or libpq-dev for building a client-side application.



----------------------------------------
Cleaning up...
Command python setup.py egg_info failed with error code 1 in /home/muhammadtaqi/Projects/MyProjects/OnlineElectionCampaign/venv/build/psycopg2
Storing debug log for failure in /home/muhammadtaqi/.pip/pip.log

回答 0

使用以下命令,将解决错误:

sudo apt-get install postgresql

然后开火:

sudo apt-get install python-psycopg2

最后:

sudo apt-get install libpq-dev

Use these following commands, this will solve the error:

sudo apt-get install postgresql

then fire:

sudo apt-get install python-psycopg2

and last:

sudo apt-get install libpq-dev

回答 1

我只是从终端以root身份运行此命令,问题就解决了,

sudo apt-get install -y postgis postgresql-9.3-postgis-2.1
pip install psycopg2

要么

sudo apt-get install libpq-dev python-dev
pip install psycopg2

I just run this command as a root from terminal and problem is solved,

sudo apt-get install -y postgis postgresql-9.3-postgis-2.1
pip install psycopg2

or

sudo apt-get install libpq-dev python-dev
pip install psycopg2

回答 2

只需安装libpq-dev

$ sudo apt-get install libpq-dev

Just install libpq-dev

$ sudo apt-get install libpq-dev

回答 3

对我来说,这个简单的命令解决了这个问题:

sudo apt-get install postgresql postgresql-contrib libpq-dev python-dev

然后我可以做:

 pip install psycopg2

For me this simple command solved the problem:

sudo apt-get install postgresql postgresql-contrib libpq-dev python-dev

Then I can do:

 pip install psycopg2

回答 4

对于Python 3,我做到了:

sudo apt install python3-dev postgresql postgresql-contrib python3-psycopg2 libpq-dev

然后我能够做到:

pip3 install psycopg2

For Python 3, I did:

sudo apt install python3-dev postgresql postgresql-contrib python3-psycopg2 libpq-dev

and then I was able to do:

pip3 install psycopg2

回答 5

他们更改了psycopg2的包装。安装二进制版本为我解决了此问题。如果您想自己编译二进制文件,以上答案仍然有效。

参见http://initd.org/psycopg/docs/news.html#what-s-new-in-psycopg-2-8

默认情况下不再安装二进制软件包。必须明确使用“ psycopg2-binary”软件包。

还有http://initd.org/psycopg/docs/install.html#binary-install-from-pypi

因此,如果您不需要编译自己的二进制文件,请使用:

pip install psycopg2-binary

They changed the packaging for psycopg2. Installing the binary version fixed this issue for me. The above answers still hold up if you want to compile the binary yourself.

See http://initd.org/psycopg/docs/news.html#what-s-new-in-psycopg-2-8.

Binary packages no longer installed by default. The ‘psycopg2-binary’ package must be used explicitly.

And http://initd.org/psycopg/docs/install.html#binary-install-from-pypi

So if you don’t need to compile your own binary, use:

pip install psycopg2-binary

回答 6

您必须设置postgresql-server-dev-XY,其中XY为您的服务器版本,它将在模块上安装libpq-dev和其他服务器变量,以进行服务器端开发。就我而言

apt-get install postgresql-server-dev-9.5

读取软件包列表…完成构建依赖关系树读取状态信息…完成以下软件包已自动安装,不再需要:libmysqlclient18 mysql-common使用’apt-get autoremove’删除它们。将安装以下额外的软件包:
libpq-dev建议的软件包:postgresql-doc-10将安装以下新软件包:libpq-dev postgresql-server-dev-9.5

就你而言

sudo apt-get install postgresql-server-dev-X.Y
sudo apt-get install python-psycopg2

You must setup postgresql-server-dev-X.Y, where X.Y. your’s servers version, and it will install libpq-dev and other servers variables at modules for server side developing. In my case it was

apt-get install postgresql-server-dev-9.5

Reading package lists… Done Building dependency tree Reading state information… Done The following packages were automatically installed and are no longer required: libmysqlclient18 mysql-common Use ‘apt-get autoremove’ to remove them. The following extra packages will be installed:
libpq-dev Suggested packages: postgresql-doc-10 The following NEW packages will be installed: libpq-dev postgresql-server-dev-9.5

In your’s case

sudo apt-get install postgresql-server-dev-X.Y
sudo apt-get install python-psycopg2

回答 7

我在Ubuntu 18.04上使用了虚拟环境,并且由于我只想将其安装为客户端,所以我只需要这样做:

sudo apt install libpq-dev
pip install psycopg2

并安装没有问题。当然,您可以像其他答案一样使用二进制文件,但是我更喜欢这种解决方案,因为它是在requirements.txt文件中声明的。

I was using a virtual environment on Ubuntu 18.04, and since I only wanted to install it as a client, I only had to do:

sudo apt install libpq-dev
pip install psycopg2

And installed without problems. Of course, you can use the binary as other answers said, but I preferred this solution since it was stated in a requirements.txt file.


Django设置默认表单值

问题:Django设置默认表单值

我有一个模型如下:

class TankJournal(models.Model):
    user = models.ForeignKey(User)
    tank = models.ForeignKey(TankProfile)
    ts = models.IntegerField(max_length=15)
    title = models.CharField(max_length=50)
    body = models.TextField()

我也有上述模型的模型形式,如下所示:

class JournalForm(ModelForm):
    tank = forms.IntegerField(widget=forms.HiddenInput()) 

    class Meta:
        model = TankJournal
        exclude = ('user','ts')

我想知道如何为该坦克隐藏字段设置默认值。这是我到目前为止显示/保存表格的功能:

def addJournal(request, id=0):
    if not request.user.is_authenticated():
        return HttpResponseRedirect('/')

    # checking if they own the tank
    from django.contrib.auth.models import User
    user = User.objects.get(pk=request.session['id'])

    if request.method == 'POST':
        form = JournalForm(request.POST)
        if form.is_valid():
            obj = form.save(commit=False)

            # setting the user and ts
            from time import time
            obj.ts = int(time())
            obj.user = user

            obj.tank = TankProfile.objects.get(pk=form.cleaned_data['tank_id'])

            # saving the test
            obj.save()

    else:
        form = JournalForm()

    try:
        tank = TankProfile.objects.get(user=user, id=id)
    except TankProfile.DoesNotExist:
        return HttpResponseRedirect('/error/')

I have a Model as follows:

class TankJournal(models.Model):
    user = models.ForeignKey(User)
    tank = models.ForeignKey(TankProfile)
    ts = models.IntegerField(max_length=15)
    title = models.CharField(max_length=50)
    body = models.TextField()

I also have a model form for the above model as follows:

class JournalForm(ModelForm):
    tank = forms.IntegerField(widget=forms.HiddenInput()) 

    class Meta:
        model = TankJournal
        exclude = ('user','ts')

I want to know how to set the default value for that tank hidden field. Here is my function to show/save the form so far:

def addJournal(request, id=0):
    if not request.user.is_authenticated():
        return HttpResponseRedirect('/')

    # checking if they own the tank
    from django.contrib.auth.models import User
    user = User.objects.get(pk=request.session['id'])

    if request.method == 'POST':
        form = JournalForm(request.POST)
        if form.is_valid():
            obj = form.save(commit=False)

            # setting the user and ts
            from time import time
            obj.ts = int(time())
            obj.user = user

            obj.tank = TankProfile.objects.get(pk=form.cleaned_data['tank_id'])

            # saving the test
            obj.save()

    else:
        form = JournalForm()

    try:
        tank = TankProfile.objects.get(user=user, id=id)
    except TankProfile.DoesNotExist:
        return HttpResponseRedirect('/error/')

回答 0

您可以使用初始被解释这里

您有两个选择,可以在调用表单构造函数时填充值:

form = JournalForm(initial={'tank': 123})

或在表单定义中设置值:

tank = forms.IntegerField(widget=forms.HiddenInput(), initial=123) 

You can use initial which is explained here

You have two options either populate the value when calling form constructor:

form = JournalForm(initial={'tank': 123})

or set the value in the form definition:

tank = forms.IntegerField(widget=forms.HiddenInput(), initial=123) 

回答 1

其他解决方案:创建表单后设置初始:

form.fields['tank'].initial = 123

Other solution: Set initial after creating the form:

form.fields['tank'].initial = 123

回答 2

如果要通过POST值创建模型形式,则可以通过以下方式分配初始值:

form = SomeModelForm(request.POST, initial={"option": "10"})

https://docs.djangoproject.com/en/1.10/topics/forms/modelforms/#providing-initial-values

If you are creating modelform from POST values initial can be assigned this way:

form = SomeModelForm(request.POST, initial={"option": "10"})

https://docs.djangoproject.com/en/1.10/topics/forms/modelforms/#providing-initial-values


回答 3

我有另一个解决方案(如果其他人正在使用该模型中的以下方法,我会发布它):

class onlyUserIsActiveField(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(onlyUserIsActiveField, self).__init__(*args, **kwargs)
        self.fields['is_active'].initial = False

    class Meta:
        model = User
        fields = ['is_active']
        labels = {'is_active': 'Is Active'}
        widgets = {
            'is_active': forms.CheckboxInput( attrs={
                            'class':          'form-control bootstrap-switch',
                            'data-size':      'mini',
                            'data-on-color':  'success',
                            'data-on-text':   'Active',
                            'data-off-color': 'danger',
                            'data-off-text':  'Inactive',
                            'name':           'is_active',

            })
        }

缩写在__init__函数上定义为self.fields['is_active'].initial = False

I had this other solution (I’m posting it in case someone else as me is using the following method from the model):

class onlyUserIsActiveField(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(onlyUserIsActiveField, self).__init__(*args, **kwargs)
        self.fields['is_active'].initial = False

    class Meta:
        model = User
        fields = ['is_active']
        labels = {'is_active': 'Is Active'}
        widgets = {
            'is_active': forms.CheckboxInput( attrs={
                            'class':          'form-control bootstrap-switch',
                            'data-size':      'mini',
                            'data-on-color':  'success',
                            'data-on-text':   'Active',
                            'data-off-color': 'danger',
                            'data-off-text':  'Inactive',
                            'name':           'is_active',

            })
        }

The initial is definded on the __init__ function as self.fields['is_active'].initial = False


回答 4

我希望这可以帮助您:

form.instance.updatedby = form.cleaned_data['updatedby'] = request.user.id

I hope this can help you:

form.instance.updatedby = form.cleaned_data['updatedby'] = request.user.id

回答 5

Django文档所述initial不是default

  • 字段的初始值打算在HTML中显示。但是,如果用户删除该值,并最终为此字段发送回空白值,则该initial值将丢失。因此,您不会获得默认行为所期望的结果。

  • 默认行为是:如果值验证过程将采取data说法不包含字段的任何值。

要实现这一点,一种简单的方法是将initial和结合起来clean_<field>()

class JournalForm(ModelForm):
    tank = forms.IntegerField(widget=forms.HiddenInput(), initial=123) 

    (...)

    def clean_tank(self):
        if not self['tank'].html_name in self.data:
            return self.fields['tank'].initial
        return self.cleaned_data['tank']

As explained in Django docs, initial is not default.

  • The initial value of a field is intended to be displayed in an HTML . But if the user delete this value, and finally send back a blank value for this field, the initial value is lost. So you do not obtain what is expected by a default behaviour.

  • The default behaviour is : the value that validation process will take if data argument do not contain any value for the field.

To implement that, a straightforward way is to combine initial and clean_<field>():

class JournalForm(ModelForm):
    tank = forms.IntegerField(widget=forms.HiddenInput(), initial=123) 

    (...)

    def clean_tank(self):
        if not self['tank'].html_name in self.data:
            return self.fields['tank'].initial
        return self.cleaned_data['tank']

Django-render(),render_to_response()和direct_to_template()之间有什么区别?

问题:Django-render(),render_to_response()和direct_to_template()之间有什么区别?

最新的差值(在语言蟒/ django的小白可以理解)在之间的视图render()render_to_response()direct_to_template()

例如,来自Nathan Borror的基本应用示例

def comment_edit(request, object_id, template_name='comments/edit.html'):
    comment = get_object_or_404(Comment, pk=object_id, user=request.user)
    # ...
    return render(request, template_name, {
        'form': form,
        'comment': comment,
    })

但我也看到了

    return render_to_response(template_name, my_data_dictionary,
              context_instance=RequestContext(request))

    return direct_to_template(request, template_name, my_data_dictionary)

有什么区别,在任何特定情况下使用什么?

Whats the difference (in language a python/django noob can understand) in a view between render(), render_to_response() and direct_to_template()?

e.g. from Nathan Borror’s basic apps examples

def comment_edit(request, object_id, template_name='comments/edit.html'):
    comment = get_object_or_404(Comment, pk=object_id, user=request.user)
    # ...
    return render(request, template_name, {
        'form': form,
        'comment': comment,
    })

But I’ve also seen

    return render_to_response(template_name, my_data_dictionary,
              context_instance=RequestContext(request))

And

    return direct_to_template(request, template_name, my_data_dictionary)

Whats the difference, what to use in any particular situation?


回答 0

https://docs.djangoproject.com/zh-CN/1.8/topics/http/shortcuts/#render

render(request, template[, dictionary][, context_instance][, content_type][, status][, current_app])

render()是一个render_to_response在1.3中崭新的快捷方式的品牌,该快捷方式将自动使用RequestContext,从现在开始我肯定会使用它。


2020年编辑:应该指出的是render_to_response(),在Django 3.0中已将其删除

https://docs.djangoproject.com/zh-CN/1.8/topics/http/shortcuts/#render-to-response

render_to_response(template[, dictionary][, context_instance][, mimetype])¶

render_to_response是教程等中使用的标准渲染功能。要使用,RequestContext您必须指定context_instance=RequestContext(request)


https://docs.djangoproject.com/zh-CN/1.8/ref/generic-views/#django-views-generic-simple-direct-to-template

direct_to_template是我在视图中使用的通用视图(而不是在URL中使用),因为像新render()功能一样,它会自动使用RequestContext及其所有context_processors。

但是direct_to_template 应避免使用,因为不建议使用基于函数的通用视图。使用render还是实际使用的类,请参见https://docs.djangoproject.com/en/1.3/topics/generic-views-migration/

很高兴我很久没输入RequestContext了。

https://docs.djangoproject.com/en/1.8/topics/http/shortcuts/#render

render(request, template[, dictionary][, context_instance][, content_type][, status][, current_app])

render() is a brand spanking new shortcut for render_to_response in 1.3 that will automatically use RequestContext that I will most definitely be using from now on.


2020 EDIT: It should be noted that render_to_response() was removed in Django 3.0

https://docs.djangoproject.com/en/1.8/topics/http/shortcuts/#render-to-response

render_to_response(template[, dictionary][, context_instance][, mimetype])¶

render_to_response is your standard render function used in the tutorials and such. To use RequestContext you’d have to specify context_instance=RequestContext(request)


https://docs.djangoproject.com/en/1.8/ref/generic-views/#django-views-generic-simple-direct-to-template

direct_to_template is a generic view that I use in my views (as opposed to in my urls) because like the new render() function, it automatically uses RequestContext and all its context_processors.

But direct_to_template should be avoided as function based generic views are deprecated. Either use render or an actual class, see https://docs.djangoproject.com/en/1.3/topics/generic-views-migration/

I’m happy I haven’t typed RequestContext in a long, long time.


回答 1

重新定义Yuri,Fábio和Frosts对Django noob(即我)的答案-几乎可以肯定是一个简化,但是一个好的起点?

  • render_to_response()是“原版”,但context_instance=RequestContext(request)几乎所有时间都需要您输入PITA。

  • direct_to_template()被设计为仅在urls.py中使用,而没有在views.py中定义视图,但是可以在views.py中使用以避免键入RequestContext

  • render()render_to_response()自动提供的快捷方式context_instance=Request…。它在django开发版本(1.2.1)中可用,但许多人创建了自己的快捷方式,例如this这个或最初让我扔的快捷方式,即Nathans basic.tools。快捷方式

Rephrasing Yuri, Fábio, and Frosts answers for the Django noob (i.e. me) – almost certainly a simplification, but a good starting point?

  • render_to_response() is the “original”, but requires you putting context_instance=RequestContext(request) in nearly all the time, a PITA.

  • direct_to_template() is designed to be used just in urls.py without a view defined in views.py but it can be used in views.py to avoid having to type RequestContext

  • render() is a shortcut for render_to_response() that automatically supplies context_instance=Request…. Its available in the django development version (1.2.1) but many have created their own shortcuts such as this one, this one or the one that threw me initially, Nathans basic.tools.shortcuts.py


回答 2

渲染为

def render(request, *args, **kwargs):
    """ Simple wrapper for render_to_response. """
    kwargs['context_instance'] = RequestContext(request)
    return render_to_response(*args, **kwargs)

因此,它们之间没有什么区别,render_to_response只是它包装了使模板预处理器正常工作的上下文。

直接到模板是通用视图

在这里使用它真的没有任何意义,因为render_to_response以视图函数的形式存在开销。

Render is

def render(request, *args, **kwargs):
    """ Simple wrapper for render_to_response. """
    kwargs['context_instance'] = RequestContext(request)
    return render_to_response(*args, **kwargs)

So there is really no difference between render_to_response except it wraps your context making the template pre-processors work.

Direct to template is a generic view.

There is really no sense in using it here because there is overhead over render_to_response in the form of view function.


回答 3

从django docs

render()与具有context_instance参数的render_to_response()调用相同,该参数强制使用RequestContext。

direct_to_template是不同的。这是一个通用视图,它使用数据字典来呈现html,而不需要views.py,您可以在urls.py中使用它。文件在这里

From django docs:

render() is the same as a call to render_to_response() with a context_instance argument that that forces the use of a RequestContext.

direct_to_template is something different. It’s a generic view that uses a data dictionary to render the html without the need of the views.py, you use it in urls.py. Docs here


回答 4

我在上面的答案中找不到一个便笺。在此代码中:

context_instance = RequestContext(request)
return render_to_response(template_name, user_context, context_instance)

第三个参数context_instance实际上是做什么的?作为RequestContext,它设置了一些基本上下文,然后将其添加到中user_context。因此,模板获取了此扩展上下文。TEMPLATE_CONTEXT_PROCESSORS在settings.py中指定了要添加的变量。例如,django.contrib.auth.context_processors.auth添加了变量user和变量perm,然后可以在模板中访问它们。

Just one note I could not find in the answers above. In this code:

context_instance = RequestContext(request)
return render_to_response(template_name, user_context, context_instance)

What the third parameter context_instance actually does? Being RequestContext it sets up some basic context which is then added to user_context. So the template gets this extended context. What variables are added is given by TEMPLATE_CONTEXT_PROCESSORS in settings.py. For instance django.contrib.auth.context_processors.auth adds variable user and variable perm which are then accessible in the template.


Django模板如何使用变量查找字典值

问题:Django模板如何使用变量查找字典值

mydict = {"key1":"value1", "key2":"value2"}

查找在Django模板字典值的常规方法是{{ mydict.key1 }}{{ mydict.key2 }}。如果键是循环变量怎么办?即:

{% for item in list %} # where item has an attribute NAME
  {{ mydict.item.NAME }} # I want to look up mydict[item.NAME]
{% endfor %}

mydict.item.NAME失败。如何解决?

mydict = {"key1":"value1", "key2":"value2"}

The regular way to lookup a dictionary value in a Django template is {{ mydict.key1 }}, {{ mydict.key2 }}. What if the key is a loop variable? ie:

{% for item in list %} # where item has an attribute NAME
  {{ mydict.item.NAME }} # I want to look up mydict[item.NAME]
{% endfor %}

mydict.item.NAME fails. How to fix this?


回答 0

编写自定义模板过滤器:

from django.template.defaulttags import register
...
@register.filter
def get_item(dictionary, key):
    return dictionary.get(key)

(我.get这样使用,如果不存在该键,则不返回任何键。如果执行dictionary[key]此操作,则将引发一个KeyErrorthen。)

用法:

{{ mydict|get_item:item.NAME }}

Write a custom template filter:

from django.template.defaulttags import register
...
@register.filter
def get_item(dictionary, key):
    return dictionary.get(key)

(I use .get so that if the key is absent, it returns none. If you do dictionary[key] it will raise a KeyError then.)

usage:

{{ mydict|get_item:item.NAME }}

回答 1

从循环中的字典中获取键和值:

{% for key, value in mydict.items %}
    {{ value }}
{% endfor %}

我发现这更容易阅读,并且不需要特殊的编码。无论如何,我通常都需要循环内的键和值。

Fetch both the key and the value from the dictionary in the loop:

{% for key, value in mydict.items %}
    {{ value }}
{% endfor %}

I find this easier to read and it avoids the need for special coding. I usually need the key and the value inside the loop anyway.


回答 2

默认情况下不能。点是属性查找/键查找/切片的分隔符/触发器。

点在模板渲染中具有特殊含义。变量名称中的点表示查找。具体来说,当模板系统遇到变量名称中的点时,它将按以下顺序尝试以下查找:

  • 字典查找。示例:foo [“ bar”]
  • 属性查询。示例:foo.bar
  • 列表索引查找。示例:foo [bar]

但是您可以创建一个过滤器,以便您传递参数:

https://docs.djangoproject.com/zh-CN/dev/howto/custom-template-tags/#writing-custom-template-filters

@register.filter(name='lookup')
def lookup(value, arg):
    return value[arg]

{{ mydict|lookup:item.name }}

You can’t by default. The dot is the separator / trigger for attribute lookup / key lookup / slice.

Dots have a special meaning in template rendering. A dot in a variable name signifies a lookup. Specifically, when the template system encounters a dot in a variable name, it tries the following lookups, in this order:

  • Dictionary lookup. Example: foo[“bar”]
  • Attribute lookup. Example: foo.bar
  • List-index lookup. Example: foo[bar]

But you can make a filter which lets you pass in an argument:

https://docs.djangoproject.com/en/dev/howto/custom-template-tags/#writing-custom-template-filters

@register.filter(name='lookup')
def lookup(value, arg):
    return value[arg]

{{ mydict|lookup:item.name }}

回答 3

对我来说template_filters.py,用下面的内容在我的应用程序中创建一个名为python的文件就可以了

# coding=utf-8
from django.template.base import Library

register = Library()


@register.filter
def get_item(dictionary, key):
    return dictionary.get(key)

用法就像culebrón所说的:

{{ mydict|get_item:item.NAME }}

For me creating a python file named template_filters.py in my App with below content did the job

# coding=utf-8
from django.template.base import Library

register = Library()


@register.filter
def get_item(dictionary, key):
    return dictionary.get(key)

usage is like what culebrón said :

{{ mydict|get_item:item.NAME }}

回答 4

我也有类似的情况。但是我使用了不同的解决方案。

在我的模型中,我创建一个执行字典查找的属性。然后在模板中使用该属性。

在我的模型中:-

@property
def state_(self):
    """ Return the text of the state rather than an integer """
    return self.STATE[self.state]

在我的模板中:-

The state is: {{ item.state_ }}

I had a similar situation. However I used a different solution.

In my model I create a property that does the dictionary lookup. In the template I then use the property.

In my model: –

@property
def state_(self):
    """ Return the text of the state rather than an integer """
    return self.STATE[self.state]

In my template: –

The state is: {{ item.state_ }}

回答 5

因为我不能评论,让我做这一个答案的形式:
建立在culebrón的答案虞姬“富田”富田的答案,传递给函数的字典是一个字符串的形式,因此,也许使用AST。 literal_eval,首先将字符串转换为字典,如本例所示

通过此编辑,代码应如下所示:

@register.filter(name='lookup')
def lookup(value, arg):
    dictionary = ast.literal_eval(value)
    return value.get(arg)

{{ mydict|lookup:item.name }}

Since I can’t comment, let me do this in the form of an answer:
to build on culebrón’s answer or Yuji ‘Tomita’ Tomita’s answer, the dictionary passed into the function is in the form of a string, so perhaps use ast.literal_eval to convert the string to a dictionary first, like in this example.

With this edit, the code should look like this:

# code for custom template tag
@register.filter(name='lookup')
def lookup(value, arg):
    value_dict = ast.literal_eval(value)
    return value_dict.get(arg)

<!--template tag (in the template)-->
{{ mydict|lookup:item.name }}

回答 6

环境:Django 2.2

  1. 示例代码:


    from django.template.defaulttags import register

    @register.filter(name='lookup')
    def lookup(value, arg):
        return value.get(arg)

我将此代码放在名为Portfoliomgr的项目文件夹中的一个名为template_filters.py的文件中

  1. 无论您将过滤器代码放在何处,都要确保该文件夹中有__init__.py

  2. 将该文件添加到projectfolder / settings.py文件中模板部分的库部分。对我来说,它是Portfoliomgr / settings.py



    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'templates')],
            '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',
                ],
                'libraries':{
                    'template_filters': 'portfoliomgr.template_filters',
                }
            },
        },
    ]
  1. 在您的html代码中加载库

    
    {% load template_filters %}

Environment: Django 2.2

  1. Example code:


    from django.template.defaulttags import register

    @register.filter(name='lookup')
    def lookup(value, arg):
        return value.get(arg)

I put this code in a file named template_filters.py in my project folder named portfoliomgr

  1. No matter where you put your filter code, make sure you have __init__.py in that folder

  2. Add that file to libraries section in templates section in your projectfolder/settings.py file. For me, it is portfoliomgr/settings.py



    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'templates')],
            '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',
                ],
                'libraries':{
                    'template_filters': 'portfoliomgr.template_filters',
                }
            },
        },
    ]

  1. In your html code load the library

    
    {% load template_filters %}
    

回答 7

环保:django 2.1.7

视图:

dict_objs[query_obj.id] = {'obj': query_obj, 'tag': str_tag}
return render(request, 'obj.html', {'dict_objs': dict_objs})

模板:

{% for obj_id,dict_obj in dict_objs.items %}
<td>{{ dict_obj.obj.obj_name }}</td>
<td style="display:none">{{ obj_id }}</td>
<td>{{ forloop.counter }}</td>
<td>{{ dict_obj.obj.update_timestamp|date:"Y-m-d H:i:s"}}</td>

env: django 2.1.7

view:

dict_objs[query_obj.id] = {'obj': query_obj, 'tag': str_tag}
return render(request, 'obj.html', {'dict_objs': dict_objs})

template:

{% for obj_id,dict_obj in dict_objs.items %}
<td>{{ dict_obj.obj.obj_name }}</td>
<td style="display:none">{{ obj_id }}</td>
<td>{{ forloop.counter }}</td>
<td>{{ dict_obj.obj.update_timestamp|date:"Y-m-d H:i:s"}}</td>