如何通过domain属性获取Django的Jornal模型对象?
解决Django中通过@property属性获取模型对象的问题
你的问题出在domain是用@property定义的计算属性,它并不是数据库中实际存在的字段——Django的ORM查询是直接转换成SQL操作数据库的,而数据库里没有domain这个列,所以你尝试的get_domain和objects(domain=domain)自然无法生效。
下面给你三种可行的解决方案,根据你的实际场景选择:
方案一:临时通过URL字段匹配(适合偶尔查询、数据量小的情况)
既然domain是从url解析而来,我们可以反过来通过匹配url字段定位对象。这里提供两种实现方式:
方式A:遍历筛选后触发异常
from urllib.parse import urlparse domain = "www.example.com" # 筛选出domain匹配的对象 matched_objs = [obj for obj in Jornal.objects.all() if obj.domain == domain] # 手动触发DoesNotExist异常,和get方法行为一致 if not matched_objs: raise Jornal.DoesNotExist(f"No Jornal found with domain {domain}") obj = matched_objs[0]
方式B:用ORM查询条件匹配URL格式
通过Q表达式覆盖常见的URL格式(带http/https、有无末尾斜杠等),避免遗漏:
from django.db.models import Q domain = "www.example.com" obj = Jornal.objects.get( Q(url__startswith=f"http://{domain}/") | Q(url__startswith=f"https://{domain}/") | Q(url__startswith=f"http://{domain}") | Q(url__startswith=f"https://{domain}") | Q(url__exact=domain) # 处理不带协议的URL情况 )
方案二:添加domain数据库字段(推荐,适合频繁查询、数据量大的场景)
把domain作为数据库字段存储,既能提升查询效率,又能直接使用ORM的get方法。我们可以在save方法中自动同步domain的值:
from django.db import models from urllib.parse import urlparse class Jornal(models.Model): url = models.URLField(unique=True, blank=True) name = models.CharField(max_length=100) # 添加domain字段,加上db_index提升查询速度 domain = models.CharField(max_length=255, blank=True, db_index=True) def __str__(self): return self.name def save(self, *args, **kwargs): # 保存时自动从url解析domain if self.url: self.domain = urlparse(self.url).netloc super().save(*args, **kwargs) # 保留原有的property方便旧代码使用(可选) @property def domain_from_url(self): return urlparse(self.url).netloc
修改后,你就能直接用get方法查询,不存在时自动触发DoesNotExist异常:
domain = "www.example.com" obj = Jornal.objects.get(domain=domain)
方案三:自定义模型管理器(不修改模型结构,优雅封装查询)
如果你不想改动现有模型,可以自定义模型管理器,封装get_by_domain方法:
from django.db import models from urllib.parse import urlparse class JornalManager(models.Manager): def get_by_domain(self, domain): for obj in self.all(): if obj.domain == domain: return obj # 找不到对象时抛出和get一致的异常 raise self.model.DoesNotExist(f"No {self.model.__name__} found with domain {domain}") class Jornal(models.Model): url = models.URLField(unique=True, blank=True) name = models.CharField(max_length=100) # 替换默认的模型管理器 objects = JornalManager() def __str__(self): return self.name @property def domain(self): return urlparse(self.url).netloc
之后你就能像最开始设想的那样调用:
domain = "www.example.com" obj = Jornal.objects.get_by_domain(domain)
注意:这个方案需要遍历所有对象,数据量大时查询效率会很低,仅适合小规模数据集。
内容的提问来源于stack exchange,提问作者Miguel
相关产品推荐
相关产品推荐

