6

【Django】DRF开发中的一些技巧记录 - 风灵动铭

 1 year ago
source link: https://www.cnblogs.com/Meepoljd/p/16625117.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

问题1:信号没有按预期触发

编写了信号函数后,并没有如预期一般在必要时候触发,函数如下:

@receiver(signals.post_save, sender=Prometheus)
def monitor_prometheus_update(instance, **kwargs):
    # 当发生修改时,更新控制台url
    web_url = "http://{ip}:{port}/{route}".format(ip=instance.ip, port=instance.port, route=instance.url)
    Prometheus.objects.filter(ip=instance.ip).update(web_url=web_url)
    print("触发", web_url, instance)

理论上应该在每次信息修改时触发,print出触发信息,但是并没生效,我是在apps.py中定义ready方法:

from django.apps import AppConfig


class ServicesConfig(AppConfig):
    name = 'apps.services'
    default_auto_field = 'django.db.models.BigAutoField'

    def ready(self):
        import apps.services.signals

问题2:startapp报错包名冲突

使用startapp创建一个新的应用到指定目录时,报错:

CommandError: 'apps' conflicts with the name of an existing Python module and cannot be used as an app directory. Please try another directory.

使用的命令是startapp services .apps

在项目目录下新建apps目录,然后在其中新建空目录services,此时使用命令startapp services ./apps/services就可以在指定的目录下创建新的应用了。

问题3:Get请求获取query_params

编写了Get请求后,需要支持用户在请求时携带部分参数,方便查询

使用rest_framework.request.Request的query_params能够方便拿到请求参数:

class PrometheusList(APIView):

    def get(self,request: Request):
        """
        :param request:
        :return:
        """
        param=request.query_params
        if param and 'group' in param.keys():
				    # 支持通过group来进行查询
            queryset = Prometheus.objects.filter(group=param['group'])
        else:
            queryset = Prometheus.objects.all()

        s = PrometheusSerializer(instance=queryset, many=True)
        return Response(s.data, status = status.HTTP_200_OK)

随后创建三条记录,分组不同,进行测试:

1336471-20220825174331667-1212650589.png

执行GET请求如下:

GET /api/v1/services/prometheus?group=default
HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

[
    {
        "ip": "1.1.1.1",
        "port": 9090,
        "url": "",
        "web_url": "http://1.1.1.1:9090/",
        "group": "default",
        "create_by": "2022-08-23 18:06:19",
        "update_by": "2022-08-23 18:06:19"
    },
    {
        "ip": "1.1.1.2",
        "port": 9090,
        "url": "",
        "web_url": "http://1.1.1.2:9090/",
        "group": "default",
        "create_by": "2022-08-23 18:06:25",
        "update_by": "2022-08-23 18:06:25"
    }
]

问题4:Model字段依赖于其他字段

在我的模型类中,web_url字段需要依赖于ip、port以及url字段生成,格式如下:

web_url = "http://{ip}:{port}/{url}"

原先使用信号机制实现这种,当任意一个字段变化时也会触发web_url变化,但是发现这样实现并不好;

新的实现方法如下,在模型类中实现save方法:


class Prometheus(models.Model):

    STATUS = (
        ("UP", "运行中"),
        ("DOWN", "已停止")
    )

    # Prometheus服务的模型
    ip = models.GenericIPAddressField(protocol="IPV4",help_text="指定了Prometheus服务所在服务器IP", verbose_name="服务IP", blank=False,
                                      primary_key=True)
    port = models.IntegerField(help_text="指定了Prometheus服务的端口号,不正确会导致服务状态获取异常", verbose_name="服务端口",
                               default=9090)
    url = models.CharField(max_length=50, help_text="该值对应了Prometheus的启动参数web.external-url", verbose_name="访问路由",
                           blank=True)
    web_url = models.URLField(help_text="可以通过此URL跳转到Prometheus的Web", verbose_name="控制台", default="")
    group = models.CharField(max_length=50, help_text="用户定义的Prometheus服务所属的组", verbose_name="分组", default="default")
    status = models.CharField(max_length=50,choices=STATUS, help_text="Prometheus节点的状态,已停止时无法进行部分操作",verbose_name="状态", default="DOWN")
    create_by = models.DateTimeField(verbose_name="创建时间", auto_now_add=True)
    update_by = models.DateTimeField(verbose_name="更新时间", auto_now=True)
		

    def save(self, *args, **kwargs):
        """
        重写save方法,自动生成web_url
        :param args:
        :param kwargs:
        :return:
        """
        self.web_url = "http://{ip}:{port}/{route}".format(ip=self.ip, port=self.port, route=self.url)
        super(Prometheus, self).save(*args, **kwargs)

问题5:自定义分页的格式

在通用类视图中,使用默认分页类的默认的返回结构是这样的:

1336471-20220825174301126-517806462.png

字段并不是我要的,所以对其最新一定的自定义;

自定义分页类继承自PageNumberPagination,然后实现get_paginated_response方法,原本的改方法返回的是OrderDict类型的结果,不过我看python3.6以后的dict也是默认有序了,所以我觉得返回dict是没问题的:

from rest_framework.pagination import PageNumberPagination

class ServicePageNumberPagination(PageNumberPagination):
    page_size_query_param = 'page_size'
    page_query_param = "page"
    max_page_size = 100
		
		    def get_paginated_response(self, data):
        return Response(dict([
            ('total', self.page.paginator.count),
            ('results', data),
            ('success', True)
        ]))

这里如果想要在返回的结构中打印出当前的url连接,可以通过get_html_context()方法实现:


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK