标签归档:Django

Pydantic — 强大的数据校验工具,比DRF快12倍

Pydantic 是一个使用Python类型注解进行数据验证和管理的模块。安装方法非常简单,打开终端输入:

pip install pydantic

它类似于 Django DRF 序列化器的数据校验功能,不同的是,Django里的序列化器的Field是有限制的,如果你想要使用自己的Field还需要继承并重写它的基类:

# Django 序列化器
class Book(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    author = models.CharField(max_length=32)
    publish = models.CharField(max_length=32)

而 Pydantic 基于Python3.7以上的类型注解特性,实现了可以对任何类做数据校验的功能:

# Pydantic 数据校验功能
from datetime import datetime
from typing import List, Optional
from pydantic import BaseModel


class User(BaseModel):
    id: int
    name = 'John Doe'
    signup_ts: Optional[datetime] = None
    friends: List[int] = []


external_data = {
    'id': '123',
    'signup_ts': '2019-06-01 12:22',
    'friends': [1, 2, '3'],
}
user = User(**external_data)
print(user.id)
print(type(user.id))
#> 123
#> <class 'int'>
print(repr(user.signup_ts))
#> datetime.datetime(2019, 6, 1, 12, 22)
print(user.friends)
#> [1, 2, 3]
print(user.dict())
"""
{
    'id': 123,
    'signup_ts': datetime.datetime(2019, 6, 1, 12, 22),
    'friends': [1, 2, 3],
    'name': 'John Doe',
}
"""

从上面的基本使用可以看到,它甚至能自动帮你做数据类型的转换,比如代码中的 user.id, 在字典中是字符串,但经过Pydantic校验器后,它自动变成了int型,因为User类里的注解就是int型。

当我们的数据和定义的注解类型不一致时会报这样的Error:

from datetime import datetime
from typing import List, Optional
from pydantic import BaseModel


class User(BaseModel):
    id: int
    name = 'John Doe'
    signup_ts: Optional[datetime] = None
    friends: List[int] = []


external_data = {
    'id': '123',
    'signup_ts': '2019-06-01 12:222',
    'friends': [1, 2, '3'],
}
user = User(**external_data)
"""
Traceback (most recent call last):
  File "1.py", line 18, in <module>
    user = User(**external_data)
  File "pydantic\main.py", line 331, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for User
signup_ts
  invalid datetime format (type=value_error.datetime)
"""

即 “invalid datetime format”, 因为我传入的 signup_ts 不是标准的时间格式(多了个2)。

1.Pydantic 模型数据导出

通过Pydantic模型中自带的 json 属性方法,能让经过校验后的数据一行命令直接转成 json 字符串,如前文中的user对象:

print(user.dict())  # 转为字典
"""
{
    'id': 123,
    'signup_ts': datetime.datetime(2019, 6, 1, 12, 22),
    'friends': [1, 2, 3],
    'name': 'John Doe',
}
"""
print(user.json())  # 转为json
"""
{"id": 123, "signup_ts": "2019-06-01T12:22:00", "friends": [1, 2, 3], "name": "John Doe"}
"""

非常方便。它还支持将整个数据结构导出为 schema json,它能完整地描述整个对象的数据结构类型:

print(user.schema_json(indent=2))
"""
{
  "title": "User",
  "type": "object",
  "properties": {
    "id": {
      "title": "Id",
      "type": "integer"
    },
    "signup_ts": {
      "title": "Signup Ts",
      "type": "string",
      "format": "date-time"
    },
    "friends": {
      "title": "Friends",
      "default": [],
      "type": "array",
      "items": {
        "type": "integer"
      }
    },
    "name": {
      "title": "Name",
      "default": "John Doe",
      "type": "string"
    }
  },
  "required": [
    "id"
  ]
}
"""

2.数据导入

除了直接定义数据校验模型,它还能通过ORM、字符串、文件导入到数据校验模型:

比如字符串(raw):

from datetime import datetime
from pydantic import BaseModel


class User(BaseModel):
    id: int
    name = 'John Doe'
    signup_ts: datetime = None
      
m = User.parse_raw('{"id": 123, "name": "James"}')
print(m)
#> id=123 signup_ts=None name='James'

此外,它能直接将ORM的对象输入,转为Pydantic的对象,比如从Sqlalchemy ORM:

from typing import List
from sqlalchemy import Column, Integer, String
from sqlalchemy.dialects.postgresql import ARRAY
from sqlalchemy.ext.declarative import declarative_base
from pydantic import BaseModel, constr

Base = declarative_base()


class CompanyOrm(Base):
    __tablename__ = 'companies'
    id = Column(Integer, primary_key=True, nullable=False)
    public_key = Column(String(20), index=True, nullable=False, unique=True)
    name = Column(String(63), unique=True)
    domains = Column(ARRAY(String(255)))


class CompanyModel(BaseModel):
    id: int
    public_key: constr(max_length=20)
    name: constr(max_length=63)
    domains: List[constr(max_length=255)]

    class Config:
        orm_mode = True


co_orm = CompanyOrm(
    id=123,
    public_key='foobar',
    name='Testing',
    domains=['example.com', 'foobar.com'],
)
print(co_orm)
#> <models_orm_mode.CompanyOrm object at 0x7f0bdac44850>
co_model = CompanyModel.from_orm(co_orm)
print(co_model)
#> id=123 public_key='foobar' name='Testing' domains=['example.com',
#> 'foobar.com']

从Json文件导入:

from datetime import datetime
from pathlib import Path
from pydantic import BaseModel


class User(BaseModel):
    id: int
    name = 'John Doe'
    signup_ts: datetime = None
      
path = Path('data.json')
path.write_text('{"id": 123, "name": "James"}')
m = User.parse_file(path)
print(m)

从pickle导入:

import pickle
from datetime import datetime
from pydantic import BaseModel

pickle_data = pickle.dumps({
    'id': 123,
    'name': 'James',
    'signup_ts': datetime(2017, 7, 14)
})
m = User.parse_raw(
    pickle_data, content_type='application/pickle', allow_pickle=True
)
print(m)
#> id=123 signup_ts=datetime.datetime(2017, 7, 14, 0, 0) name='James'

3.自定义数据校验

你还能给它增加 validator 装饰器,增加你需要的校验逻辑:

from pydantic import BaseModel, ValidationError, validator


class UserModel(BaseModel):
    name: str
    username: str
    password1: str
    password2: str

    @validator('name')
    def name_must_contain_space(cls, v):
        if ' ' not in v:
            raise ValueError('must contain a space')
        return v.title()

    @validator('password2')
    def passwords_match(cls, v, values, **kwargs):
        if 'password1' in values and v != values['password1']:
            raise ValueError('passwords do not match')
        return v

    @validator('username')
    def username_alphanumeric(cls, v):
        assert v.isalnum(), 'must be alphanumeric'
        return v

上面,我们增加了三种自定义校验逻辑:

1.name 必须带有空格

2.password2 必须和 password1 相同

3.username 必须为字母

让我们试试这三个校验是否成功实现:

user = UserModel(
    name='samuel colvin',
    username='scolvin',
    password1='zxcvbn',
    password2='zxcvbn',
)
print(user)
#> name='Samuel Colvin' username='scolvin' password1='zxcvbn' password2='zxcvbn'

try:
    UserModel(
        name='samuel',
        username='scolvin',
        password1='zxcvbn',
        password2='zxcvbn2',
    )
except ValidationError as e:
    print(e)
    """
    2 validation errors for UserModel
    name
      must contain a space (type=value_error)
    password2
      passwords do not match (type=value_error)
    """

可以看到,第一个UserModel里的数据完全没有问题,通过校验。

第二个UserModel里的数据,由于name存在空格,password2和password1不一致,无法通过校验。

4.性能表现

这是最令我惊讶的部分,Pydantic 比 Django-rest-framework 还快了12.3倍:

PackageVersionRelative PerformanceMean validation time
pydantic1.7.393.7μs
attrs + cattrs20.3.01.5x slower143.6μs
valideer0.4.21.9x slower175.9μs
marshmallow3.10.02.4x slower227.6μs
voluptuous0.12.12.7x slower257.5μs
trafaret2.1.03.2x slower296.7μs
schematics2.1.010.2x slower955.5μs
django-rest-framework3.12.212.3x slower1148.4μs
cerberus1.3.225.9x slower2427.6μs

而且他们的所有基准测试代码都是开源的,你可以在下面这个Github链接找到:

https://github.com/samuelcolvin/pydantic/tree/master/benchmarks

如果你的网络无法访问GitHub,请关注Python实用宝典公众号后台回复Pydantic获取。

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

仅在Django启动一次时执行代码?

问题:仅在Django启动一次时执行代码?

我正在编写一个Django中间件类,该类只想在启动时执行一次,以初始化一些其他人工代码。我遵循了sdolan 在此处发布的非常好的解决方案,但是“ Hello”消息两次输出到终端。例如

from django.core.exceptions import MiddlewareNotUsed
from django.conf import settings

class StartupMiddleware(object):
    def __init__(self):
        print "Hello world"
        raise MiddlewareNotUsed('Startup complete')

在我的Django设置文件中,该类已包含在MIDDLEWARE_CLASSES列表中。

但是当我使用runserver运行Django并请求页面时,我进入了终端

Django version 1.3, using settings 'config.server'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
Hello world
[22/Jul/2011 15:54:36] "GET / HTTP/1.1" 200 698
Hello world
[22/Jul/2011 15:54:36] "GET /static/css/base.css HTTP/1.1" 200 0

有什么想法为什么要打印两次“ Hello world”?谢谢。

I’m writing a Django Middleware class that I want to execute only once at startup, to initialise some other arbritary code. I’ve followed the very nice solution posted by sdolan here, but the “Hello” message is output to the terminal twice. E.g.

from django.core.exceptions import MiddlewareNotUsed
from django.conf import settings

class StartupMiddleware(object):
    def __init__(self):
        print "Hello world"
        raise MiddlewareNotUsed('Startup complete')

and in my Django settings file, I’ve got the class included in the MIDDLEWARE_CLASSES list.

But when I run Django using runserver and request a page, I get in the terminal

Django version 1.3, using settings 'config.server'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
Hello world
[22/Jul/2011 15:54:36] "GET / HTTP/1.1" 200 698
Hello world
[22/Jul/2011 15:54:36] "GET /static/css/base.css HTTP/1.1" 200 0

Any ideas why “Hello world” is printed twice? Thanks.


回答 0

从以下Pykler的答案进行更新:Django 1.7现在对此具有钩子


不要这样

您不希望一次性使用“中间件”。

您想在顶层执行代码urls.py。该模块将被导入并执行一次。

urls.py

from django.confs.urls.defaults import *
from my_app import one_time_startup

urlpatterns = ...

one_time_startup()

Update from Pykler’s answer below: Django 1.7 now has a hook for this


Don’t do it this way.

You don’t want “middleware” for a one-time startup thing.

You want to execute code in the top-level urls.py. That module is imported and executed once.

urls.py

from django.confs.urls.defaults import *
from my_app import one_time_startup

urlpatterns = ...

one_time_startup()

如何在Django网站上记录服务器错误

问题:如何在Django网站上记录服务器错误

因此,在进行开发时,我可以设置settings.DEBUGTrue,如果发生错误,我可以看到格式正确,具有良好的堆栈跟踪和请求信息。

但是在某种生产站点上,我更愿意使用DEBUG=False并向访问者展示一些标准错误500页,其中包含我目前正在修复此bug的信息;)
同时,我想以某种方式记录所有这些信息(堆栈跟踪和请求信息)存储到服务器上的文件中-因此我可以将其输出到控制台并观看错误滚动,每小时将日志发送给我或类似的东西。

您会为django站点推荐什么样的日志记录解决方案,这些解决方案可以满足那些简单的要求?我有作为fcgi服务器运行的应用程序,并且我使用apache Web服务器作为前端(尽管考虑使用lighttpd)。

So, when playing with the development I can just set settings.DEBUG to True and if an error occures I can see it nicely formatted, with good stack trace and request information.

But on kind of production site I’d rather use DEBUG=False and show visitors some standard error 500 page with information that I’m working on fixing this bug at this moment ;)
At the same time I’d like to have some way of logging all those information (stack trace and request info) to a file on my server – so I can just output it to my console and watch errors scroll, email the log to me every hour or something like this.

What logging solutions would you recomend for a django-site, that would meet those simple requirements? I have the application running as fcgi server and I’m using apache web server as frontend (although thinking of going to lighttpd).


回答 0

