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

版权声明:本文系大江狗原创,请勿直接copy应用于你的出版物或任何公众平台。 https://blog.csdn.net/weixin_42134789/article/details/82184481

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

模型坑

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

class Person(models.Model):
    name = models.CharField('Name')

class Book(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会要求你提供默认值,那是相当的烦。

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

Django基础核心技术之Model模型的介绍与设计

视图坑

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

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

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

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

def article_create(request):
    if request.method == 'POST':
        form = ArticleForm(request.POST)
        if form.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()

            return HttpResponseRedirect("/blog/")
    else:
        form = ArticleForm()
    return render(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配置。

from django.conf.urls import path, include
from django.contrib import admin
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path(r'^myapp/', include('myapp.urls')),
    path(r'^admin/', admin.site.urls),

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

URL坑
假设你的URL里包含有2个参数(如下所示,餐厅id和菜品id),那么当你在模板中使用{% url 'dish_detail' %}获取菜品详情链接时会出现错误,因为你没有向这个命名url传递任何参数,同样仅传递1个参数也是不对的。正确的做法是使用{% url 'dish_detail' restaurant.id  restaurant.dish.id %}。

    re_path(r'^restaurant/(?P<pkr>\d+)/dishes/(?P<pk>\d+)/$',
        views.DishDetail.as_view(), name='dish_detail'),

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

Django基础(10): URL重定向的HttpResponseDirect, redirect和reverse的用法详解

表单坑

上传图片和文件时,模板中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开发智能文档管理系统的教程,欢迎关注。

猜你喜欢

转载自blog.csdn.net/weixin_42134789/article/details/82184481