当你开始学习并使用 Django 后,请勿吝啬分享让你兴奋的东西(错误)。我们将尝试改进 Django 的错误处理,以在将来捕获此类错误。

常见错误一:POST 提交数据到视图而丢失 POST 数据

现象

你有一个需要提交数据到某个视图的表单,然而视图并没有获取到 POST 提交的表单数据。

可能的原因

你可能在表单的 action 中忘了最后的 /. 如果是这样的话,CommonMiddleware(查看你的 MIDDLEWARE_CLASSES) 会重定向至视图的确切名称 —— 并且总会有带上一个 /. 因为它是通过标准 HTTP 的 Location 头来实现重定向的,所以它无法传递 POST 数据,这就是为什么它会丢失数据的原因。

解决方法

始终确保表单 action/ 结尾,如下所示:

1
2
3
4
<form action="/registration/login/" method="POST">
<input name="username">
<input name="password" type="password">
</form>

注:Django 现在正尝试捕获这个问题,见 [3109]

常见错误二:表单无法上传文件

现象

在你的表单中有 FileField()ImageField() ,但是当你提交表单后,并没有上传文件。

可能的原因

当你实例化 Form 时,你可能忘记了 request.FILES 参数。

解决方法

确保实例化 Form 时传递 requests.FILES.

1
form = MyForm(request.POST, request.FILES)

另一种可能

表单中可能缺少 enctype 属性。

解决方法

确保你的表单中有如下形式的 enctype 属性:

1
<form method="post" action="/some/url/" enctype="multipart/form-data">

常见错误三:URLconf include() 失效

现象

你的 URLconf 文件无法正常工作,但也收不到任何关于找不到模块 index 的信息(index 是你尝试分配为视图的某些功能) 或者 模块 foo 缺失 urlpattern 属性的信息。

可能的原因

你可能在 URLconf 文件中用 include() 方法尝试加载视图文件 ( 在教程 3 中,是 myproject/settings/urls/main.py )。这里的 include() 调用是假设加载的也是一个 URLconf 文件

解决方法

移除 include() 方法。就用模块名和函数名(例如:myproject.apps.polls.views.polls.index) 组成字符串即可,不需要 include() 方法去包含它。

常见错误四:空白对象名

现象

The automatic admin interface is showing nothing (or a single &nbsp;) in the “Select [object_type] to change” view.

可能的原因

You may have forgotten to create a __str__() function for your model (__unicode__() in Python 2). Django calls __str__() to find out how to display objects in the admin interface. An alternate cause is the string you return from __str__() includes brackets (an therefore looks like an html tag), and is cleaned up by the strip_tags template filter, resulting in blank entries.

解决方法

Add a correct __str__() function (without brackets in the output) to all your models. Make it a habit so it becomes automatic.

常见错误五:整数和空值

问题

你有如下字段:

1
current_zip = meta.IntegerField(max_length=5, blank=True)

Django 会在你的数据库中创建一个非空的字段。然而,当你表单留空(在管理后台或者是网页上)时,Django 会尝试向你数据库插入 NULL 的空值。

解决方法

加上 null=True :

1
current_zip = meta.IntegerField(max_length=5, null=True, blank=True)

常见错误六:日期和空值

问题与解决方法同 “常见错误五:整数和空值”。

常见错误七:无法往 session 中添加列表

问题

session 中有一个列表,但是无法向该列表中添加数据。

解决方法

将列表拷贝出来,然后添加数据,再拷贝回去:

1
2
3
sessionlist = request.session['my_list']
sessionlist.append(new_object)
request.session['my_list'] = sessionlist

或者,将 session 标记为已修改:

1
2
request.session['my_list'].append(new_object)
request.session.modified = True

常见错误八:关于带有一个字符名称的未定义属性的错误

问题

You get an AttributeError with some weird attribute name that’s only one char long. You don’t have that attribute name anywhere in your code.

解决方法

Search your model and code for situations where you have to pass a tuple of values and want to pass a tuple with one element - and that element is a string like in this sample:

1
2
3
4
5
6
class META:     
...
admin = meta.Admin(
list_display = ('total_price'),
...
)