好的,当时DEBUG = False,Django会自动将所有错误的完整回溯邮件发送给ADMINS设置中列出的每个人,这几乎可以免费为您提供通知。如果您想要更细粒度的控件,则可以编写一个中间件类并将其添加到设置中,该中间件类定义了一个名为的方法process_exception(),该方法可以访问所引发的异常:

http://docs.djangoproject.com/en/dev/topics/http/middleware/#process-exception

process_exception()然后,您的方法可以执行您想要的任何类型的日志记录:写入控制台,写入文件等,等等。

编辑:尽管它的用处不大,但是您也可以侦听got_request_exception信号,该信号将在请求处理期间遇到异常时发送:

http://docs.djangoproject.com/en/dev/ref/signals/#got-request-exception

但是,这不能使您访问异常对象,因此中间件方法更容易使用。

Well, when DEBUG = False, Django will automatically mail a full traceback of any error to each person listed in the ADMINS setting, which gets you notifications pretty much for free. If you’d like more fine-grained control, you can write and add to your settings a middleware class which defines a method named process_exception(), which will have access to the exception that was raised:

http://docs.djangoproject.com/en/dev/topics/http/middleware/#process-exception

Your process_exception() method can then perform whatever type of logging you’d like: writing to console, writing to a file, etc., etc.

Edit: though it’s a bit less useful, you can also listen for the got_request_exception signal, which will be sent whenever an exception is encountered during request processing:

http://docs.djangoproject.com/en/dev/ref/signals/#got-request-exception

This does not give you access to the exception object, however, so the middleware method is much easier to work with.


回答 1

如前所述,Django Sentry是一个不错的选择,但是要正确设置它(作为一个单独的网站)需要进行一些工作。如果您只想将所有内容记录到一个简单的文本文件中,请在此处输入以下记录配置settings.py

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        # Include the default Django email handler for errors
        # This is what you'd get without configuring logging at all.
        'mail_admins': {
            'class': 'django.utils.log.AdminEmailHandler',
            'level': 'ERROR',
             # But the emails are plain text by default - HTML is nicer
            'include_html': True,
        },
        # Log to a text file that can be rotated by logrotate
        'logfile': {
            'class': 'logging.handlers.WatchedFileHandler',
            'filename': '/var/log/django/myapp.log'
        },
    },
    'loggers': {
        # Again, default Django configuration to email unhandled exceptions
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        },
        # Might as well log any errors anywhere else in Django
        'django': {
            'handlers': ['logfile'],
            'level': 'ERROR',
            'propagate': False,
        },
        # Your own app - this assumes all your logger names start with "myapp."
        'myapp': {
            'handlers': ['logfile'],
            'level': 'WARNING', # Or maybe INFO or DEBUG
            'propagate': False
        },
    },
}

Django Sentry is a good way to go, as already mentioned, but there is a bit of work involved in setting it up properly (as a separate website). If you just want to log everything to a simple text file here’s the logging configuration to put in your settings.py

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        # Include the default Django email handler for errors
        # This is what you'd get without configuring logging at all.
        'mail_admins': {
            'class': 'django.utils.log.AdminEmailHandler',
            'level': 'ERROR',
             # But the emails are plain text by default - HTML is nicer
            'include_html': True,
        },
        # Log to a text file that can be rotated by logrotate
        'logfile': {
            'class': 'logging.handlers.WatchedFileHandler',
            'filename': '/var/log/django/myapp.log'
        },
    },
    'loggers': {
        # Again, default Django configuration to email unhandled exceptions
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        },
        # Might as well log any errors anywhere else in Django
        'django': {
            'handlers': ['logfile'],
            'level': 'ERROR',
            'propagate': False,
        },
        # Your own app - this assumes all your logger names start with "myapp."
        'myapp': {
            'handlers': ['logfile'],
            'level': 'WARNING', # Or maybe INFO or DEBUG
            'propagate': False
        },
    },
}

回答 2

另一个答案中提到的django-db-log已替换为:

https://github.com/dcramer/django-sentry

django-db-log, mentioned in another answer, has been replaced with:

https://github.com/dcramer/django-sentry


回答 3

显然,James是正确的,但是如果您想在数据存储区中记录异常,则已经有一些开源解决方案可用:

1)CrashLog是一个不错的选择:http : //code.google.com/p/django-crashlog/

2)Db-Log也是一个不错的选择:http : //code.google.com/p/django-db-log/

两者有什么区别?我几乎看不到任何东西,所以只要一个就足够了。

我都用过,而且它们运作良好。

Obviously James is correct, but if you wanted to log exceptions in a datastore, there are a few open source solutions already available:

1) CrashLog is a good choice: http://code.google.com/p/django-crashlog/

2) Db-Log is a good choice as well: http://code.google.com/p/django-db-log/

What is the difference between the two? Almost nothing that I can see, so either one will suffice.

I’ve used both and they work well.


回答 4

自EMP提交最有用的代码以来,已经过去了一段时间。我刚刚实现了它,并在尝试使用一些manage.py选项进行尝试以查找错误时,我收到了弃用警告,以表明在当前版本的Django(1.5。?)中,现在需要require_debug_false过滤器mail_admins处理程序所需。

这是修改后的代码:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'filters': {
         'require_debug_false': {
             '()': 'django.utils.log.RequireDebugFalse'
         }
     },
    'handlers': {
        # Include the default Django email handler for errors
        # This is what you'd get without configuring logging at all.
        'mail_admins': {
            'class': 'django.utils.log.AdminEmailHandler',
            'level': 'ERROR',
            'filters': ['require_debug_false'],
             # But the emails are plain text by default - HTML is nicer
            'include_html': True,
        },
        # Log to a text file that can be rotated by logrotate
        'logfile': {
            'class': 'logging.handlers.WatchedFileHandler',
            'filename': '/home/username/public_html/djangoprojectname/logfilename.log'
        },
    },
    'loggers': {
        # Again, default Django configuration to email unhandled exceptions
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        },
        # Might as well log any errors anywhere else in Django
        'django': {
            'handlers': ['logfile'],
            'level': 'ERROR',
            'propagate': False,
        },
        # Your own app - this assumes all your logger names start with "myapp."
        'myapp': {
            'handlers': ['logfile'],
            'level': 'DEBUG', # Or maybe INFO or WARNING
            'propagate': False
        },
    },
}

Some time has passed since EMP’s most helpful code submission. I just now implemented it, and while thrashing around with some manage.py option, to try to chase down a bug, I got a deprecation warning to the effect that with my current version of Django (1.5.?) a require_debug_false filter is now needed for the mail_admins handler.

Here is the revised code:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'filters': {
         'require_debug_false': {
             '()': 'django.utils.log.RequireDebugFalse'
         }
     },
    'handlers': {
        # Include the default Django email handler for errors
        # This is what you'd get without configuring logging at all.
        'mail_admins': {
            'class': 'django.utils.log.AdminEmailHandler',
            'level': 'ERROR',
            'filters': ['require_debug_false'],
             # But the emails are plain text by default - HTML is nicer
            'include_html': True,
        },
        # Log to a text file that can be rotated by logrotate
        'logfile': {
            'class': 'logging.handlers.WatchedFileHandler',
            'filename': '/home/username/public_html/djangoprojectname/logfilename.log'
        },
    },
    'loggers': {
        # Again, default Django configuration to email unhandled exceptions
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        },
        # Might as well log any errors anywhere else in Django
        'django': {
            'handlers': ['logfile'],
            'level': 'ERROR',
            'propagate': False,
        },
        # Your own app - this assumes all your logger names start with "myapp."
        'myapp': {
            'handlers': ['logfile'],
            'level': 'DEBUG', # Or maybe INFO or WARNING
            'propagate': False
        },
    },
}

回答 5

我的fcgi脚本有一个烦人的问题。它发生在django开始之前。缺少伐木非常痛苦。无论如何,将stderr重定向到文件作为第一件事很有帮助:

#!/home/user/env/bin/python
sys.stderr = open('/home/user/fcgi_errors', 'a')

I just had an annoying problem with my fcgi script. It occurred before django even started. The lack of logging is sooo painful. Anyway, redirecting stderr to a file as the very first thing helped a lot:

#!/home/user/env/bin/python
sys.stderr = open('/home/user/fcgi_errors', 'a')

Django:登录后重定向到上一页

问题:Django:登录后重定向到上一页

我正在尝试建立一个简单的网站,其登录功能与SO上的登录功能非常相似。该用户应该能够以匿名用户身份浏览该网站,并且每个页面上都会有一个登录链接。当单击登录链接时,用户将被带到登录表单。成功登录后,应将用户带回到他首先单击登录链接的页面。我猜想我必须以某种方式将当前页面的url传递给处理登录表单的视图,但是我真的无法使其正常工作。

编辑:我想通了。我通过将当前页面作为GET参数传递来链接到登录表单,然后使用“下一个”重定向到该页面。谢谢!

编辑2:我的解释似乎不清楚,所以这里要求的是我的代码:假设我们在页面foo.html上,并且尚未登录。现在,我们希望在foo.html上有一个链接,该链接登录。我们可以在那里登录,然后将其重定向回foo.html。foo.html上的链接如下所示:

      <a href='/login/?next={{ request.path }}'>Login</a> 

现在,我编写了一个自定义登录视图,看起来像这样:

def login_view(request):
   redirect_to = request.REQUEST.get('next', '')
   if request.method=='POST':
      #create login form...
      if valid login credentials have been entered:
         return HttpResponseRedirect(redirect_to)  
   #...
   return render_to_response('login.html', locals())

还有login.html中的重要一行:

<form method="post" action="./?next={{ redirect_to }}">

是的,就这样,希望可以弄清楚。

I’m trying to build a simple website with login functionality very similar to the one here on SO. The user should be able to browse the site as an anonymous user and there will be a login link on every page. When clicking on the login link the user will be taken to the login form. After a successful login the user should be taken back to the page from where he clicked the login link in the first place. I’m guessing that I have to somehow pass the url of the current page to the view that handles the login form but I can’t really get it to work.

EDIT: I figured it out. I linked to the login form by passing the current page as a GET parameter and then used ‘next’ to redirect to that page. Thanks!

EDIT 2: My explanation did not seem to be clear so as requested here is my code: Lets say we are on a page foo.html and we are not logged in. Now we would like to have a link on foo.html that links to login.html. There we can login and are then redirected back to foo.html. The link on foo.html looks like this:

      <a href='/login/?next={{ request.path }}'>Login</a> 

Now I wrote a custom login view that looks somewhat like this:

def login_view(request):
   redirect_to = request.REQUEST.get('next', '')
   if request.method=='POST':
      #create login form...
      if valid login credentials have been entered:
         return HttpResponseRedirect(redirect_to)  
   #...
   return render_to_response('login.html', locals())

And the important line in login.html:

<form method="post" action="./?next={{ redirect_to }}">

So yeah thats pretty much it, hope that makes it clear.


回答 0

您无需为此额外查看,该功能已内置。

首先,每个具有登录链接的页面都需要知道当前路径,最简单的方法是将请求上下文前置变量添加到settings.py(默认为前四个),然后在每个请求中都可以使用请求对象:

settings.py:

TEMPLATE_CONTEXT_PROCESSORS = (
    "django.core.context_processors.auth",
    "django.core.context_processors.debug",
    "django.core.context_processors.i18n",
    "django.core.context_processors.media",
    "django.core.context_processors.request",
)

然后添加您想要“登录”链接的模板:

base.html:

<a href="{% url django.contrib.auth.views.login %}?next={{request.path}}">Login</a>

这会将GET参数添加到登录页面,该参数指向当前页面。

登录模板可以像下面这样简单:

registration / login.html:

{% block content %}
<form method="post" action="">
  {{form.as_p}}
<input type="submit" value="Login">
</form>
{% endblock %}

You do not need to make an extra view for this, the functionality is already built in.

First each page with a login link needs to know the current path, and the easiest way is to add the request context preprosessor to settings.py (the 4 first are default), then the request object will be available in each request:

settings.py:

TEMPLATE_CONTEXT_PROCESSORS = (
    "django.core.context_processors.auth",
    "django.core.context_processors.debug",
    "django.core.context_processors.i18n",
    "django.core.context_processors.media",
    "django.core.context_processors.request",
)

Then add in the template you want the Login link:

base.html:

<a href="{% url django.contrib.auth.views.login %}?next={{request.path}}">Login</a>

This will add a GET argument to the login page that points back to the current page.

The login template can then be as simple as this:

registration/login.html:

{% block content %}
<form method="post" action="">
  {{form.as_p}}
<input type="submit" value="Login">
</form>
{% endblock %}

