如何从Django模型获取属性?

时间:2018-01-28 12:41:18

标签: python django django-models

each

如何通过其域获取Jornal对象?我在shell中尝试这个:

class Jornal(models.Model):
    url = models.URLField(unique = True,blank=True)
    name = models.CharField(max_length=100) 

    def __str__(self):
        return self.name
    @property
    def domain(self):
        return urlparse(self.url).netloc

然后这个:

domain = "www.example.com"
obj = Jornal.objects.get_domain(domain)

但没有效果。

编辑我正在尝试使用get方法,因为我找不到DoesNotExist,以防它找不到。

4 个答案:

答案 0 :(得分:1)

您无法查询模型的属性。您可以检查URL是否包含域,但这将返回数据库中具有相同域的所有条目。

from django.core.exceptions import ObjectDoesNotExist


domain = 'www.example.com'
journal_qs = Journal.objects.filter(url__icontains=domain) # Case insensitive
# Journal.objects.filter(url__contains=domain) # Case sensitive

if journal_qs.exists():
    # Some logic here because there exists some value
else:
   raise ObjectDoesNotExist

答案 1 :(得分:1)

由于属性是在运行时存储的,我们可以 - 如果我们认为该属性是 blackbox - 只能通过在Python级别进行过滤来实现。例如,列表理解:

domain = "www.example.com"
all_example_domain = [j for j in Journal.objects.all() if j.domain == domain]

我们不能 - 通常 - 反转一个函数,所以我们不能在数据库级别使用过滤。

此处我们现在有一些额外的东西:domain是网址的子字符串。因此,我们可以通过在数据库级别进行一些过滤来增强过滤过程:

domain = "www.example.com"
all_example_domain = [j for j in Journal.objects.filter(url__icontains=domain)
                        if j.domain == domain]

因此,我们已经过滤掉了Journal 包含请求的url的{​​{1}}个对象。从技术上讲,它可能仍然存在错误(例如,带有domain的网址)。因此,我们最好使用www.example.com.com进行第二次过滤。

如果没有这样的对象,那么列表将为空,如果有多个,列表将包含两个或更多项。

我们可以使用它来编写一个函数来进行正确的过滤并在没有找到这样的对象或多个对象的情况下引发错误。比如:

来自itertools import islice

j.domain == domain

我们可以使用def property_get(query_set, **kwargs): results = list(islice((j for j in qs if all(getattr(j, k) == v for k, v in kwargs.items())), 2)) if results: if len(results) > 1: raise MultipleObjectsReturned return results[0] else: raise ObjectDoesNotExist 查询,这会引发property_get(Journal.objects.all(), domain=domain)ObjectDoesNotExist例外。但效率很低。

通常情况下,如果经常查询属性,将属性存储在数据库和字段中,从而不使用属性,则会更好。

答案 2 :(得分:1)

一旦您创建了Journal的实例,就可以访问该属性。

过滤您想要的方式只允许在python中进行过滤,但您实际上应该在SQL中执行此操作。

我建议您在模型中添加域字段,然后删除该属性。考虑使用Django的信号。

    from django.db.models.signals import pre_save


    class Journal(models.Model):
        url = models.URLField(unique = True,blank=True)
        name = models.CharField(max_length=100)
        domain  = models.CharField(max_length=100)

    def extract_domain(sender, instance, **kwargs):
        instance.domain = urlparse(instance.url).netloc

   pre_save.connect(extract_domain, Journal)

然后,您可以.filter(domain=...).get(domain=)没有性能问题。

答案 3 :(得分:0)

要做到这一点,你根本不需要数据库。所以它就像在这种情况下的任何其他Python对象一样工作,你可以忽略它是一个Django模型的事实。

url = "www.example.com"
jornal = Jornal(url=url)
print(jornal.domain)