首页 > 编程问答 >Python - Django - MySQL #need to add distinct() after select_related().distinct() in views.py

Python - Django - MySQL #need to add distinct() after select_related().distinct() in views.py

时间:2024-06-06 12:22:26浏览次数:15  
标签:python mysql django distinct django-select-related

所以这是 ads/views.py 还有 ads/models.py、ads/forms、ads/urls.py 和其他文件,但评分器抱怨的是这个 views.py...

检索到 3806 个 HTML 字符 测试已完成:在页面顶部发现菜单栏 搜索 "HHGTTG_42 1717639962 "时发现多个广告。 您可能需要在 views.py 中的 select_related().distinct() 后添加 distinct() ...

因此,我尝试使用 select_related().distinct(),并在其后添加它,但没有奏效:(

)

views.py 部分导致的问题:

class AdListView(ListView):
    model = Ad # 指定你正在使用的模型
    template_name = "ads/ad_list.html";

    def get(self, request):
        strval = request.GET.get("search", False)
        if strval:
            query = Q(title__icontains=strval) | Q(text__icontains=strval) | Q(tags__name__in=[strval])
            #query.add(Q(text__icontains=strval), Q.OR)
            #query.add(Q(tags__name__in=[strval]), Q.OR)

            ad_list = Ad.objects.filter(query).order_by('-updated_at').distinct()
        否则
            ad_list = Ad.objects.all().order_by('-updated_at')

        # 明确应用 distinct()
        # ad_list = ad_list.distinct()

        for obj in ad_list:
            obj.natural_updated = naturaltime(obj.updated_at)

        if request.user.is_authenticated:
            favorites = list(request.user.favorite_ads.values_list('id', flat=True))
        否则
            favorites = []

        ctx = {'ad_list': ad_list, 'favorites': favorites, 'search': strval}
        return render(request, self.template_name, ctx)

models.py

models.py

 from django.db import models
from django.conf import settings
from django.core.validators import MinLengthValidator
from taggit.managers import TaggableManager

类 Ad(models.Model):
    title = models.CharField(
        max_length=200、
        validators=[MinLengthValidator(2, "标题必须大于 2 个字符")] )
    )
    price = models.DecimalField( max_digits=7, decimal_places=2, null=True)
    text = models.TextField()
    标签 = TaggableManager(blank=True)
    owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='tagme_owner')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    图片 = models.BinaryField(null=True, blank=True, editable=True)
    content_type = models.CharField(max_length=256, null=True, blank=True, help_text='The MIMEType of the file')
    comments = models.ManyToManyField(settings.AUTH_USER_MODEL, through='Comment', related_name='tagme_comments')
    favorites = models.ManyToManyField(settings.AUTH_USER_MODEL, through='Fav', related_name='favorite_ads')

    def __str__(self):
        return self.title

类 Comment(models.Model):
    text = models.TextField(
        validators=[MinLengthValidator(3, "注释必须大于 3 个字符")] )
    )
    ad = models.ForeignKey(Ad, on_delete=models.CASCADE)
    owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.text[:20] + ("..." if len(self.text) > 20 else "")

类 Fav(models.Model):
    ad = models.ForeignKey(Ad, on_delete=models.CASCADE)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

    def __str__(self):
        return self.user.username + " likes " + self.ad.title

forms.py

 from django import forms
from ads.models import Ad, Comment
from django.core.files.uploadedfile import InMemoryUploadedFile
from ads.humanize import naturalsize
from taggit.forms import TagWidget

类 CreateForm(forms.ModelForm):
    max_upload_limit = 2 * 1024 * 1024
    max_upload_limit_text = naturalsize(max_upload_limit)

    picture = forms.FileField(required=False, label='要上传的文件 <= '+max_upload_limit_text)
    upload_field_name = '图片

    类 元
        model = Ad
        fields = ['title', 'price', 'text', 'tags', 'picture'] 字段
        小部件 = {
            标签TagWidget()、
        }

    def clean(self):
        cleaned_data = super().clean()
        pic = cleaned_data.get('picture')
        if pic and isinstance(pic, InMemoryUploadedFile):
            if pic.size > self.max_upload_limit:
                self.add_error('picture', "File must be < " + self.max_upload_limit_text + " bytes")
        返回 cleaned_data

    def save(self, commit=True):
        instance = super(CreateForm, self).save(commit=False)
        f = instance.picture
        if isinstance(f, InMemoryUploadedFile):
            bytearr = f.read()
            instance.content_type = f.content_type
            实例.图片 = bytearr
        如果提交
            instance.save()
            self.save_m2m() # 保存多对多字段,如标签
        返回实例