如何在Django queryset中执行小于或等于过滤器?

问题:如何在Django queryset中执行小于或等于过滤器?

我试图通过每个称为“个人资料”的用户个人资料中的自定义字段来过滤用户。此字段称为级别,是0到3之间的整数。

如果我使用等于进行过滤,则会得到具有预期级别的用户列表:

user_list = User.objects.filter(userprofile__level = 0)

当我尝试使用少于以下内容进行过滤时:

user_list = User.objects.filter(userprofile__level < 3)

我得到了错误:

未定义全局名称“ userprofile__level”

有没有一种方法可以通过<或>进行过滤,或者我是否吠叫了错误的树。

I am attempting to filter users by a custom field in each users profile called profile. This field is called level and is an integer between 0-3.

If I filter using equals, I get a list of users with the chosen level as expected:

user_list = User.objects.filter(userprofile__level = 0)

When I try to filter using less than:

user_list = User.objects.filter(userprofile__level < 3)

I get the error:

global name ‘userprofile__level’ is not defined

Is there a way to filter by < or >, or am I barking up the wrong tree.


回答 0

小于或等于:

User.objects.filter(userprofile__level__lte=0)

大于或等于:

User.objects.filter(userprofile__level__gte=0)

同样,lt小于和gt大于。您可以在文档中找到它们。

Less than or equal:

User.objects.filter(userprofile__level__lte=0)

Greater than or equal:

User.objects.filter(userprofile__level__gte=0)

Likewise, lt for less than and gt for greater than. You can find them all in the documentation.


django MultiValueDictKeyError错误,我该如何处理

问题:django MultiValueDictKeyError错误,我该如何处理

我正在尝试将对象保存到数据库中,但是它引发了MultiValueDictKeyError错误。

问题出在表格内,is_private用一个复选框表示。如果未选中该复选框,则显然不会传递任何内容。这是消除错误的地方。

我如何正确处理并捕获此异常?

该行是

is_private = request.POST['is_private']

I’m trying to save a object to my database, but it’s throwing a MultiValueDictKeyError error.

The problems lies within the form, the is_private is represented by a checkbox. If the check box is NOT selected, obviously nothing is passed. This is where the error gets chucked.

How do I properly deal with this exception, and catch it?

The line is

is_private = request.POST['is_private']

回答 0

使用MultiValueDict的get方法。这在标准字典中也存在,并且是一种在不存在默认值的情况下获取值的方法。

is_private = request.POST.get('is_private', False)

通常,

my_var = dict.get(<key>, <default>)

Use the MultiValueDict’s get method. This is also present on standard dicts and is a way to fetch a value while providing a default if it does not exist.

is_private = request.POST.get('is_private', False)

Generally,

my_var = dict.get(<key>, <default>)

回答 1

选择最适合您的:

1个

is_private = request.POST.get('is_private', False);

如果is_privatekey在request.POST中存在,则is_private变量等于它,如果不相等,则它等于False。

2

if 'is_private' in request.POST:
    is_private = request.POST['is_private']
else:
    is_private = False

3

from django.utils.datastructures import MultiValueDictKeyError
try:
    is_private = request.POST['is_private']
except MultiValueDictKeyError:
    is_private = False

Choose what is best for you:

1

is_private = request.POST.get('is_private', False);

If is_private key is present in request.POST the is_private variable will be equal to it, if not, then it will be equal to False.

2

if 'is_private' in request.POST:
    is_private = request.POST['is_private']
else:
    is_private = False

3

from django.utils.datastructures import MultiValueDictKeyError
try:
    is_private = request.POST['is_private']
except MultiValueDictKeyError:
    is_private = False

回答 2

之所以会这样,是因为您试图从不存在的字典中获取密钥。您需要先测试它是否在其中。

尝试:

is_private = 'is_private' in request.POST

要么

is_private = 'is_private' in request.POST and request.POST['is_private']

取决于您使用的值。

You get that because you’re trying to get a key from a dictionary when it’s not there. You need to test if it is in there first.

try:

is_private = 'is_private' in request.POST

or

is_private = 'is_private' in request.POST and request.POST['is_private']

depending on the values you’re using.


回答 3

您为什么不尝试is_private在模型中定义为default=False

class Foo(models.Models):
    is_private = models.BooleanField(default=False)

Why didn’t you try to define is_private in your models as default=False?

class Foo(models.Models):
    is_private = models.BooleanField(default=False)

回答 4

要记住的另一件事是request.POST['keyword']引用由指定的html name属性标识的元素keyword

因此,如果您的表格是:

<form action="/login/" method="POST">
  <input type="text" name="keyword" placeholder="Search query">
  <input type="number" name="results" placeholder="Number of results">
</form>

然后,request.POST['keyword']和分别request.POST['results']包含输入元素keyword和的值results

Another thing to remember is that request.POST['keyword'] refers to the element identified by the specified html name attribute keyword.

So, if your form is:

<form action="/login/" method="POST">
  <input type="text" name="keyword" placeholder="Search query">
  <input type="number" name="results" placeholder="Number of results">
</form>

then, request.POST['keyword'] and request.POST['results'] will contain the value of the input elements keyword and results, respectively.


回答 5

首先检查请求对象是否具有’is_private’键参数。多数情况下,此MultiValueDictKeyError发生是因为类字典的请求对象中缺少键。由于字典是无序键,因此值对为“关联存储器”或“关联数组”

换句话说。request.GET或request.POST是类似于字典的对象,包含所有请求参数。这是特定于Django的。

如果key在字典中,则方法get()返回给定key的值。如果key不可用,则返回默认值None。

您可以通过以下方式处理此错误:

is_private = request.POST.get('is_private', False);

First check if the request object have the ‘is_private’ key parameter. Most of the case’s this MultiValueDictKeyError occurred for missing key in the dictionary-like request object. Because dictionary is an unordered key, value pair “associative memories” or “associative arrays”

In another word. request.GET or request.POST is a dictionary-like object containing all request parameters. This is specific to Django.

The method get() returns a value for the given key if key is in the dictionary. If key is not available then returns default value None.

You can handle this error by putting :

is_private = request.POST.get('is_private', False);

回答 6

对我而言,由于以下原因,此错误在我的django项目中发生:

  1. 我在项目的模板文件夹中的home.html文件中插入了一个新的超链接,如下所示:

    <input type="button" value="About" onclick="location.href='{% url 'about' %}'">

  2. 在views.py中,我具有count和about的以下定义:

   def count(request):
           fulltext = request.GET['fulltext']
           wordlist = fulltext.split()
           worddict = {}
           for word in wordlist:
               if word in worddict:
                   worddict[word] += 1
               else:
                   worddict[word] = 1
                   worddict = sorted(worddict.items(), key = operator.itemgetter(1),reverse=True)
           return render(request,'count.html', 'fulltext':fulltext,'count':len(wordlist),'worddict'::worddict})

   def about(request): 
       return render(request,"about.html")
  1. 在urls.py中,我具有以下url模式:
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('',views.homepage,name="home"),
        path('eggs',views.eggs),
        path('count/',views.count,name="count"),
        path('about/',views.count,name="about"),
    ]

可以看出没有。上面的3,在最后一个url模式中,我错误地调用了views.count而我需要调用views.about。fulltext = request.GET['fulltext']views.py的count函数中的这一行(由于在urlpatterns中输入错误而被错误地调用)引发了multivaluedictkeyerror异常。

然后,我将urls.py中的最后一个URL模式更改为正确的模式,即path('about/',views.about,name="about"),一切正常。

显然,通常django中的新手程序员会犯这样的错误,即我错误地为URL调用了另一个视图函数,这可能是期望使用不同的参数集或在其render调用中传递不同的对象集,而不是预期的行为。

希望这可以帮助一些新手程序员使用django。

For me, this error occurred in my django project because of the following:

  1. I inserted a new hyperlink in my home.html present in templates folder of my project as below:

    <input type="button" value="About" onclick="location.href='{% url 'about' %}'">
  2. In views.py, I had the following definitions of count and about:

   def count(request):
           fulltext = request.GET['fulltext']
           wordlist = fulltext.split()
           worddict = {}
           for word in wordlist:
               if word in worddict:
                   worddict[word] += 1
               else:
                   worddict[word] = 1
                   worddict = sorted(worddict.items(), key = operator.itemgetter(1),reverse=True)
           return render(request,'count.html', 'fulltext':fulltext,'count':len(wordlist),'worddict'::worddict})

   def about(request): 
       return render(request,"about.html")
  1. In urls.py, I had the following url patterns:
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('',views.homepage,name="home"),
        path('eggs',views.eggs),
        path('count/',views.count,name="count"),
        path('about/',views.count,name="about"),
    ]

As can be seen in no. 3 above,in the last url pattern, I was incorrectly calling views.count whereas I needed to call views.about. This line fulltext = request.GET['fulltext'] in count function (which was mistakenly called because of wrong entry in urlpatterns) of views.py threw the multivaluedictkeyerror exception.

Then I changed the last url pattern in urls.py to the correct one i.e. path('about/',views.about,name="about"), and everything worked fine.

Apparently, in general a newbie programmer in django can make the mistake I made of wrongly calling another view function for a url, which might be expecting different set of parameters or passing different set of objects in its render call, rather than the intended behavior.

Hope this helps some newbie programmer to django.


Django:为什么某些模型字段会相互冲突?

问题:Django:为什么某些模型字段会相互冲突?

我想创建一个包含2个指向用户的链接的对象。例如:

class GameClaim(models.Model):
    target = models.ForeignKey(User)
    claimer = models.ForeignKey(User)
    isAccepted = models.BooleanField()

但是运行服务器时出现以下错误:

  • 字段“目标”的访问器与相关字段“ User.gameclaim_set”冲突。在’target’的定义中添加related_name参数。

  • 字段“ claimer”的访问器与相关字段“ User.gameclaim_set”冲突。在“ claimer”的定义中添加一个related_name参数。

您能否解释为什么我会收到错误以及如何解决这些错误?

I want to create an object that contains 2 links to Users. For example:

class GameClaim(models.Model):
    target = models.ForeignKey(User)
    claimer = models.ForeignKey(User)
    isAccepted = models.BooleanField()

but I am getting the following errors when running the server:

  • Accessor for field ‘target’ clashes with related field ‘User.gameclaim_set’. Add a related_name argument to the definition for ‘target’.

  • Accessor for field ‘claimer’ clashes with related field ‘User.gameclaim_set’. Add a related_name argument to the definition for ‘claimer’.

Can you please explain why I am getting the errors and how to fix them?


回答 0

您有两个用户外键。Django自动创建一个从User到GameClaim的反向关系,通常是gameclaim_set。但是,由于您有两个FK,因此将具有两个gameclaim_set属性,这显然是不可能的。因此,您需要告诉Django用于反向关系的名称。

使用related_nameFK定义中的属性。例如

class GameClaim(models.Model):
    target = models.ForeignKey(User, related_name='gameclaim_targets')
    claimer = models.ForeignKey(User, related_name='gameclaim_users')
    isAccepted = models.BooleanField()

You have two foreign keys to User. Django automatically creates a reverse relation from User back to GameClaim, which is usually gameclaim_set. However, because you have two FKs, you would have two gameclaim_set attributes, which is obviously impossible. So you need to tell Django what name to use for the reverse relation.

Use the related_name attribute in the FK definition. e.g.

class GameClaim(models.Model):
    target = models.ForeignKey(User, related_name='gameclaim_targets')
    claimer = models.ForeignKey(User, related_name='gameclaim_users')
    isAccepted = models.BooleanField()

回答 1

User模型试图创建具有相同名称的两个领域,一个是GameClaims说有User作为target,而另一个用于GameClaims该有User作为claimer。这是上的文档related_name,这是Django允许您设置属性名称的方法,以便自动生成的属性不会冲突。

The User model is trying to create two fields with the same name, one for the GameClaims that have that User as the target, and another for the GameClaims that have that User as the claimer. Here’s the docs on related_name, which is Django’s way of letting you set the names of the attributes so the autogenerated ones don’t conflict.


回答 2

OP没有使用抽象基类…但是,如果您使用的是,您会发现在FK中硬编码related_name(例如…,related_name =“ myname”)会导致许多此类冲突错误-从基类继承的每个类一个。下面提供的链接包含解决方法,这很简单,但绝对不明显。

从Django文档…

如果在ForeignKey或ManyToManyField上使用related_name属性,则必须始终为该字段指定唯一的反向名称。这通常会在抽象基类中引起问题,因为此类的字段包含在每个子类中,并且每次属性(包括related_name)的值都完全相同。

