Django中signals和serializers应用

最近工作中出现了一个问题, models需要等一个进程结束后更新,但我不知道进程什么时候结束。

简单来说就是我是监考老师,我得在学生答完题后收卷,但我不知道学生什么时候答完,当我问同事的时候他告诉我这个????

Django中signals和serializers应用

signals应用(仅限入门,记录我的问题)

    百度了一下,signal(信号)类似于前端的一些周期函数,可以在models save,delete,包括请求发生前后调用自己定义的方法,可以很好的解决我的问题

首先,在你需要发送信号的app下创建signals.py,apps.py, __init__.py文件

Django中signals和serializers应用

开始写逻辑

# 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_字段名会自己自动调用该方法返回给字段

判断用户登录,并阅读过这本书, 则返回保存的进度