class CommentForm(forms.ModelForm):
    类 Meta:
        model = Comment
        fields = ['text]


问题出在对 Django ORM 中 distinct() 的使用上。 尽管错误消息建议在 select_related().distinct() 之后添加 distinct() ,但这实际上不是正确的解决方案,而且 select_related().distinct() 本身就是不正确的。

正在基于与 tags__name 字段相关的查询来获取重复的广告。 这就是 distinct() 看起来无效的原因 - 它正在工作,但它正在返回基于数据库中唯一行的不同 组合 ,这些组合仍然包含重复的广告。

可以通过以下两种方法之一解决此问题:

1. 使用 set 在 Python 中移除重复项:

这是在检索查询集后移除重复项的最简单方法。 可以在的视图中修改 AdListView get() 方法,如下所示:

```python class AdListView(ListView): model = Ad template_name = "ads/ad_list.html"

   def get(self, request):
       # ...(的其他代码)...

       if strval:
           # ...(的查询代码)...

           # 使用 set 从查询集中移除重复的广告
           ad_list = list(set(Ad.objects.filter(query).order_by('-updated_at')))
       else:
           # ...(的其他代码)...

       # ...(的其他代码)...

```

此代码首先像以前一样运行的查询。 然后,它使用 set(ad_list) 创建一个唯一的 Ad 对象集。 最后,它使用 list() 将集合转换回列表。 这会保留原始查询的顺序。

2. 使用 Subquery 优化的数据库查询:

对于更大的数据集,更有效的解决方案是在数据库级别防止重复项。 可以使用 Django 的 Subquery 表达式来实现此目的。 这会告诉数据库仅选择具有不同 id 的广告:

```python from django.db.models import OuterRef, Subquery

class AdListView(ListView): # ...(的其他代码)...

   def get(self, request):
       # ...

       if strval:
           query = Q(title__icontains=strval) | Q(text__icontains=strval) | Q(tags__name__in=[strval])
           ad_list = Ad.objects.filter(query).annotate(
               newest=Subquery(
                   Ad.objects.filter(id=OuterRef('id')).order_by('-updated_at').values('updated_at')[:1]
               )
           ).order_by('-newest').distinct()

       # ...(的其他代码)...

```

此代码在数据库级别创建了一个对 Ad 的子查询,获取每个广告的最新 updated_at ,并将结果注释回主查询集。 然后,它使用注释的 newest 字段进行排序和区分,从而确保仅检索唯一的广告。

注意: 此方法假设 Ad 模型具有 id 作为主键。

选择哪种解决方案取决于的应用程序的具体需求和数据集的大小。 如果的数据集很小,则在 Python 中移除重复项可能更容易。 但是,对于更大的数据集,优化数据库查询将更有效率。

标签:python,mysql,django,distinct,django-select-related
From: 78584218

相关文章

  • python基本语法元素
    1.输入与输出实现人机交互。输出:使用print()函数print("Hello,World!")#简单文本输出,输入:使用input()函数,用户输入默认被视为字符串name=input("请输入你的名字:")print("你好,"+name)2.注释单行注释:使用#符号#这是一个单行注释多行注释:使用三个单引号......
  • Python实现【监控远程仓库代码提交,如果有提交就自动执行需要监控测试的接口,以确保新提
    一、代码如下importgitfromdel_folderimportdel_folderimporttimefromsend_Dmessageimportsend_messagefromsend_giftimportsend_gift#设置远程仓库路径remote_url='xxx'#本地仓库路径local_path='xxx'#webhook地址和密钥webhook_url="x......
  • clickhouse 同步mysql数据
    1、mysql端1.1、配置mysql启动二进制复制vim/etc/my.conf在[mysqld]下添加[mysqld]server-id=1log-bin=mysql-binbinlog_format=ROWgtid_mode=ONenforce_gtid_consistency=ONdefault_authentication_plugin=mysql_native_password 修改配置需要重启mysql服务 ......
  • 003基于SSM+Jsp+Mysql的美好生活日志网
    开发语言:Java框架:ssm技术:JSPJDK版本:JDK1.8服务器:tomcat7数据库:mysql5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包:Maven3.3.9系统展示前台首页用户注册用户登录日记信息管理员登录用户管理日记信息管理美食信息管理景点信息管......
  • Python部分错误总结
    1.couldnotconvertstringtofloat:''由于空字符串不包含任何数字,因此无法确定其浮点数等价物,所以转换失败并抛出ValueError。在没办法处理数据的时候,可以通过设置默认值。some_value=""try:result=float(some_value)exceptValueError:result=0#或......
  • MySQL查询数据库响应时长的方法
    要查询MySQL数据库的响应时长,通常我们需要测量查询执行的时间。MySQL本身并不直接提供一个查询来显示每个查询的响应时长历史记录,但我们可以使用MySQL的内置函数和工具来测量和记录查询的执行时间。以下是一些方法,我们可以用来测量MySQL查询的响应时长:1.使用SHOWPROFILES(......
  • python---正则表达式
    ==本章目标:1:能够知道在Python中使用正则要导入的模块;[了解]   re模块2:能够使用re模块匹配单个字符;[重点]   \d \w 正则表达式的概述:基本介绍正则表达式,也叫做规则表达式,通常会说成[正则]实际上正则表达式就是指符合一定规则的字符串,同时他能用......
  • MySQL Shell 的简单使用
    util.dumpTables():导出表util.dumpSchemas():导出单个或多个schemautil.dumpInstance():导出整个实例 util.dumpTables()的使用语法:util.dumpTables(schema,tables,outputUrl[,options])其中:·schema:是表所在的schema·tables:是一个数组,表示要导出的表的列表·outp......
  • python 正则表达式使用简介和实用技巧
    元字符释义.代指任意字符^从字符串开始匹配$匹配字符串的结尾*匹配前面挨着的字符,能匹配0到无穷次+同*,能匹配1到无穷次(最少1个)?匹配前面挨着的字符,匹配0或1次{}自定义匹配次数,{1,6}匹配1到6次,{6}匹配6次(重复匹配前面挨着的字符)......
  • MySQL清空所有表的数据的方法
    1.MySQL清空所有表的数据的方法要清空MySQL数据库中所有表的数据,但保留表结构,我们可以采取以下几种方法。这里,我将提供几种常用的方法,并给出相应的SQL代码示例。1.1方法一:使用TRUNCATETABLE命令(针对每个表)TRUNCATETABLE命令会删除表中的所有数据,但不会重置表的自增计数器(AUTO......