You are just missing a comma in the list_display assignment like this:

1
2
3
4
5
6
class META:     
...
admin = meta.Admin(
list_display = ('total_price',),
...
)

Remember, in python:

1
2
3
4
5
6
7
8
>>> a = (1) ## This causes problems
1
>>> a = (1,) ## These are fine.
(1,)
>>> a = [1]
[1]
>>> a = [1,]
[1]

Since a tuple is expected but a string provided, the code will merrily iterate over the characters of the string instead of the tuple elements - and that’s where the single-char attribute names come from. If the commas are consistently causing you problems, try using brackets [] instead of parentheses.

常见错误九:使用 formfields.FormWrapper 但表单字段均不显示

问题

You are using code similar to that documented here, but when you put , you get nothing.

解决方法

Make sure when you create your form object, you are passing in empty dictionaries, not tuples. For example:

1
2
manip = things.AddManipulator()
form = formfields.FormWrapper(manip, {}, {})

Not:

1
2
manip = things.AddManipulator()
form = formfields.FormWrapper(manip, (), ())

If you pass in empty tuples for data & errors, it will silently fail to insert your form fields.

常见错误十:使用 SQLite3 时,Django 提示 “Unable to Open Database File”

问题

You’re using SQLite3, your DATABASE_NAME is set to the database file’s full path, the database file is writeable by Apache, but you still get the above error.

解决方法

Make sure Apache can also write to the parent directory of the database. SQLite needs to be able to write to this directory. Avoid setting the permissions to 777, as it’s a security risk (see this page for an explanation why).

Make sure each folder of your database file’s full path does not start with number, eg. /www/4myweb/db (observed on Windows 2000).

If DATABASE_NAME is set to something like ‘/Users/yourname/Sites/mydjangoproject/db/db’, make sure you’ve created the ‘db’ directory first.

Make sure your /tmp directory is world-writable (an unlikely cause as other thing on your system will also not work). ls /tmp -ald should produce drwxrwxrwt ....

Make sure the path to the database specified in settings.py is a full path.

If you working on windows make also sure that you have the path to the db directory written with double backlashes (using os.path methods are recommended)

1
'C:\\django\\sqlite\\django.db'

or

1
r'C:\django\sqlite\django.db'

