返回文章列表文章索引阅读全文
STARBLOG / 阅读手记
Django

Django Project Notes: Session Handling and Complex Object Serialization

Preface: A bit of a digression I've found that when I don't update my blog, it's either because I'm extremely busy or because my efficiency is very low. I haven't updated the blog much recently, and the reason is the second one = =. How embarrassing. Today my efficiency was unusually high. I finished writing all the PassNote backend APIs in a single day. Django is great to use, but in actual projects there are still some features the framework can't implement that need to be solved. I quite like reinventing the wheel, but to keep efficiency up I still try to use existing tools as much as possible and cut down on unnecessary hassle. About PassNote I should have mentioned this on the blog before: this is a password management

曦远 (DealiAxy)约 23 分钟
目录11 个章节

Preface: A Bit of a Digression

I've found that when I don't update my blog, it's either because I'm extremely busy or because my efficiency is very low. I haven't updated the blog much recently, and the reason is the second one = =. How embarrassing. Today my efficiency was unusually high. I finished writing all the PassNote backend APIs in a single day. Django is great to use, but in actual projects there are still some features the framework can't implement that need to be solved. I quite like reinventing the wheel, but to keep efficiency up I still try to use existing tools as much as possible and cut down on unnecessary hassle.

About PassNote

I should have mentioned this on the blog before: this is a password manager for encrypting and storing various website accounts and passwords, and it can also generate high-strength passwords. Project homepage: https://deali-axy.github.io/PassNote/ Check it out. But this is only a desktop app and doesn't have cloud backup, so I've always wanted to find time to develop a cross-platform version. I've been putting it off, and only started writing it today.

Django Session Handling

Simply put, a session means taking the cookie and storing it on the server side, then the client uses the ID returned by the server as the session identifier.

The session framework lets you store and retrieve data about visitors. This information is stored on the server (in the database by default). Cookies are used to send and retrieve a value containing the session ID; cookies are not used to pass the data itself.

Using Sessions in Django

Enabling Sessions

Edit settings.py. Add the following to MIDDLEWARE_CLASSES:

'django.contrib.sessions.middleware.SessionMiddleware',

Add the following to INSTALLED_APPS:

'django.contrib.sessions',

Using Sessions in Views

# 创建或修改 session:
request.session[key] = value
# 获取 session:
request.session.get(key,default=None)
# 删除 session
del request.session[key] # 不存在时报错

For more session usage, see the official docs: https://docs.djangoproject.com/en/2.0/topics/http/sessions/

On Serializing Complex Objects

There are already several solutions for serializing Django data:

django.core.serializers

Django's built-in serializer can serialize Django model querysets but cannot directly serialize a single Django model instance. If your model contains mixed data, this serializer also cannot be used (if you want to use the serialized data directly). Besides that, if you want to return the serialized data directly to the user, it clearly contains a lot of sensitive information as well as information that is useless to the user.

QuerySet.values()

Same as above, QuerySet.values() also won't work if your model has a DateTimeField or other special Fields, as well as extra data.

django-rest-framework serializers

django-rest-framework is a powerful framework that can help you quickly build REST APIs. It has a complete serializer, but before using it you need to spend some time getting started and learning the cbv development style. For projects with time constraints, this is clearly not the best solution.

Simply put, the several ready-made solutions in Django are either not powerful enough or have a high learning cost. Just as I was about to reinvent the wheel myself, I found a convenient solution, so to save time I immediately abandoned my plan of reinventing the wheel.

Project address: https://github.com/bluedazzle/django-simple-serializer Check it out.

But when actually using it there was another problem: when serializing a QuerySet, if it contains an AutoField it throws an error: 'AutoField' object has no attribute 'rel' That's a bit of a trap. I finally found a useful tool so I wouldn't have to reinvent the wheel, only to suddenly discover this tool has a problem—and I have to fill in the hole for it??

Well, no choice, I had to step in. Since the code has no comments, and I didn't have that much time to figure out exactly where the problem was, I just fixed whatever was throwing errors. I also just filed an issue for the author on GitHub.

I modified the data_inspect function in the Serializer file. The code is as follows; I added a check for the rel attribute.