更多信息在这里

The OP isn’t using a abstract base class… but if you are, you will find that hard coding the related_name in the FK (e.g. …, related_name=”myname”) will result in a number of these conflict errors – one for each inherited class from the base class. The link provided below contains the workaround, which is simple, but definitely not obvious.

From the django docs…

If you are using the related_name attribute on a ForeignKey or ManyToManyField, you must always specify a unique reverse name for the field. This would normally cause a problem in abstract base classes, since the fields on this class are included into each of the child classes, with exactly the same values for the attributes (including related_name) each time.

More info here.


回答 3

有时,您related_name 实际上必须在使用继承的任何时候使用额外的格式设置。

class Value(models.Model):
    value = models.DecimalField(decimal_places=2, max_digits=5)
    animal = models.ForeignKey(
        Animal, related_name="%(app_label)s_%(class)s_related")

    class Meta:
        abstract = True

class Height(Value):
    pass

class Weigth(Value):
    pass

class Length(Value):
    pass

这里没有冲突,但是related_name定义一次,Django将小心创建唯一的关系名称。

然后在Value类的子级中,您可以访问:

herdboard_height_related
herdboard_lenght_related
herdboard_weight_related

Sometimes you have to use extra formatting in related_name – actually, any time when inheritance is used.

class Value(models.Model):
    value = models.DecimalField(decimal_places=2, max_digits=5)
    animal = models.ForeignKey(
        Animal, related_name="%(app_label)s_%(class)s_related")

    class Meta:
        abstract = True

class Height(Value):
    pass

class Weigth(Value):
    pass

class Length(Value):
    pass

No clash here, but related_name is defined once and Django will take care for creating unique relation names.

then in children of Value class, you’ll have access to:

herdboard_height_related
herdboard_lenght_related
herdboard_weight_related

回答 4

当我将子模块作为应用程序添加到Django项目时,似乎偶尔会遇到这种情况,例如,给定以下结构:

myapp/
myapp/module/
myapp/module/models.py

如果我将以下内容添加到INSTALLED_APPS:

'myapp',
'myapp.module',

Django似乎两次处理了myapp.mymodule models.py文件,并抛出了以上错误。可以通过在INSTALLED_APPS列表中不包括主模块来解决此问题:

'myapp.module',

包含myapp代替myapp.module会导致所有数据库表都使用不正确的名称创建,因此这似乎是正确的方法。

我在寻找此问题的解决方案时遇到了这篇文章,所以我想把它放在这里:)

I seem to come across this occasionally when I add a submodule as an application to a django project, for example given the following structure:

myapp/
myapp/module/
myapp/module/models.py

If I add the following to INSTALLED_APPS:

'myapp',
'myapp.module',

Django seems to process the myapp.mymodule models.py file twice and throws the above error. This can be resolved by not including the main module in the INSTALLED_APPS list:

'myapp.module',

Including the myapp instead of myapp.module causes all the database tables to be created with incorrect names, so this seems to be the correct way to do it.

I came across this post while looking for a solution to this problem so figured I’d put this here :)


回答 5

只是添加约旦的答案(感谢约旦的提示),如果您在应用程序上方导入级别,然后导入应用程序,则也可能发生这种情况,例如

myproject/ apps/ foo_app/ bar_app/

因此,如果要导入应用程序foo_app和bar_app,则可能会遇到此问题。我的应用程序foo_app和bar_app都列在设置中。INSTALLED_APPS

而且您还是想避免导入应用程序,因为那样您会将相同的应用程序安装在2个不同的命名空间中

apps.foo_appfoo_app

Just adding to Jordan’s answer (thanks for the tip Jordan) it can also happen if you import the level above the apps and then import the apps e.g.

myproject/ apps/ foo_app/ bar_app/

So if you are importing apps, foo_app and bar_app then you could get this issue. I had apps, foo_app and bar_app all listed in settings.INSTALLED_APPS

And you want to avoid importing apps anyway, because then you have the same app installed in 2 different namespaces

apps.foo_app and foo_app


如何在Django中过滤DateTimeField的日期?

问题:如何在Django中过滤DateTimeField的日期?

我试图过滤DateTimeField与日期比较。我的意思是:

MyObject.objects.filter(datetime_attr=datetime.date(2009,8,22))

我得到一个空的查询集列表作为答案,因为(我认为)我不在考虑时间,但我希望“任何时间”。

Django中有一种简单的方法吗?

我在datetime中设置了时间,但不是00:00

I am trying to filter a DateTimeField comparing with a date. I mean:

MyObject.objects.filter(datetime_attr=datetime.date(2009,8,22))

I get an empty queryset list as an answer because (I think) I am not considering time, but I want “any time”.

Is there an easy way in Django for doing this?

I have the time in the datetime setted, it is not 00:00.


回答 0

此类查询的实现django.views.generic.date_based方式如下:

{'date_time_field__range': (datetime.datetime.combine(date, datetime.time.min),
                            datetime.datetime.combine(date, datetime.time.max))} 

因为它很冗长,所以有计划使用__date运算符来改进语法。有关更多详细信息,请检查“ #9596将DateTimeField与日期比较太难 ”。

Such lookups are implemented in django.views.generic.date_based as follows:

{'date_time_field__range': (datetime.datetime.combine(date, datetime.time.min),
                            datetime.datetime.combine(date, datetime.time.max))} 

Because it is quite verbose there are plans to improve the syntax using __date operator. Check “#9596 Comparing a DateTimeField to a date is too hard” for more details.


回答 1

YourModel.objects.filter(datetime_published__year='2008', 
                         datetime_published__month='03', 
                         datetime_published__day='27')

//在评论后编辑

YourModel.objects.filter(datetime_published=datetime(2008, 03, 27))

不起作用,因为它创建了一个时间值设置为0的datetime对象,因此数据库中的时间不匹配。

YourModel.objects.filter(datetime_published__year='2008', 
                         datetime_published__month='03', 
                         datetime_published__day='27')

// edit after comments

YourModel.objects.filter(datetime_published=datetime(2008, 03, 27))

doest not work because it creates a datetime object with time values set to 0, so the time in database doesn’t match.


回答 2

这是我使用ipython的timeit函数得到的结果:

from datetime import date
today = date.today()

timeit[Model.objects.filter(date_created__year=today.year, date_created__month=today.month, date_created__day=today.day)]
1000 loops, best of 3: 652 us per loop

timeit[Model.objects.filter(date_created__gte=today)]
1000 loops, best of 3: 631 us per loop

timeit[Model.objects.filter(date_created__startswith=today)]
1000 loops, best of 3: 541 us per loop

timeit[Model.objects.filter(date_created__contains=today)]
1000 loops, best of 3: 536 us per loop

包含似乎更快。

Here are the results I got with ipython’s timeit function:

from datetime import date
today = date.today()

timeit[Model.objects.filter(date_created__year=today.year, date_created__month=today.month, date_created__day=today.day)]
1000 loops, best of 3: 652 us per loop

timeit[Model.objects.filter(date_created__gte=today)]
1000 loops, best of 3: 631 us per loop

timeit[Model.objects.filter(date_created__startswith=today)]
1000 loops, best of 3: 541 us per loop

timeit[Model.objects.filter(date_created__contains=today)]
1000 loops, best of 3: 536 us per loop

contains seems to be faster.


回答 3

现在,Django具有__date queryset过滤器,可以针对开发版本中的日期查询datetime对象。因此,它将很快在1.9中可用。

Now Django has __date queryset filter to query datetime objects against dates in development version. Thus, it will be available in 1.9 soon.


回答 4

Mymodel.objects.filter(date_time_field__contains=datetime.date(1986, 7, 28))

以上是我用过的。它不仅有效,而且还具有一些固有的逻辑支持。

Mymodel.objects.filter(date_time_field__contains=datetime.date(1986, 7, 28))

the above is what I’ve used. Not only does it work, it also has some inherent logical backing.


回答 5

从Django 1.9开始,执行此操作的方法是__date在datetime对象上使用。

例如: MyObject.objects.filter(datetime_attr__date=datetime.date(2009,8,22))

As of Django 1.9, the way to do this is by using __date on a datetime object.

For example: MyObject.objects.filter(datetime_attr__date=datetime.date(2009,8,22))


回答 6

这产生与使用__year,__ month和__day相同的结果,并且似乎对我有用:

YourModel.objects.filter(your_datetime_field__startswith=datetime.date(2009,8,22))

This produces the same results as using __year, __month, and __day and seems to work for me:

YourModel.objects.filter(your_datetime_field__startswith=datetime.date(2009,8,22))

回答 7

假设active_on是一个日期对象,将其增加1天,然后进行范围调整

next_day = active_on + datetime.timedelta(1)
queryset = queryset.filter(date_created__range=(active_on, next_day) )

assuming active_on is a date object, increment it by 1 day then do range

next_day = active_on + datetime.timedelta(1)
queryset = queryset.filter(date_created__range=(active_on, next_day) )

回答 8

这是一种有趣的技术-我利用在Django上在MySQL上实现的startswith过程来实现只在日期中查找日期时间的结果。基本上,当Django在数据库中进行查找时,它必须对DATETIME MySQL存储对象进行字符串转换,因此您可以对此进行过滤,而忽略日期的时间戳部分-这样%LIKE%仅与日期匹配对象,您将获得给定日期的每个时间戳。

datetime_filter = datetime(2009, 8, 22) 
MyObject.objects.filter(datetime_attr__startswith=datetime_filter.date())

这将执行以下查询:

SELECT (values) FROM myapp_my_object \ 
WHERE myapp_my_object.datetime_attr LIKE BINARY 2009-08-22%

在这种情况下,无论时间戳如何,LIKE BINARY都将匹配日期中的所有内容。包括以下值:

+---------------------+
| datetime_attr       |
+---------------------+
| 2009-08-22 11:05:08 |
+---------------------+

希望这对所有人都有帮助,直到Django提出解决方案为止!

Here is an interesting technique– I leveraged the startswith procedure as implemented with Django on MySQL to achieve the result of only looking up a datetime through only the date. Basically, when Django does the lookup in the database it has to do a string conversion for the DATETIME MySQL storage object, so you can filter on that, leaving out the timestamp portion of the date– that way %LIKE% matches only the date object and you’ll get every timestamp for the given date.

datetime_filter = datetime(2009, 8, 22) 
MyObject.objects.filter(datetime_attr__startswith=datetime_filter.date())

This will perform the following query:

SELECT (values) FROM myapp_my_object \ 
WHERE myapp_my_object.datetime_attr LIKE BINARY 2009-08-22%

The LIKE BINARY in this case will match everything for the date, no matter the timestamp. Including values like:

+---------------------+
| datetime_attr       |
+---------------------+
| 2009-08-22 11:05:08 |
+---------------------+

Hopefully this helps everyone until Django comes out with a solution!


回答 9

这里有一篇很棒的博客文章:在Django ORM中比较日期和日期时间

为Django> 1.7,<1.9发布的最佳解决方案是注册一个转换:

from django.db import models

class MySQLDatetimeDate(models.Transform):
    """
    This implements a custom SQL lookup when using `__date` with datetimes.
    To enable filtering on datetimes that fall on a given date, import
    this transform and register it with the DateTimeField.
    """
    lookup_name = 'date'

    def as_sql(self, compiler, connection):
        lhs, params = compiler.compile(self.lhs)
        return 'DATE({})'.format(lhs), params

    @property
    def output_field(self):
        return models.DateField()

然后可以在过滤器中使用它,如下所示:

Foo.objects.filter(created_on__date=date)

编辑

此解决方案绝对取决于后端。从文章:

当然,此实现依赖于具有DATE()函数的SQL的特定风格。MySQL确实如此。SQLite也是如此。另一方面,我还没有亲自使用PostgreSQL,但是通过谷歌搜索使我相信它没有DATE()函数。因此,这种简单的实现似乎必然与后端有关。

There’s a fantastic blogpost that covers this here: Comparing Dates and Datetimes in the Django ORM

The best solution posted for Django>1.7,<1.9 is to register a transform:

from django.db import models

class MySQLDatetimeDate(models.Transform):
    """
    This implements a custom SQL lookup when using `__date` with datetimes.
    To enable filtering on datetimes that fall on a given date, import
    this transform and register it with the DateTimeField.
    """
    lookup_name = 'date'

    def as_sql(self, compiler, connection):
        lhs, params = compiler.compile(self.lhs)
        return 'DATE({})'.format(lhs), params

    @property
    def output_field(self):
        return models.DateField()

Then you can use it in your filters like this:

Foo.objects.filter(created_on__date=date)