Make sure there is no special charcaters in the path like “éè” or “(“.

If you are using Windows and this message appears intermittently make sure that your security software (Anti-malware) are not opening (and locking) your database file to check for malware presence.

常见错误十一:如何将 Apache 指向媒体文件目录

问题

You have no clue how to map a media url to your media directory when using apache2.

解决方法

Use the Alias Directive and don’t forget to set-up access rights correctly.

1
2
3
4
5
Alias /mediaurl /path/to/files
<Directory /path/to/files>
Order allow,deny
Allow from all
</Directory>

常见错误十二:数据库查询结果并不是列表

问题

You have been playing with the database API and noticed that a returned query set looks a lot like a list:

1
2
3
>>> from mysite.polls.models import Poll,Choice
>>> Poll.objects.all()
[<Poll: What is up?>, <Poll: What is your favourite colour?>] ## looks a lot like a list to me

But, it doesn’t behave like a list in some cases.

解决方法

Here are a couple of cases where the behaviour is not list-like and their solution.

In Python this is how we can test for an empty list:

1
2
3
>>> b=[]
>>> b==[]
True

This doesn’t work with a QuerySet. You might try the following but it will fail:

1
2
3
4
5
6
>>> from mysite.polls.models import Poll,Choice
>>> p = Poll.objects.filter(question__startswith='ZZZZZZZZZZZZ')
>>> p
[]
>>> p==[]
False

The way to do it is test for p.exists:

1
2
3
4
5
6
>>> from mysite.polls.models import Poll,Choice
>>> p = Poll.objects.filter(question__startswith='ZZZZZZZZZZZZ')
>>> p
[]
>>> p.exists()
False

Another case occurs when you want to retrieve the last member of a QuerySet:

1
2
3
4
5
6
7
8
9
10
11
>>> from mysite.polls.models import Poll,Choice
>>> p = Poll.objects.all()
>>> p
[<Poll: What is up?>, <Poll: What is your favourite colour?>]
>>> p[-1]
Traceback (most recent call last):
File "<console>", line 1, in ?
File "c:\python24\lib\site-packages\django-0.95-py2.4.egg\django\db\models\query.py", line 98, in
__getitem__
assert (not isinstance(k, slice) and (k >= 0)) \
AssertionError: Negative indexing is not supported.

The way I get the last member is either:

1
2
>>> p[p.count()-1]
<Poll: What is your favourite colour?>

or

1
2
>>> p.last()
<Poll: What is your favourite colour?>

常见错误十三:在应用程序中使用保留名称会破坏管理

现象

After creating a new application, with a model that validates, trying to log on to the admin causes an error similar to:

1
ImproperlyConfigured: Error importing middleware django.middleware.common: "No module named ... "

可能的原因

Check to see that you didn’t use a reserved name in naming your application, i.e. “email”, “date” and “time” are common application names that would validate when the server starts but will break Django’s admin.

解决方法

Rename your application directory using a non-reserved name, i.e., “email_app” instead of “email”. Go into the INSTALLED_APPS section of settings.py and change the name there too. Also, don’t forget to migrate your database (python manage.py migrate) to create the newly renamed app in your database. You may also want to go in to your database and drop the old “mis-named” table.

常见错误十四:未绑定方法 contribute_to_class()

现象

模型不可用,报错信息如下:

1
2
3
4
Validating models...
project.allication: Error when calling the metaclass bases
unbound method contribute_to_class() must be called with TextField instance as first argument (got ModelBase instance instead)
1 error found.

可能的原因

未正确声明模型字段,缺少字段类型名称后的括号:

错误写法:

1
2
class Content(models.Model):
content = models.TextField

正确写法:

1
2
class Content(models.Model):
content = models.TextField()

解决方法

模型字段是特定 Field 类的实例,所以是需要括号的。

常见错误十五:使用静态服务时权限被拒绝

可能的原因

The ADMIN_MEDIA_PREFIX is the same as MEDIA_URL in settings.py

解决方法

Ensure they have different values - e.g. ADMIN_MEDIA_PREFIX = ‘admin-media’ and MEDIA_URL = ‘/media’

常见错误十六:默认值和调用

现象

You call a method to set a default value, such as random.randint(), but the value is the same for every new instance of your object.

可能的原因

每一个新的实例并没有调用 random.randint()

解决方法

使用 “lambda:” ,如:

1
MyRandNum = models.CharField(max_length=4, default=lambda:random.randint(1000,9999))

常见错误十七:页面无法找到

Using the URLconf defined in wikicamp.urls, Django tried these URL patterns, in this order:

1
2
3
^wikicamp/(?P<page_name>[^/+])/edit/$
^wikicamp/(?P<page_name>[^/+])/save/$
^wikicamp/(?P<page_name>[^/+])/$

The current URL, , didn’t match any of these.

常见错误十八:空表单

Be it a normal form , model form or class-based-view The page display a blank (empty) page

问题

One possible reason might be you forgot to add {% block content %} {% endblock %} in your template file

解决方法

Make sure that template used to display the page actually contains the tags {% block content %} {% endblock %} wrapping your form definition in the template file.

常见错误十九:SECRET_KEY 不可为空

现象

You’re attempting to run the Django shell from your terminal (ie. python manage.py shell), for either the first time or after rebooting your system. Instead of a Django shell opening, you are presented with the following error.

1
django.core.exceptions.ImproperlyConfigured: The SECRET_KEY setting must not be empty.

可能的原因

A DJANGO_SETTINGS_MODULE has not been specified as an environment variable and therefore no settings file could be loaded as the shell attempts to open.

解决方法

Add a DJANGO_SETTINGS_MODULE environment variable with the appropriate python module in your shell.

1
export DJANGO_SETTINGS_MODULE=<projectname>.settings

原文:https://code.djangoproject.com/wiki/NewbieMistakes