def data_inspect(self, data, extra=None):
        if isinstance(data, (QuerySet, Page, list)):
            convert_data = []
            if extra:
                for i, obj in enumerate(data):
                    convert_data.append(self.data_inspect(obj, extra.get(
                        **{self.through_fields[0]: obj, self.through_fields[1]: self.source_field})))
            else:
                for obj in data:
                    convert_data.append(self.data_inspect(obj))
            return convert_data
        elif isinstance(data, models.Model):
            obj_dict = {}
            concrete_model = data._meta.concrete_model
            for field in concrete_model._meta.local_fields:
                # 检查 field 是否存在 rel 这个属性,为'AutoField' object has no attribute 'rel'错误填坑
                if hasattr(field, 'rel'):
                    if field.rel is None:
                        if self.check_attr(field.name) and hasattr(data, field.name):
                            obj_dict[field.name] = self.data_inspect(getattr(data, field.name))
                    else:
                        if self.check_attr(field.name) and self.foreign:
                            obj_dict[field.name] = self.data_inspect(getattr(data, field.name))
                else:
                    if self.check_attr(field.name) and hasattr(data, field.name):
                        obj_dict[field.name] = self.data_inspect(getattr(data, field.name))
            for field in concrete_model._meta.many_to_many:
                if self.check_attr(field.name) and self.many:
                    obj_dict[field.name] = self.data_inspect(getattr(data, field.name))
            for k, v in data.__dict__.items():
                if not str(k).startswith('_') and k not in obj_dict.keys() and self.check_attr(k):
                    obj_dict[k] = self.data_inspect(v)
            if extra:
                for field in extra._meta.concrete_model._meta.local_fields:
                    if field.name not in obj_dict.keys() and field.name not in self.through_fields:
                        if field.rel is None:
                            if self.check_attr(field.name) and hasattr(extra, field.name):
                                obj_dict[field.name] = self.data_inspect(getattr(extra, field.name))
                        else:
                            if self.check_attr(field.name) and self.foreign:
                                obj_dict[field.name] = self.data_inspect(getattr(extra, field.name))
            return obj_dict
        elif isinstance(data, manager.Manager):
            through_list = data.through._meta.concrete_model._meta.local_fields
            through_data = data.through._default_manager
            self.through_fields = [data.target_field.name, data.source_field.name]
            self.source_field = data.instance
            if len(through_list) > 3 and self.through:
                return self.data_inspect(data.all(), through_data)
            else:
                return self.data_inspect(data.all())
        elif isinstance(data, (datetime.datetime, datetime.date, datetime.time)):
            return self.time_func(data)
        elif isinstance(data, (ImageFieldFile, FileField)):
            return data.url if data.url else data.path
        elif isinstance(data, Decimal):
            return float(data)
        elif isinstance(data, dict):
            obj_dict = {}
            if self._dict_check:
                for k, v in data.items():
                    obj_dict[k] = self.data_inspect(v)
            else:
                for k, v in data.items():
                    if self.check_attr(k):
                        obj_dict[k] = self.data_inspect(v)
            return obj_dict
        elif isinstance(data, (str, bool, float, int)):
            return data
        else:
            return None

I tested it and it works normally, so I'll leave it like this for now, even though it feels a bit like "hack programming", hhh

End

That's all for these project notes. The new version of PassNote, like before, will be fully open-sourced after development is complete. This time I'm planning to make it cross-platform across mobile, desktop, and mini programs. Friends who are interested, feel free to follow along~

As is international custom, here's a screenshot.

_EOF_

Django Project Notes: Session Handling and Complex Object Serialization

本文作者:
程序设计实验室
版权声明:
本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

相关文章

Django数据库性能优化之使用Python集合操作

前言 最近有个新需求: 人员基础信息(记作人员A),10w 某种类型的人员信息(记作人员B),1000 要求在后台上(Django Admin)分别展示:已录入A的人员B列表、未录入的人员B列表 团队的DBA提议使用视图可以解决这个问题(不愧是搞数据库的) PS:起先我觉得Django的Model是直接管理数据库表的,使用Model来映射数据库模型怕是有一定的麻烦,不过查了一下资料发现并不会~ 只

2022-08-26 · Django · 约 1 分钟

聊聊Django应用的部署和性能的那些事儿

前言 随着工作的深入,我越来越发现Python Web开发中有很多坑,也一直在羡慕AspNetCore和Go等的可执行文件部署和高性能,以及Spring生态的丰富,不过因为工作用了Django,生活还是要继续的嘛,这Django好歹也是有很大份额的Web框架,也没那么不堪,至少开发速度上就吊打一众框架了~ 在之前的文章里我介绍过使用Docker部署Django应用的方法,不过那种部署方式只适合上线

2022-05-27 · Django · 约 1 分钟

Django的信号机制入门

概念 django自带一套信号机制来帮助我们在框架的不同位置之间传递信息。也就是说,当某一事件发生时,信号系统可以允许一个或多个发送者(senders)将通知或信号(signals)发送给一组接受者(receivers)。 (感觉就很像Qt的信号与槽机制) 信号系统包含以下三要素: 发送者-信号的发出方 信号-信号本身 接收者-信号的接受者 Django内置了一整套信号,下面是一些比较常用的: 在

2022-08-26 · Django · 约 1 分钟

讨论

共 0 条

良言一句三冬暖,恶语伤人六月寒。

加载评论中…