Django常见错误总结:细数我们一起走过的大坑

小编我初学Django的时候跳了不少的坑,曾经一度想放弃。现在想想,幸亏没有哈。坚持学习持续改进才是王道啊,要不然老是中途放弃肯定一事无成。我记忆最为深刻的就是看着官网的入门教程练手,当我在模板里看到for choice in question.choice_set.all时, 心里快崩溃了。Question模型里根本没有choice_set这个字段或方法啊,这是什么鬼。后来得知这是Django进行反向查询的方式。今天小编我来专门总结下Django新手容易犯的常见错误,并教你如何避免choice_set那样的大坑。本文适合初学者,老鸟们请多指教啊。

模型坑

请仔细观察下面Django模型,你能找到几处坑呢? Django项目第一步就是写模型,如果你动笔没写5行就包含了一堆错误,相信你一定会先怀疑自己,然后再怀疑人生。

classPerson(models.Model): name = models.CharField('Name')

classBook(models.Model):

name = models.TextField('Name', blank = True, null = True)

author = models.ForeignKey('Person', related_name='author')

答案是4个错误,你发现了吗? 如果你能找到更多错误,请留言。

Person模型中的CharField没有指定字符串最大长度max_length。CharField和TextField类似,都是字符串,区别在于CharField必需要设置max_length, 而对TextField而言max_length是可选的。这在数据库层面是有用的,设置最大长度可以帮助节省数据库空间。

Book模型中ForeignKey应该是Person,而不是'Person'。加了引号就把Person变成普通的字符串了,变成verbose_name了。

如果你设置了ForeignKey,on_delete删除选项是必需要设置的,比如on_delete=models.CASCADE, on_delete=models.SET_NULL。前者意思是如果一个person删除了,其对应的所有books要删除。后者意思是,如果一个person删除了,其对应的所有books变为NULL。

related_name应该是用来做反向查询的名字,而不是与字段相同的verbose_name。在这里related_name应该改为‘book’或'books'。如果你不设置related_name, 你要从Person反查Book就要使用Person.book_set.filter()或者Person.book_set.all()。如果你设置了related_name, 你就可以使用Person.book了。

当然还有一个最后技术细节也值得关注,那就是Book模型中TextField的blank=True和null=True的区别。其实本例中完全没有必要同时设置blank=True和null=True,原因如下。

blank 是针对表单的,如果 blank=True,表示你的表单填写该字段的时候可以不填,但是对数据库来说,没有任何影响。

null 是针对数据库而言,如果 null=True, 表示数据库的该字段可以为空,即在Null字段显示为yes。

对于CharField和TextField,如果为空字符串或没有字符,数据库里会存储''空字符串,不会以null形式存储,所以设置nul=True没有任何意义。

对于在模型中修改现有字段和新增字段合理地设置blank=True和null=True非常重要,否则当你运行python manage.py makemigrations和python manage.py migrate时, Django会要求你提供默认值,那是相当的烦。

当你编写模型时,请一定了解哪些选项是必需设置的,更多内容见:

视图坑

老实说,视图的坑不多。不过值得注意的是,我们需要了解的是何时使用save_m2m方法只用来存储多对多的关系。当你同时满足下面两个条件时,你必须要使用此方法。如果你直接使用modelform.save()或form_valid()方法,是可以直接存储多对多(m2m)关系的,不需要用save_m2m。

你使用了save(commit=False)方法,添加了额外的自动user

你的model里有多对多的关系(比如tags)

假设我们文章模型里有tags这个多对多的字段,我们还需要在视图里增加一行save_m2m, 否则多对多关系不会被存储。

defarticle_create(request):

ifrequest.method =='POST':

form = ArticleForm(request.POST)

ifform.is_valid():

article = form.save(commit=False)

# commit=False tells Django that "Don't send this to database yet.

article.author = request.user# Set the user object here

article.save()# Now you can send it to DB

form.save_m2m()

returnHttpResponseRedirect("/blog/")

else:

form = ArticleForm()

returnrender(request,'blog/article_create_form.html',{'form': form})

设置文件settings.py坑

在你运行python manage.py migrate前,请一定把它加到settings.py里INSATLLED_APP里去,如下所示,要不然会出现错误。

INSTALLED_APPS = [

'django.contrib.admin',

'django.contrib.auth',

'django.contrib.contenttypes',

'django.contrib.sessions',

'django.contrib.staticfiles',

'django.contrib.sites',

'myapp',

]

如果你要使用到静态文件如css和图片,你还需要在settings.py里设置STATIC_URL和MEDIA,否则静态文件无法正确显示。这样用户上传的图片会放在/media/文件夹里。请注意这个设置是通用的哦,新手直接拿去用吧。:)

STATIC_URL ='/static/'

STATICFILES_DIRS = [os.path.join(BASE_DIR,"static"),]

# specify media root for user uploaded files,

MEDIA_ROOT = os.path.join(BASE_DIR,'media')

MEDIA_URL ='/media/'

同时也别忘了把你app的urls.py加到项目里的urls.py里去。显示图片和静态文件,还需在结尾部分加static配置。

fromdjango.conf.urlsimportpath,include

fromdjango.contribimportadmin

fromdjango.confimportsettings

fromdjango.conf.urls.staticimportstatic

urlpatterns = [

path(r'^myapp/',include('myapp.urls')),

path(r'^admin/',admin.site.urls),

] + static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)

re_path(r'^restaurant/(?P

\d+)/dishes/(?P

\d+)/$',

views.DishDetail.as_view(),name='dish_detail'),

同样当你使用reverse方法对命名url进行反向解析时,请确保你传递的参数数量与你设计的URL中的参数数量是一致的。

表单坑

上传图片和文件时,模板中form一定加enctype="multipart/form-data“属性, 同时视图中别忘了加request.FILES, 如form =UploadForm(request.POST, request.FILES)。

如果你在forms.py里通过clean方法自定义表单验证,那么视图中请用form.cleaned_data.get('field_name')获取验证过的数据,而不是直接使用request.POST['fileld_name']获取表单提取来的数据, 否则表单不会进行验证,那么你的clean方法也白定义了。小编我曾被这个坑怕了。

另外的你的模板里的form加{% csrf %}了吗?

小结坑

小编我专门总结了Django一些常见错误,希望能帮你避免如坑。坑并不可怕,可怕的是被坑怕了! 聪明小心的你还经历过哪些坑,欢迎评论区留言啊。

大江狗

2018.8.17

下篇我打算写利用Django开发智能文档管理系统的教程,欢迎关注。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180817G0PETT00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券