EDIT

This solution is definitely back end dependent. From the article:

Of course, this implementation relies on your particular flavor of SQL having a DATE() function. MySQL does. So does SQLite. On the other hand, I haven’t worked with PostgreSQL personally, but some googling leads me to believe that it does not have a DATE() function. So an implementation this simple seems like it will necessarily be somewhat backend-dependent.


回答 10

嗯..我的解决方案正在工作:

Mymodel.objects.filter(date_time_field__startswith=datetime.datetime(1986, 7, 28))

Hm.. My solution is working:

Mymodel.objects.filter(date_time_field__startswith=datetime.datetime(1986, 7, 28))

回答 11

Model.objects.filter(datetime__year=2011, datetime__month=2, datetime__day=30)
Model.objects.filter(datetime__year=2011, datetime__month=2, datetime__day=30)

回答 12

在Django 1.7.6中工作:

MyObject.objects.filter(datetime_attr__startswith=datetime.date(2009,8,22))

In Django 1.7.6 works:

MyObject.objects.filter(datetime_attr__startswith=datetime.date(2009,8,22))

回答 13

请参阅文章Django文档

ur_data_model.objects.filter(ur_date_field__gte=datetime(2009, 8, 22), ur_date_field__lt=datetime(2009, 8, 23))

See the article Django Documentation

ur_data_model.objects.filter(ur_date_field__gte=datetime(2009, 8, 22), ur_date_field__lt=datetime(2009, 8, 23))

设置Django以使用MySQL

问题:设置Django以使用MySQL

我想稍微远离PHP,学习Python。为了使用Python进行Web开发,我需要一个框架来帮助模板和其他事情。

我有一台非生产服务器,用于测试所有Web开发内容。这是一个运行MariaDB而不是常见的MySQL服务器软件包的Debian 7.1 LAMP堆栈。

昨天我安装了Django并创建了我的第一个项目firstweb。我尚未更改任何设置。

这是我的第一个大困惑。在教程中,我跟随那个家伙安装了Django,开始了他的第一个项目,重新启动了Apache,从那时起Django就开始工作了。他转到浏览器,然后毫无问题地转到Django默认页面。

但是我,我必须进入我的firstweb文件夹并运行

python manage.py runserver myip:port

而且有效。没问题。但是我想知道它是否应该像这样工作,并且这是否会引起问题?

我的第二个问题是我想对其进行设置,以便它使用我的MySQL数据库。我进入/ firstweb / firstweb下的settings.py,看到了ENGINE和NAME,但不确定在这里放什么。

然后在USER,PASSWORD和HOST区域中,这是我的数据库及其凭据吗?如果我使用本地主机,是否可以将本地主机放在HOST区域中?

I want to move away from PHP a little and learn Python. In order to do web development with Python I’ll need a framework to help with templating and other things.

I have a non-production server that I use to test all of web development stuff on. It is a Debian 7.1 LAMP stack that runs MariaDB instead of the common MySQL-server package.

Yesterday I installed Django and created my first project called firstweb. I have not changed any settings yet.

Here is my first big piece of confusion. In the tutorial I followed the guy installed Django, started his first project, restarted Apache, and Django just worked from then on. He went to his browser and went to the Django default page with no problems.

Me however, I have to cd into my firstweb folder and run

python manage.py runserver myip:port

And it works. No problem. But I’m wondering if it is supposed to work like this, and if this will cause problems down the line?

My second question is that I want to set it up so it uses my MySQL database. I go into my settings.py under /firstweb/firstweb and I see ENGINE and NAME but I’m not sure what to put here.

And then in the USER, PASSWORD, and HOST areas is this my database and its credentials? If I am using localhost can I just put localhost in the HOST area?


回答 0

MySQL支持很容易添加。在您的DATABASES字典中,您将有一个像这样的条目:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', 
        'NAME': 'DB_NAME',
        'USER': 'DB_USER',
        'PASSWORD': 'DB_PASSWORD',
        'HOST': 'localhost',   # Or an IP Address that your DB is hosted on
        'PORT': '3306',
    }
}

从Django 1.7开始,您还可以选择使用MySQL 选项文件。您可以这样设置DATABASES数组来完成此操作:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'OPTIONS': {
            'read_default_file': '/path/to/my.cnf',
        },
    }
}

您还需要/path/to/my.cnf使用与上面类似的设置来创建文件

[client]
database = DB_NAME
host = localhost
user = DB_USER
password = DB_PASSWORD
default-character-set = utf8

使用Django 1.7中的这种新连接方法,重要的是要知道建立了顺序连接:

1. OPTIONS.
2. NAME, USER, PASSWORD, HOST, PORT
3. MySQL option files.

换句话说,如果在OPTIONS中设置数据库的名称,它将优先于NAME,而NAME将覆盖MySQL选项文件中的所有内容。


如果您只是在本地计算机上测试应用程序,则可以使用

python manage.py runserver

添加ip:port参数允许您自己的机器以外的其他机器访问您的开发应用程序。准备好部署应用程序后,建议您阅读djangobook上有关部署Django章节

MySQL默认字符集通常不是utf-8,因此请确保使用以下sql创建数据库:

CREATE DATABASE mydatabase CHARACTER SET utf8 COLLATE utf8_bin

如果您正在使用Oracle的MySQL的连接器ENGINE线应该是这样的:

'ENGINE': 'mysql.connector.django',

请注意,您首先需要在操作系统上安装mysql。

brew install mysql (MacOS)

此外,mysql客户端软件包已针对python 3进行了更改(MySQL-Client仅适用于python 2)

pip3 install mysqlclient

MySQL support is simple to add. In your DATABASES dictionary, you will have an entry like this:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', 
        'NAME': 'DB_NAME',
        'USER': 'DB_USER',
        'PASSWORD': 'DB_PASSWORD',
        'HOST': 'localhost',   # Or an IP Address that your DB is hosted on
        'PORT': '3306',
    }
}

You also have the option of utilizing MySQL option files, as of Django 1.7. You can accomplish this by setting your DATABASES array like so:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'OPTIONS': {
            'read_default_file': '/path/to/my.cnf',
        },
    }
}

You also need to create the /path/to/my.cnf file with similar settings from above

[client]
database = DB_NAME
host = localhost
user = DB_USER
password = DB_PASSWORD
default-character-set = utf8

With this new method of connecting in Django 1.7, it is important to know the order connections are established:

1. OPTIONS.
2. NAME, USER, PASSWORD, HOST, PORT
3. MySQL option files.

In other words, if you set the name of the database in OPTIONS, this will take precedence over NAME, which would override anything in a MySQL option file.


If you are just testing your application on your local machine, you can use

python manage.py runserver

Adding the ip:port argument allows machines other than your own to access your development application. Once you are ready to deploy your application, I recommend taking a look at the chapter on Deploying Django on the djangobook

Mysql default character set is often not utf-8, therefore make sure to create your database using this sql:

CREATE DATABASE mydatabase CHARACTER SET utf8 COLLATE utf8_bin

If you are using Oracle’s MySQL connector your ENGINE line should look like this:

'ENGINE': 'mysql.connector.django',

Note that you will first need to install mysql on your OS.

brew install mysql (MacOS)

Also, the mysql client package has changed for python 3 (MySQL-Client works only for python 2)

pip3 install mysqlclient

回答 1

首先,请运行以下命令以安装python依赖项,否则python runserver命令将引发错误。

sudo apt-get install libmysqlclient-dev
sudo pip install MySQL-python

然后配置#Andy定义的settings.py文件,并在最后一次执行:

python manage.py runserver

玩得开心..!!

To the very first please run the below commands to install python dependencies otherwise python runserver command will throw error.

sudo apt-get install libmysqlclient-dev
sudo pip install MySQL-python

Then configure the settings.py file as defined by #Andy and at the last execute :

python manage.py runserver

Have fun..!!


回答 2

如果您使用的是python3.x,则运行以下命令

pip install mysqlclient

然后像这样更改setting.py

DATABASES = {
'default': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME': 'DB',
     'USER': 'username',
    'PASSWORD': 'passwd',
  }
  }

If you are using python3.x then Run below command

pip install mysqlclient

Then change setting.py like

DATABASES = {
'default': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME': 'DB',
     'USER': 'username',
    'PASSWORD': 'passwd',
  }
  }

回答 3

如上所述,您可以轻松地首先从https://www.apachefriends.org/download.html安装xampp, 然后按照以下说明进行操作:

  1. http://www.unixmen.com/install-xampp-stack-ubuntu-14-04/安装并运行xampp ,然后从GUI启动Apache Web Server和MySQL数据库。
  2. 您可以根据需要配置Web服务器,但默认情况下Web服务器位于http://localhost:80,数据库位于port 3306,而PhpMyadmin位于http://localhost/phpmyadmin/
  3. 从这里您可以看到您的数据库,并使用非常友好的GUI访问它们。
  4. 创建要在Django项目上使用的任何数据库。
  5. settings.py像这样编辑文件:

    DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'DB_NAME',
        'HOST': '127.0.0.1',
        'PORT': '3306',
        'USER': 'root',
        'PASSWORD': '',
    }}
  6. 在virtualenv中安装以下软件包(如果您在virtualenv上使用django,则更可取):

    sudo apt-get安装libmysqlclient-dev

    pip安装MySQL-python

  7. 而已!!您已经以非常简单的方式为MySQL配置了Django。

  8. 现在运行您的Django项目:

    python manage.py迁移

    python manage.py运行服务器

As all said above, you can easily install xampp first from https://www.apachefriends.org/download.html Then follow the instructions as:

  1. Install and run xampp from http://www.unixmen.com/install-xampp-stack-ubuntu-14-04/, then start Apache Web Server and MySQL Database from the GUI.
  2. You can configure your web server as you want but by default web server is at http://localhost:80 and database at port 3306, and PhpMyadmin at http://localhost/phpmyadmin/
  3. From here you can see your databases and access them using very friendly GUI.
  4. Create any database which you want to use on your Django Project.
  5. Edit your settings.py file like:

    DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'DB_NAME',
        'HOST': '127.0.0.1',
        'PORT': '3306',
        'USER': 'root',
        'PASSWORD': '',
    }}
    
  6. Install the following packages in the virtualenv (if you’re using django on virtualenv, which is more preferred):

    sudo apt-get install libmysqlclient-dev

    pip install MySQL-python

  7. That’s it!! you have configured Django with MySQL in a very easy way.

  8. Now run your Django project:

    python manage.py migrate

    python manage.py runserver


回答 4

实际上,不同的环境,python版本等等存在很多问题。您可能还需要安装python dev文件,因此要“强行安装”,我将运行所有这些文件:

sudo apt-get install python-dev python3-dev
sudo apt-get install libmysqlclient-dev
pip install MySQL-python
pip install pymysql
pip install mysqlclient

您应该接受公认的答案。如果对您很重要,可以删除不需要的软件包。

Actually, there are many issues with different environments, python versions, so on. You might also need to install python dev files, so to ‘brute-force’ the installation I would run all of these:

sudo apt-get install python-dev python3-dev
sudo apt-get install libmysqlclient-dev
pip install MySQL-python
pip install pymysql
pip install mysqlclient

You should be good to go with the accepted answer. And can remove the unnecessary packages if that’s important to you.


回答 5

运行这些命令

sudo apt-get install python-dev python3-dev
sudo apt-get install libmysqlclient-dev
pip install MySQL-python 
pip install pymysql
pip install mysqlclient

然后像这样配置settings.py

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'django_db',
        'HOST': '127.0.0.1',
        'PORT': '3306',
        'USER': 'root',
        'PASSWORD': '123456',
    }
}

享受mysql连接

Run these commands

sudo apt-get install python-dev python3-dev
sudo apt-get install libmysqlclient-dev
pip install MySQL-python 
pip install pymysql
pip install mysqlclient

Then configure settings.py like

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'django_db',
        'HOST': '127.0.0.1',
        'PORT': '3306',
        'USER': 'root',
        'PASSWORD': '123456',
    }
}

Enjoy mysql connection


回答 6

安迪的答案很有帮助,但是如果您担心要在django设置中公开数据库密码,我建议在mysql连接上遵循django官方配置:https : //docs.djangoproject.com/en/1.7/ref/databases/

在这里引用为:

# settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'OPTIONS': {
            'read_default_file': '/path/to/my.cnf',
        },
    }
}


# my.cnf
[client]
database = NAME
user = USER
password = PASSWORD
default-character-set = utf8

要在设置中替换“ HOST”:“ 127.0.0.1”,只需将其添加到my.cnf中:

# my.cnf
[client]
database = NAME
host = HOST NAME or IP
user = USER
password = PASSWORD
default-character-set = utf8

另一个有用的选项是为django设置存储引擎,您可能需要在setting.py中使用它:

'OPTIONS': {
   'init_command': 'SET storage_engine=INNODB',
}

Andy’s answer helps but if you have concern on exposing your database password in your django setting, I suggest to follow django official configuration on mysql connection: https://docs.djangoproject.com/en/1.7/ref/databases/

Quoted here as:

# settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'OPTIONS': {
            'read_default_file': '/path/to/my.cnf',
        },
    }
}


# my.cnf
[client]
database = NAME
user = USER
password = PASSWORD
default-character-set = utf8

To replace ‘HOST’: ‘127.0.0.1’ in setting, simply add it in my.cnf:

# my.cnf
[client]
database = NAME
host = HOST NAME or IP
user = USER
password = PASSWORD
default-character-set = utf8

Another OPTION that is useful, is to set your storage engine for django, you might want it in your setting.py:

'OPTIONS': {
   'init_command': 'SET storage_engine=INNODB',
}

回答 7

settings.py

DATABASES = {
'default': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME': 'django',
    'USER': 'root',
    'PASSWORD': '*****',
    'HOST': '***.***.***.***',
    'PORT': '3306',
    'OPTIONS': {
        'autocommit': True,
    },
}

}

然后:

python manage.py migrate

如果成功将生成这些表:

auth_group
auth_group_permissions
auth_permission
auth_user
auth_user_groups
auth_user_user_permissions
django_admin_log
django_content_type
django_migrations
django_session

您将可以使用mysql。

这是一个展示示例,请在Django 1.11.5版上进行测试: Django-pool-showcase

settings.py

DATABASES = {
'default': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME': 'django',
    'USER': 'root',
    'PASSWORD': '*****',
    'HOST': '***.***.***.***',
    'PORT': '3306',
    'OPTIONS': {
        'autocommit': True,
    },
}

}

then:

python manage.py migrate

if success will generate theses tables:

auth_group
auth_group_permissions
auth_permission
auth_user
auth_user_groups
auth_user_user_permissions
django_admin_log
django_content_type
django_migrations
django_session

and u will can use mysql.

this is a showcase example ,test on Django version 1.11.5: Django-pool-showcase


回答 8

  1. 安装 mysqlclient

sudo pip3 install mysqlclient

如果出现错误:

命令“ python setup.py egg_info”在/ tmp / pip-install-dbljg4tx / mysqlclient /中失败,错误代码为1

然后:

 1. sudo apt install libmysqlclient-dev python-mysqldb

 2. sudo pip3 install mysqlclient

  1. 修改settings.py

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'website',
            'USER': 'root',
            'PASSWORD': '',
            'HOST': '127.0.0.1',
            'PORT': '3306',
            'OPTION': {'init_command':"SET sql_mode='STRICT_TRANS_TABLE',"},
        }
    }
  1. Install mysqlclient

sudo pip3 install mysqlclient

if you get error:

Command “python setup.py egg_info” failed with error code 1 in /tmp/pip-install-dbljg4tx/mysqlclient/

then:

 1. sudo apt install libmysqlclient-dev python-mysqldb

 2. sudo pip3 install mysqlclient

  1. Modify settings.py

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'website',
            'USER': 'root',
            'PASSWORD': '',
            'HOST': '127.0.0.1',
            'PORT': '3306',
            'OPTION': {'init_command':"SET sql_mode='STRICT_TRANS_TABLE',"},
        }
    }
    

回答 9

请按照给定的步骤进行设置以使用MySQL数据库:

1) Install MySQL Database Connector :

    sudo apt-get install libmysqlclient-dev

2) Install the mysqlclient library :

    pip install mysqlclient

3) Install MySQL server, with the following command :

    sudo apt-get install mysql-server

4) Create the Database :

    i) Verify that the MySQL service is running:

        systemctl status mysql.service

    ii) Log in with your MySQL credentials using the following command where -u is the flag for declaring your username and -p is the flag that tells MySQL that this user requires a password :  

        mysql -u db_user -p


    iii) CREATE DATABASE db_name;

    iv) Exit MySQL server, press CTRL + D.

5) Add the MySQL Database Connection to your Application:

    i) Navigate to the settings.py file and replace the current DATABASES lines with the following:

        # Database
        # https://docs.djangoproject.com/en/2.0/ref/settings/#databases

        DATABASES = {
            'default': {
                'ENGINE': 'django.db.backends.mysql',
                'OPTIONS': {
                    'read_default_file': '/etc/mysql/my.cnf',
                },
            }
        }
        ...

    ii) Next, lets edit the config file so that it has your MySQL credentials. Use vi as sudo to edit the file and add the following information:

        sudo vi /etc/mysql/my.cnf

        database = db_name
        user = db_user
        password = db_password
        default-character-set = utf8

6) Once the file has been edited, we need to restart MySQL for the changes to take effect :

    systemctl daemon-reload

    systemctl restart mysql

7) Test MySQL Connection to Application:

    python manage.py runserver your-server-ip:8000

Follow the given steps in order to setup it up to use MySQL database:

1) Install MySQL Database Connector :

    sudo apt-get install libmysqlclient-dev

2) Install the mysqlclient library :

    pip install mysqlclient

3) Install MySQL server, with the following command :

    sudo apt-get install mysql-server

4) Create the Database :

    i) Verify that the MySQL service is running:

        systemctl status mysql.service

    ii) Log in with your MySQL credentials using the following command where -u is the flag for declaring your username and -p is the flag that tells MySQL that this user requires a password :  

        mysql -u db_user -p


    iii) CREATE DATABASE db_name;

    iv) Exit MySQL server, press CTRL + D.

5) Add the MySQL Database Connection to your Application:

    i) Navigate to the settings.py file and replace the current DATABASES lines with the following:

        # Database
        # https://docs.djangoproject.com/en/2.0/ref/settings/#databases

        DATABASES = {
            'default': {
                'ENGINE': 'django.db.backends.mysql',
                'OPTIONS': {
                    'read_default_file': '/etc/mysql/my.cnf',
                },
            }
        }
        ...

    ii) Next, let’s edit the config file so that it has your MySQL credentials. Use vi as sudo to edit the file and add the following information:

        sudo vi /etc/mysql/my.cnf

        database = db_name
        user = db_user
        password = db_password
        default-character-set = utf8

6) Once the file has been edited, we need to restart MySQL for the changes to take effect :

    systemctl daemon-reload

    systemctl restart mysql

7) Test MySQL Connection to Application:

    python manage.py runserver your-server-ip:8000

回答 10

您必须首先创建一个MySQL数据库。然后转到settings.py文件并'DATABASES'使用您的MySQL凭据编辑字典:

DATABASES = {
 'default': {
 'ENGINE': 'django.db.backends.mysql',
 'NAME': 'YOUR_DATABASE_NAME',
 'USER': 'YOUR_MYSQL_USER',
 'PASSWORD': 'YOUR_MYSQL_PASS',
 'HOST': 'localhost',   # Or an IP that your DB is hosted on
 'PORT': '3306',
 }
}

这是用于将Django设置为在virtualenv上使用MySQL的完整安装指南:

http://codex.themedelta.com/how-to-install-django-with-mysql-in-a-virtualenv-on-linux/

You must create a MySQL database first. Then go to settings.py file and edit the 'DATABASES' dictionary with your MySQL credentials:

DATABASES = {
 'default': {
 'ENGINE': 'django.db.backends.mysql',
 'NAME': 'YOUR_DATABASE_NAME',
 'USER': 'YOUR_MYSQL_USER',
 'PASSWORD': 'YOUR_MYSQL_PASS',
 'HOST': 'localhost',   # Or an IP that your DB is hosted on
 'PORT': '3306',
 }
}

Here is a complete installation guide for setting up Django to use MySQL on a virtualenv:

http://codex.themedelta.com/how-to-install-django-with-mysql-in-a-virtualenv-on-linux/


以自定义形式使用Django时间/日期小部件

问题:以自定义形式使用Django时间/日期小部件

如何使用默认管理员在自定义视图中使用的漂亮的JavaScript日期和时间小部件?

我浏览了Django表单文档,其中简要提到了django.contrib.admin.widgets,但我不知道如何使用它?

这是我希望将其应用于的模板。

<form action="." method="POST">
    <table>
        {% for f in form %}
           <tr> <td> {{ f.name }}</td> <td>{{ f }}</td> </tr>
        {% endfor %}
    </table>
    <input type="submit" name="submit" value="Add Product">
</form>

另外,我认为应该指出的是,我并未真正为这种形式编写视图,而是使用了通用视图。这是url.py中的条目:

(r'^admin/products/add/$', create_object, {'model': Product, 'post_save_redirect': ''}),

而且我对整个Django / MVC / MTV都是陌生的,所以请放轻松…

How can I use the nifty JavaScript date and time widgets that the default admin uses with my custom view?

I have looked through the Django forms documentation, and it briefly mentions django.contrib.admin.widgets, but I don’t know how to use it?

Here is my template that I want it applied on.

<form action="." method="POST">
    <table>
        {% for f in form %}
           <tr> <td> {{ f.name }}</td> <td>{{ f }}</td> </tr>
        {% endfor %}
    </table>
    <input type="submit" name="submit" value="Add Product">
</form>

Also, I think it should be noted that I haven’t really written a view up myself for this form, I am using a generic view. Here is the entry from the url.py:

(r'^admin/products/add/$', create_object, {'model': Product, 'post_save_redirect': ''}),

And I am relevantly new to the whole Django/MVC/MTV thing, so please go easy…


回答 0

随着时间的流逝,此答案的复杂性不断提高,并且需要进行许多破解,可能应该警告您不要这样做。它依赖于管理员未记录的内部实现细节,可能会在将来的Django版本中再次中断,并且比找到另一个JS日历小部件并使用它更容易实现。

就是说,如果您决心进行这项工作,这是您必须做的:

  1. 为模型定义自己的ModelForm子类(最好将其放在应用程序的forms.py中),并告诉它使用AdminDateWidget / AdminTimeWidget / AdminSplitDateTime(用模型中的正确字段名称替换“ mydate”等):

    from django import forms
    from my_app.models import Product
    from django.contrib.admin import widgets                                       
    
    class ProductForm(forms.ModelForm):
        class Meta:
            model = Product
        def __init__(self, *args, **kwargs):
            super(ProductForm, self).__init__(*args, **kwargs)
            self.fields['mydate'].widget = widgets.AdminDateWidget()
            self.fields['mytime'].widget = widgets.AdminTimeWidget()
            self.fields['mydatetime'].widget = widgets.AdminSplitDateTime()
  2. 更改您的URLconf,以将“ form_class”:ProductForm而不是“ model”:Product传递到通用的create_object视图(这当然意味着“从my_app.forms import ProductForm”而不是“从my_app.models import Product”)。

  3. 在模板的开头,包括{{form.media}},以输出指向Javascript文件的链接。

  4. hacky部分:admin日期/时间小部件假定i18n JS东西已加载,并且还需要core.js,但不会自动提供其中任何一个。因此,在{{form.media}}上方的模板中,您需要:

    <script type="text/javascript" src="/my_admin/jsi18n/"></script>
    <script type="text/javascript" src="/media/admin/js/core.js"></script>

    您可能还希望使用以下管理CSS(感谢Alex提到了这一点):

    <link rel="stylesheet" type="text/css" href="/media/admin/css/forms.css"/>
    <link rel="stylesheet" type="text/css" href="/media/admin/css/base.css"/>
    <link rel="stylesheet" type="text/css" href="/media/admin/css/global.css"/>
    <link rel="stylesheet" type="text/css" href="/media/admin/css/widgets.css"/>

这意味着Django的管理媒体(ADMIN_MEDIA_PREFIX)位于/ media / admin /-您可以更改其设置。理想情况下,您将使用上下文处理器将此值传递给模板,而不是对其进行硬编码,但这超出了此问题的范围。

这还需要将URL / my_admin / jsi18n /手动连接到django.views.i18n.javascript_catalog视图(如果未使用I18N,则为null_javascript_catalog)。您必须自己执行此操作,而不是通过admin应用程序,因此无论您是否登录到admin都可以访问它(感谢Jeremy指出了这一点)。URLconf的示例代码:

(r'^my_admin/jsi18n', 'django.views.i18n.javascript_catalog'),

最后,如果您使用的是Django 1.2或更高版本,则需要在模板中添加一些其他代码来帮助小部件找到其媒体:

