使用Get
请求 完成其他作用(非查询)
Problem
# 删除
def remove_comment(request, comment_pk):
Comment.objects.filter(
comment_id=comment_pk
).delete()
# …
这样做违反了 HTTP
标准
GET
和 HEAD
方法不应该具有采取除检索
以外的动作的意义。
这些方法应该被认为是“安全的”
互联网上的其他参与者认为 GET 请求是安全的。
例如,如果您使用额外的 GET 请求刷新浏览器,浏览器不会发出警告,
而大多数浏览器会为 POST 请求执行此操作
Solution
应该使用 POST、PUT、PATCH 或 DELETE
请求来更新实体
在 Django 中使用 @require_http_methods 装饰器 确保实例的请求方法
from django.views.decorators.http import require_POST
@require_POST
def remove_comment(request, comment_pk):
Comment.objects.filter(
comment_id=comment_pk
).delete()
# …
数据表模型 使用 Model
后缀
Problem
from django.db import models
class CarModel(models.Model):
# …
pass
除非指定数据表的verbose_name
和 verbose_name_plural
否则Django 也会根据类名构造verbose name
>>> CarModel._meta.verbose_name
'car model'
>>> CarModel._meta.verbose_name_plural
'car models'
Solution
Django 模型不应该有 ...Model 后缀
from django.db import models
class Car(models.Model):
# …
pass
Signal信号使用不当
Django 有一个复杂的信号系统
,可以在您保存、删除、更改多对多关系等时触发某些逻辑。
人们经常使用这些信号,对于某些边缘情况,这些确实是唯一有效的解决方案,但也有只有少数情况下使用信号是合适的
Problem
-
信号的主要问题之一是
信号并不总是运行
批量保存或更新对象时,pre_save 和 post_save 信号不会运行
人们通常假设信号会在这种情况下运行
例如对信号执行计算:他们根据更新的值重新计算某个字段。 由于可以在不触发相应信号的情况下更新字段,因此这会导致不一致的值。 因此,信号给人一种错误的安全感,即处理程序确实会相应地更新对象
# 批量保存
Post.objects.bulk_create([
Post(title='foo'),
Post(title='bar'),
Post(title='qux')
])
# 更新
Post.objects.all().update(views=0)
- 信号可以引发异常并破坏代码流
如果信号运行,例如当我们在模型对象上调用 .save()
时,那么触发器将运行。
信号不是异步运行
的,而是以同步方式运行
的:有一个函数列表,这些函数都会运行。
信号可能会引发错误,从而导致触发视图的函数引发该错误。最终 .save()
调用将引发错误。
如果同一个信号有多个处理程序,那么某些处理程序可能已经进行了更改,而其他处理程序可能没有被调用。
因此,修复对象变得更加复杂,因为处理程序可能已经部分更改了对象
-
信号会导致无限递归(有外键关联的数据)
Especially if we use signals on two models that are related to each other.
from django.db import models
from django.db.models.signals import pre_delete
from django.dispatch import receiver
class Profile(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE
)
# …
@receiver(pre_delete, sender=Profile)
def delete_profile(sender, instance, using):
instance.user.delete()
# remove a Profile --> trigger the signal -> remove a User -->(Django Django will look what to do when removing the user) remove the Profile --> trigger the signal
Solution
通常最好避免使用信号
。人们可以在没有信号的情况下实现很多逻辑
使用异步任务队列
去完成使用信号完成的任务