Reputation: 3064
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
How to I get the Jornal object through its domain? I was trying this in the shell:
domain = "www.example.com"
obj = Jornal.objects.get_domain(domain)
and then this:
domain = "www.example.com"
obj = Jornal.objects(domain = domain)
But none works.
EDIT I was trying with a get method because I want DoesNotExist in case it is not found.
Upvotes: 3
Views: 7335
Reputation: 1204
You cannot query for properties of a model. You can check if the url contains the domain in it, but this would return all entries in your database which have the same domain.
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
Upvotes: 2
Reputation: 31260
To do this exact thing, you don't need the database at all. So it works just like any other Python object in this case and you can ignore the fact it's a Django model.
url = "www.example.com"
jornal = Jornal(url=url)
print(jornal.domain)
Upvotes: 0
Reputation:
The property is accessible once you've created an instance of Journal
.
Filtering the way you want will only allow filtering in python, but you should actually do this in SQL.
I suggest you add a domain field to your model, and remove the property. Consider using Django's signals.
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)
And then you will able to .filter(domain=...)
or .get(domain=)
without a performance problem.
Upvotes: 1
Reputation: 477883
Since the property is stored at runtime, we can - if we consider the property to be a blackbox - only do this by filtering at the level of Python. So for instance with list comprehension:
domain = "www.example.com"
all_example_domain = [j for j in Journal.objects.all() if j.domain == domain]
We can not - in general - reverse a function, so we can not use filtering at the database level for this.
Here we now however something extra: that the domain
is a substring of the URL. So we can boost the filtering process by already doing some filtering at the database level:
domain = "www.example.com"
all_example_domain = [j for j in Journal.objects.filter(url__icontains=domain)
if j.domain == domain]
So here we already filter out Journal
objects where the url
does not contain the requested domain
. It would technically be possible that there are still errors in it (for instance an url with www.example.com.com
). We thus better do a second filtering with j.domain == domain
.
In case there is no such object, then the list will be empty, in case there are multiple, the list will contain two or more items.
We can use this to write a function that will do the proper filtering and raise errors in case no such object, or multiple objects are found. Like for instance:
from itertools import islice
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
Which we can thus query with property_get(Journal.objects.all(), domain=domain)
and it will raise an ObjectDoesNotExist
or MultiObjectsReturned
exceptions. But it is rather inefficient.
Usually it is better if you frequently query for a property, to store the property in the database as well as a field, and thus not use a property.
Upvotes: 2