{% load adminmedia %} /* At the top of the template. */

/* In the head section of the template. */
<script type="text/javascript">
window.__admin_media_prefix__ = "{% filter escapejs %}{% admin_media_prefix %}{% endfilter %}";
</script>

感谢lupefiasco的添加。

The growing complexity of this answer over time, and the many hacks required, probably ought to caution you against doing this at all. It’s relying on undocumented internal implementation details of the admin, is likely to break again in future versions of Django, and is no easier to implement than just finding another JS calendar widget and using that.

That said, here’s what you have to do if you’re determined to make this work:

  1. Define your own ModelForm subclass for your model (best to put it in forms.py in your app), and tell it to use the AdminDateWidget / AdminTimeWidget / AdminSplitDateTime (replace ‘mydate’ etc with the proper field names from your model):

    from django import forms
    from my_app.models import Product
    from django.contrib.admin import widgets                                       
    
    class ProductForm(forms.ModelForm):
        class Meta:
            model = Product
        def __init__(self, *args, **kwargs):
            super(ProductForm, self).__init__(*args, **kwargs)
            self.fields['mydate'].widget = widgets.AdminDateWidget()
            self.fields['mytime'].widget = widgets.AdminTimeWidget()
            self.fields['mydatetime'].widget = widgets.AdminSplitDateTime()
    
  2. Change your URLconf to pass ‘form_class’: ProductForm instead of ‘model’: Product to the generic create_object view (that’ll mean “from my_app.forms import ProductForm” instead of “from my_app.models import Product”, of course).

  3. In the head of your template, include {{ form.media }} to output the links to the Javascript files.

  4. And the hacky part: the admin date/time widgets presume that the i18n JS stuff has been loaded, and also require core.js, but don’t provide either one automatically. So in your template above {{ form.media }} you’ll need:

    <script type="text/javascript" src="/my_admin/jsi18n/"></script>
    <script type="text/javascript" src="/media/admin/js/core.js"></script>
    

    You may also wish to use the following admin CSS (thanks Alex for mentioning this):

    <link rel="stylesheet" type="text/css" href="/media/admin/css/forms.css"/>
    <link rel="stylesheet" type="text/css" href="/media/admin/css/base.css"/>
    <link rel="stylesheet" type="text/css" href="/media/admin/css/global.css"/>
    <link rel="stylesheet" type="text/css" href="/media/admin/css/widgets.css"/>
    

This implies that Django’s admin media (ADMIN_MEDIA_PREFIX) is at /media/admin/ – you can change that for your setup. Ideally you’d use a context processor to pass this values to your template instead of hardcoding it, but that’s beyond the scope of this question.

This also requires that the URL /my_admin/jsi18n/ be manually wired up to the django.views.i18n.javascript_catalog view (or null_javascript_catalog if you aren’t using I18N). You have to do this yourself instead of going through the admin application so it’s accessible regardless of whether you’re logged into the admin (thanks Jeremy for pointing this out). Sample code for your URLconf:

(r'^my_admin/jsi18n', 'django.views.i18n.javascript_catalog'),

Lastly, if you are using Django 1.2 or later, you need some additional code in your template to help the widgets find their media:

{% load adminmedia %} /* At the top of the template. */

/* In the head section of the template. */
<script type="text/javascript">
window.__admin_media_prefix__ = "{% filter escapejs %}{% admin_media_prefix %}{% endfilter %}";
</script>

Thanks lupefiasco for this addition.


回答 1

由于该解决方案有点漏洞,因此我认为将自己的日期/时间窗口小部件与一些JavaScript结合使用更可行。

As the solution is hackish, I think using your own date/time widget with some JavaScript is more feasible.


回答 2

是的,我最终覆盖了/ admin / jsi18n /网址。

这是我在urls.py中添加的内容。确保它在/ admin /网址上方

    (r'^admin/jsi18n', i18n_javascript),

这是我创建的i18n_javascript函数。

from django.contrib import admin
def i18n_javascript(request):
  return admin.site.i18n_javascript(request)

Yep, I ended up overriding the /admin/jsi18n/ url.

Here’s what I added in my urls.py. Make sure it’s above the /admin/ url

    (r'^admin/jsi18n', i18n_javascript),

And here is the i18n_javascript function I created.

from django.contrib import admin
def i18n_javascript(request):
  return admin.site.i18n_javascript(request)

回答 3

我发现自己经常引用这篇文章,并且发现文档定义了一种略微不友好的方法来覆盖默认小部件。

无需重写ModelForm的__init__方法

但是,您仍然需要如Carl所述适当地连接JS和CSS。

表格

from django import forms
from my_app.models import Product
from django.contrib.admin import widgets                                       


class ProductForm(forms.ModelForm):
    mydate = forms.DateField(widget=widgets.AdminDateWidget)
    mytime = forms.TimeField(widget=widgets.AdminTimeWidget)
    mydatetime = forms.SplitDateTimeField(widget=widgets.AdminSplitDateTime)

    class Meta:
        model = Product

参考字段类型以查找默认表单字段。

I find myself referencing this post a lot, and found that the documentation defines a slightly less hacky way to override default widgets.

(No need to override the ModelForm’s __init__ method)

However, you still need to wire your JS and CSS appropriately as Carl mentions.

forms.py

from django import forms
from my_app.models import Product
from django.contrib.admin import widgets                                       


class ProductForm(forms.ModelForm):
    mydate = forms.DateField(widget=widgets.AdminDateWidget)
    mytime = forms.TimeField(widget=widgets.AdminTimeWidget)
    mydatetime = forms.SplitDateTimeField(widget=widgets.AdminSplitDateTime)

    class Meta:
        model = Product

Reference Field Types to find the default form fields.


回答 4

我的1.4版头代码(有些是新增的,有些是删除的)

{% block extrahead %}

<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}admin/css/forms.css"/>
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}admin/css/base.css"/>
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}admin/css/global.css"/>
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}admin/css/widgets.css"/>

<script type="text/javascript" src="/admin/jsi18n/"></script>
<script type="text/javascript" src="{{ STATIC_URL }}admin/js/core.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}admin/js/admin/RelatedObjectLookups.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}admin/js/jquery.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}admin/js/jquery.init.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}admin/js/actions.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}admin/js/calendar.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}admin/js/admin/DateTimeShortcuts.js"></script>

{% endblock %}

My head code for 1.4 version(some new and some removed)

{% block extrahead %}

<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}admin/css/forms.css"/>
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}admin/css/base.css"/>
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}admin/css/global.css"/>
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}admin/css/widgets.css"/>

<script type="text/javascript" src="/admin/jsi18n/"></script>
<script type="text/javascript" src="{{ STATIC_URL }}admin/js/core.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}admin/js/admin/RelatedObjectLookups.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}admin/js/jquery.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}admin/js/jquery.init.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}admin/js/actions.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}admin/js/calendar.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}admin/js/admin/DateTimeShortcuts.js"></script>

{% endblock %}

回答 5

从Django 1.2 RC1开始,如果您使用的是Django admin日期选择器widge技巧,则必须将以下内容添加到模板中,否则您将看到通过“ / missing-admin-media-prefix”引用的日历图标url /”。

{% load adminmedia %} /* At the top of the template. */

/* In the head section of the template. */
<script type="text/javascript">
window.__admin_media_prefix__ = "{% filter escapejs %}{% admin_media_prefix %}{% endfilter %}";
</script>

Starting in Django 1.2 RC1, if you’re using the Django admin date picker widge trick, the following has to be added to your template, or you’ll see the calendar icon url being referenced through “/missing-admin-media-prefix/”.

{% load adminmedia %} /* At the top of the template. */

/* In the head section of the template. */
<script type="text/javascript">
window.__admin_media_prefix__ = "{% filter escapejs %}{% admin_media_prefix %}{% endfilter %}";
</script>

回答 6

为了补充Carl Meyer的答案,我想评论一下,您需要将该标头放在模板中的某个有效块中(标头内)。

{% block extra_head %}

<link rel="stylesheet" type="text/css" href="/media/admin/css/forms.css"/>
<link rel="stylesheet" type="text/css" href="/media/admin/css/base.css"/>
<link rel="stylesheet" type="text/css" href="/media/admin/css/global.css"/>
<link rel="stylesheet" type="text/css" href="/media/admin/css/widgets.css"/>

<script type="text/javascript" src="/admin/jsi18n/"></script>
<script type="text/javascript" src="/media/admin/js/core.js"></script>
<script type="text/javascript" src="/media/admin/js/admin/RelatedObjectLookups.js"></script>

{{ form.media }}

{% endblock %}

Complementing the answer by Carl Meyer, I would like to comment that you need to put that header in some valid block (inside the header) within your template.

{% block extra_head %}

<link rel="stylesheet" type="text/css" href="/media/admin/css/forms.css"/>
<link rel="stylesheet" type="text/css" href="/media/admin/css/base.css"/>
<link rel="stylesheet" type="text/css" href="/media/admin/css/global.css"/>
<link rel="stylesheet" type="text/css" href="/media/admin/css/widgets.css"/>

<script type="text/javascript" src="/admin/jsi18n/"></script>
<script type="text/javascript" src="/media/admin/js/core.js"></script>
<script type="text/javascript" src="/media/admin/js/admin/RelatedObjectLookups.js"></script>

{{ form.media }}

{% endblock %}

回答 7

对于Django> = 2.0

注意:对于日期时间字段使用管理小部件不是一个好主意,因为如果您使用引导程序或任何其他CSS框架,则管理样式表可能会与您的网站样式表发生冲突。如果您要在Bootstrap上构建站点,请使用我的bootstrap-datepicker小部件django-bootstrap-datepicker-plus

步骤1:新增javascript-catalog URL到您的项目(而非应用程序)urls.py文件中。

from django.views.i18n import JavaScriptCatalog

urlpatterns = [
    path('jsi18n', JavaScriptCatalog.as_view(), name='javascript-catalog'),
]

第2步:将所需的JavaScript / CSS资源添加到模板中。

