Django中signals和serializers应用
最近工作中出现了一个问题, models需要等一个进程结束后更新,但我不知道进程什么时候结束。
简单来说就是我是监考老师,我得在学生答完题后收卷,但我不知道学生什么时候答完,当我问同事的时候他告诉我这个????
signals应用(仅限入门,记录我的问题)
百度了一下,signal
(信号)类似于前端的一些周期函数,可以在models save,delete,包括请求发生前后调用自己定义的方法,可以很好的解决我的问题
首先,在你需要发送信号的app下创建signals.py
,apps.py
, __init__.py
文件
开始写逻辑
# signals.py
from django.dispatch import receiver
from django.db.models.signals import post_save
from .models import Submit
@receiver(post_save, sender=Submit, dispatch_uid="subject_post_save")
def sub_result_changed(sender, instance, **kwargs):
print("signals正常")
sub = Submit.objects.get(pk=instance.id)
print(sub.id)
调用receiver装饰器
post_save
是models.save发生后调用
上面一段代码完成了在Submit这个model更新之后返回它的id
在app.py文件写配置引用signal
# app.py
from django.apps import AppConfig
class QuestionBankConfig(AppConfig):
name = 'question_bank'
verbose_name = '题库'
# 在ready方法中引用
def ready(self):
import question_bank.signals
__init__.py
文件中再声明配置
# __init__.py
default_app_config = 'question_bank.apps.QuestionBankConfig'
分三步且放在三个文件是为了模块化划分,每个文件各司其职降低各模块耦合度,易于维护
serializers序列化进阶
serializer,在view中调用写好的serializer类,将models字段序列化输出。
在flask中,开发API不需要serializer,只需从db中取出数据,按你想输出的格式将数据dumps就可以完成一个API
django的serializer看似冗余,不过这种先做模板,再走流程的开发方式在大型项目中显得很吃香。
问题场景: 小说网站,首页有很多书,当你登录后,会显示你读过的书的进度
分析:
- 不能修改书的model
- 需判断用户是否登录, 登录:显示当前进度
- 需建立user-book关联表
# models.py
# 章节
class Chapter(models.Model):
_id = models.IntegerField(verbose_name="编号")
title = models.CharField()
problem = models.ManyToManyField(Problem)
pass_rate = models.IntegerField(verbose_name="通关率")
# 书籍
class Book(models.Model):
title = models.CharField()
desc = models.TextField()
chapter = models.ManyToManyField(Chapter,verbose_name="章节")
speed = models.IntegerField(verbose_name="进度", default=0)
# 关联
class UserBook(models.Model):
user = models.ForeignKey(User)
book = models.ForeignKey(Book)
book_speed = models.IntegerField(verbose_name="进度", default=0)
当然也可以book字段manyTomany,或者json字段存储状态
# views.py
from .models import Book
from .serializers import BookSerializer
class BookAPI(APIView):
def get(self, request):
id = request.GET.get("id")
user = request.user
# 判断用户登录
if user.is_authenticated():
user = user
else:
user = None
if not id:
return self.error("id参数必填")
try:
Book = Book.objects.filter()
except Book.DoesNotExist:
return self.error("Book不存在")
data = BookSerializer(Book, context={"user": user}, many=True).data
return self.success(data)
序列化文件
# serializers.py
from .models import Book, Chapter, UserBook
class ChapterSerializer(serializers.ModelSerializer):
class Meta:
model = Chapter
fields = "__all__"
class BookSerializer(serializers.ModelSerializer):
chapter = ChapterSerializer(many=True)
speed = serializers.SerializerMethodField()
def get_speed(self, obj):
# 这里的self.context是我传进来的
user = self.context["user"]
user_book = UserBook.objects.filter(user=user, book=obj)
if user and user_book:
speed = user_book.speed
else:
return speed
class Meta:
model = Book
fields = "__all__"
关键在于 speed字段通过serializers.SerializerMethodField()
自定义序列化方法,
get_字段名
会自己自动调用该方法返回给字段
判断用户登录,并阅读过这本书, 则返回保存的进度