<script type="text/javascript" src="{% url 'javascript-catalog' %}"></script>
<script type="text/javascript" src="{% static '/admin/js/core.js' %}"></script>
<link rel="stylesheet" type="text/css" href="{% static '/admin/css/widgets.css' %}">
<style>.calendar>table>caption{caption-side:unset}</style><!--caption fix for bootstrap4-->
{{ form.media }}        {# Form required JS and CSS #}

步骤3:在中的日期时间输入字段中使用管理小部件forms.py

from django.contrib.admin import widgets
from .models import Product

class ProductCreateForm(forms.ModelForm):
    class Meta:
        model = Product
        fields = ['name', 'publish_date', 'publish_time', 'publish_datetime']
        widgets = {
            'publish_date': widgets.AdminDateWidget,
            'publish_time': widgets.AdminTimeWidget,
            'publish_datetime': widgets.AdminSplitDateTime,
        }

For Django >= 2.0

Note: Using admin widgets for date-time fields is not a good idea as admin style-sheets can conflict with your site style-sheets in case you are using bootstrap or any other CSS frameworks. If you are building your site on bootstrap use my bootstrap-datepicker widget django-bootstrap-datepicker-plus.

Step 1: Add javascript-catalog URL to your project’s (not app’s) urls.py file.

from django.views.i18n import JavaScriptCatalog

urlpatterns = [
    path('jsi18n', JavaScriptCatalog.as_view(), name='javascript-catalog'),
]

Step 2: Add required JavaScript/CSS resources to your template.

<script type="text/javascript" src="{% url 'javascript-catalog' %}"></script>
<script type="text/javascript" src="{% static '/admin/js/core.js' %}"></script>
<link rel="stylesheet" type="text/css" href="{% static '/admin/css/widgets.css' %}">
<style>.calendar>table>caption{caption-side:unset}</style><!--caption fix for bootstrap4-->
{{ form.media }}        {# Form required JS and CSS #}

Step 3: Use admin widgets for date-time input fields in your forms.py.

from django.contrib.admin import widgets
from .models import Product

class ProductCreateForm(forms.ModelForm):
    class Meta:
        model = Product
        fields = ['name', 'publish_date', 'publish_time', 'publish_datetime']
        widgets = {
            'publish_date': widgets.AdminDateWidget,
            'publish_time': widgets.AdminTimeWidget,
            'publish_datetime': widgets.AdminSplitDateTime,
        }

回答 8

如果以上操作失败,以下内容也将作为最后的手段

class PaymentsForm(forms.ModelForm):
    class Meta:
        model = Payments

    def __init__(self, *args, **kwargs):
        super(PaymentsForm, self).__init__(*args, **kwargs)
        self.fields['date'].widget = SelectDateWidget()

和…一样

class PaymentsForm(forms.ModelForm):
    date = forms.DateField(widget=SelectDateWidget())

    class Meta:
        model = Payments

把它放在你的forms.py中 from django.forms.extras.widgets import SelectDateWidget

The below will also work as a last resort if the above failed

class PaymentsForm(forms.ModelForm):
    class Meta:
        model = Payments

    def __init__(self, *args, **kwargs):
        super(PaymentsForm, self).__init__(*args, **kwargs)
        self.fields['date'].widget = SelectDateWidget()

Same as

class PaymentsForm(forms.ModelForm):
    date = forms.DateField(widget=SelectDateWidget())

    class Meta:
        model = Payments

put this in your forms.py from django.forms.extras.widgets import SelectDateWidget


回答 9

仅向您的小部件分配一个类,然后将该类绑定到JQuery datepicker怎么样?

Django Forms.py:

class MyForm(forms.ModelForm):

  class Meta:
    model = MyModel

  def __init__(self, *args, **kwargs):
    super(MyForm, self).__init__(*args, **kwargs)
    self.fields['my_date_field'].widget.attrs['class'] = 'datepicker'

以及模板的一些JavaScript:

  $(".datepicker").datepicker();

What about just assigning a class to your widget and then binding that class to the JQuery datepicker?

Django forms.py:

class MyForm(forms.ModelForm):

  class Meta:
    model = MyModel

  def __init__(self, *args, **kwargs):
    super(MyForm, self).__init__(*args, **kwargs)
    self.fields['my_date_field'].widget.attrs['class'] = 'datepicker'

And some JavaScript for the template:

  $(".datepicker").datepicker();

回答 10

使用required = False更新了SplitDateTime的解决方案和解决方法:

表格

from django import forms

class SplitDateTimeJSField(forms.SplitDateTimeField):
    def __init__(self, *args, **kwargs):
        super(SplitDateTimeJSField, self).__init__(*args, **kwargs)
        self.widget.widgets[0].attrs = {'class': 'vDateField'}
        self.widget.widgets[1].attrs = {'class': 'vTimeField'}  


class AnyFormOrModelForm(forms.Form):
    date = forms.DateField(widget=forms.TextInput(attrs={'class':'vDateField'}))
    time = forms.TimeField(widget=forms.TextInput(attrs={'class':'vTimeField'}))
    timestamp = SplitDateTimeJSField(required=False,)

form.html

<script type="text/javascript" src="/admin/jsi18n/"></script>
<script type="text/javascript" src="/admin_media/js/core.js"></script>
<script type="text/javascript" src="/admin_media/js/calendar.js"></script>
<script type="text/javascript" src="/admin_media/js/admin/DateTimeShortcuts.js"></script>

urls.py

(r'^admin/jsi18n/', 'django.views.i18n.javascript_catalog'),

Updated solution and workaround for SplitDateTime with required=False:

forms.py

from django import forms

class SplitDateTimeJSField(forms.SplitDateTimeField):
    def __init__(self, *args, **kwargs):
        super(SplitDateTimeJSField, self).__init__(*args, **kwargs)
        self.widget.widgets[0].attrs = {'class': 'vDateField'}
        self.widget.widgets[1].attrs = {'class': 'vTimeField'}  


class AnyFormOrModelForm(forms.Form):
    date = forms.DateField(widget=forms.TextInput(attrs={'class':'vDateField'}))
    time = forms.TimeField(widget=forms.TextInput(attrs={'class':'vTimeField'}))
    timestamp = SplitDateTimeJSField(required=False,)

form.html

<script type="text/javascript" src="/admin/jsi18n/"></script>
<script type="text/javascript" src="/admin_media/js/core.js"></script>
<script type="text/javascript" src="/admin_media/js/calendar.js"></script>
<script type="text/javascript" src="/admin_media/js/admin/DateTimeShortcuts.js"></script>

urls.py

(r'^admin/jsi18n/', 'django.views.i18n.javascript_catalog'),

回答 11

我用这个很好,但是模板有两个问题:

  1. 对于模板中的每个字段,我都会两次看到日历图标。
  2. 对于TimeField,我有一个’ 输入有效日期。

models.py

from django.db import models
    name=models.CharField(max_length=100)
    create_date=models.DateField(blank=True)
    start_time=models.TimeField(blank=False)
    end_time=models.TimeField(blank=False)

表格

from django import forms
from .models import Guide
from django.contrib.admin import widgets

class GuideForm(forms.ModelForm):
    start_time = forms.DateField(widget=widgets.AdminTimeWidget)
    end_time = forms.DateField(widget=widgets.AdminTimeWidget)
    create_date = forms.DateField(widget=widgets.AdminDateWidget)
    class Meta:
        model=Guide
        fields=['name','categorie','thumb']

I use this, it’s great, but I have 2 problems with the template:

  1. I see the calendar icons twice for every filed in template.
  2. And for TimeField I have ‘Enter a valid date.

models.py

from django.db import models
    name=models.CharField(max_length=100)
    create_date=models.DateField(blank=True)
    start_time=models.TimeField(blank=False)
    end_time=models.TimeField(blank=False)

forms.py

from django import forms
from .models import Guide
from django.contrib.admin import widgets

class GuideForm(forms.ModelForm):
    start_time = forms.DateField(widget=widgets.AdminTimeWidget)
    end_time = forms.DateField(widget=widgets.AdminTimeWidget)
    create_date = forms.DateField(widget=widgets.AdminDateWidget)
    class Meta:
        model=Guide
        fields=['name','categorie','thumb']

回答 12

在Django 10中,myproject / urls.py:urlpatterns的开头

  from django.views.i18n import JavaScriptCatalog

urlpatterns = [
    url(r'^jsi18n/$', JavaScriptCatalog.as_view(), name='javascript-catalog'),
.
.
.]

在我的template.html中:

{% load staticfiles %}

    <script src="{% static "js/jquery-2.2.3.min.js" %}"></script>
    <script src="{% static "js/bootstrap.min.js" %}"></script>
    {# Loading internazionalization for js #}
    {% load i18n admin_modify %}
    <script type="text/javascript" src="{% url 'javascript-catalog' %}"></script>
    <script type="text/javascript" src="{% static "/admin/js/jquery.init.js" %}"></script>

    <link rel="stylesheet" type="text/css" href="{% static "/admin/css/base.css" %}">
    <link rel="stylesheet" type="text/css" href="{% static "/admin/css/forms.css" %}">
    <link rel="stylesheet" type="text/css" href="{% static "/admin/css/login.css" %}">
    <link rel="stylesheet" type="text/css" href="{% static "/admin/css/widgets.css" %}">



    <script type="text/javascript" src="{% static "/admin/js/core.js" %}"></script>
    <script type="text/javascript" src="{% static "/admin/js/SelectFilter2.js" %}"></script>
    <script type="text/javascript" src="{% static "/admin/js/admin/RelatedObjectLookups.js" %}"></script>
    <script type="text/javascript" src="{% static "/admin/js/actions.js" %}"></script>
    <script type="text/javascript" src="{% static "/admin/js/calendar.js" %}"></script>
    <script type="text/javascript" src="{% static "/admin/js/admin/DateTimeShortcuts.js" %}"></script>

In Django 10. myproject/urls.py: at the beginning of urlpatterns

  from django.views.i18n import JavaScriptCatalog

urlpatterns = [
    url(r'^jsi18n/$', JavaScriptCatalog.as_view(), name='javascript-catalog'),
.
.
.]

In my template.html:

{% load staticfiles %}

    <script src="{% static "js/jquery-2.2.3.min.js" %}"></script>
    <script src="{% static "js/bootstrap.min.js" %}"></script>
    {# Loading internazionalization for js #}
    {% load i18n admin_modify %}
    <script type="text/javascript" src="{% url 'javascript-catalog' %}"></script>
    <script type="text/javascript" src="{% static "/admin/js/jquery.init.js" %}"></script>

    <link rel="stylesheet" type="text/css" href="{% static "/admin/css/base.css" %}">
    <link rel="stylesheet" type="text/css" href="{% static "/admin/css/forms.css" %}">
    <link rel="stylesheet" type="text/css" href="{% static "/admin/css/login.css" %}">
    <link rel="stylesheet" type="text/css" href="{% static "/admin/css/widgets.css" %}">



    <script type="text/javascript" src="{% static "/admin/js/core.js" %}"></script>
    <script type="text/javascript" src="{% static "/admin/js/SelectFilter2.js" %}"></script>
    <script type="text/javascript" src="{% static "/admin/js/admin/RelatedObjectLookups.js" %}"></script>
    <script type="text/javascript" src="{% static "/admin/js/actions.js" %}"></script>
    <script type="text/javascript" src="{% static "/admin/js/calendar.js" %}"></script>
    <script type="text/javascript" src="{% static "/admin/js/admin/DateTimeShortcuts.js" %}"></script>

回答 13

我的Django设置:1.11引导程序:3.3.7

由于没有一个答案是完全清楚的,因此我共享我的模板代码,该代码完全没有错误。

模板的上半部分:

{% extends 'base.html' %}
{% load static %}
{% load i18n %}

{% block head %}
    <title>Add Interview</title>
{% endblock %}

{% block content %}

<script type="text/javascript" src="{% url 'javascript-catalog' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/core.js' %}"></script>
<link rel="stylesheet" type="text/css" href="{% static 'admin/css/forms.css' %}"/>
<link rel="stylesheet" type="text/css" href="{% static 'admin/css/widgets.css' %}"/>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" >
<script type="text/javascript" src="{% static 'js/jquery.js' %}"></script>

下半区:

<script type="text/javascript" src="/admin/jsi18n/"></script>
<script type="text/javascript" src="{% static 'admin/js/vendor/jquery/jquery.min.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/jquery.init.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/actions.min.js' %}"></script>
{% endblock %}

My Django Setup : 1.11 Bootstrap: 3.3.7

Since none of the answers are completely clear, I am sharing my template code which presents no errors at all.

Top Half of template:

{% extends 'base.html' %}
{% load static %}
{% load i18n %}

{% block head %}
    <title>Add Interview</title>
{% endblock %}

{% block content %}

<script type="text/javascript" src="{% url 'javascript-catalog' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/core.js' %}"></script>
<link rel="stylesheet" type="text/css" href="{% static 'admin/css/forms.css' %}"/>
<link rel="stylesheet" type="text/css" href="{% static 'admin/css/widgets.css' %}"/>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" >
<script type="text/javascript" src="{% static 'js/jquery.js' %}"></script>

Bottom Half:

<script type="text/javascript" src="/admin/jsi18n/"></script>
<script type="text/javascript" src="{% static 'admin/js/vendor/jquery/jquery.min.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/jquery.init.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/actions.min.js' %}"></script>
{% endblock %}

回答 14

2020年6月3日(所有答案均无效,您可以尝试使用我使用的此解决方案。仅用于TimeField)

在表单中Charfield为时间字段(在此示例中为开始结束)使用simple 。

表格

我们可以在这里使用FormModelForm

class TimeSlotForm(forms.ModelForm):
    start = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'HH:MM'}))
    end = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'HH:MM'}))

    class Meta:
        model = TimeSlots
        fields = ('start', 'end', 'provider')

将字符串输入转换为视图中的时间对象。

import datetime
def slots():
    if request.method == 'POST':
        form = create_form(request.POST)
        if form.is_valid():                
            slot = form.save(commit=False)
            start = form.cleaned_data['start']
            end = form.cleaned_data['end']
            start = datetime.datetime.strptime(start, '%H:%M').time()
            end = datetime.datetime.strptime(end, '%H:%M').time()
            slot.start = start
            slot.end = end
            slot.save()

June 3, 2020 (All answers didn’t worked, you can try this solution I used. Just for TimeField)

Use simple Charfield for time fields (start and end in this example) in forms.

forms.py

we can use Form or ModelForm here.

class TimeSlotForm(forms.ModelForm):
    start = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'HH:MM'}))
    end = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'HH:MM'}))

    class Meta:
        model = TimeSlots
        fields = ('start', 'end', 'provider')

Convert string input into time object in views.

import datetime
def slots():
    if request.method == 'POST':
        form = create_form(request.POST)
        if form.is_valid():                
            slot = form.save(commit=False)
            start = form.cleaned_data['start']
            end = form.cleaned_data['end']
            start = datetime.datetime.strptime(start, '%H:%M').time()
            end = datetime.datetime.strptime(end, '%H:%M').time()
            slot.start = start
            slot.end = end
            slot.save()