On Jan 25, 2006, at 9:57 PM, Adrian Holovaty wrote:
I've written up my latest proposal here:
http://code.djangoproject.com/wiki/DescriptorFields
Yum!
I agree with Joseph -- I like this new syntax a *lot*.
I do have a few semantic questions, though. WARNING: Much nit-
picking follows; I should lead with the disclaimer that I'm *very*
happy with the syntax; I just want to make sure we get it as perfect
as possible!
First:
Also, it would be cool if the _set stuff wasn't forced on us, there's
a disconnect between creating an attribute called 'sites' in your
model, and accessing that attribute via 'site_set'.
I *very* much agree with this.
Consider::
class Article(models.Model):
headline = models.CharField(maxlength=50)
reporter = models.ForeignKey(Reporter)
sites = models.ManyToManyField(Site)
The fact that I can't do ``article.sites.all()`` seems wrong -- is
there a reason for the foo_set name over the given field name that
I'm missing? This also deals with the edge case where I have
something like::
class Foo(models.Model):
bars = models.ManyToManyField(Bar)
bar_set = models.CharField()
Second, I'm still unhappy that it's not clear when a database lookup
is performed. Luckily, I think the proposed syntax makes it easy to
write a few rules so that you'll always know when the db is being
hit. How does this sound:
1. ``Manager.get`` always perfoms a lookup.
2. Any other manager method only actually hits the database when
iterated.
3. ``object.foreign_key`` always performs a lookup.
4. ``object.m2m_set`` is esentially a manager, so it behaves as
for 1 and 2.
There is a question of how/weather to cache database lookups::
article = Article.objects.get(pk=1)
article.reporter.fname # obvious performs a lookup
article.reporter.lname # does this?
I'd expect that subsequent accesses to the same foreign key do not
perform additional lookups, but if that's so there needs to be a way
to clear the cached object in case you have an object you need to
hang on to for a while. I'd suggest ``article.clear_relation_cache()``.
There's also the question of caching many to many lookups; my gut is
that Django shouldn't::
list(article.site_set) # hits the db
list(article.site_set) # does it again
Finally, it seems like the manager has a lot of methods, and I think
some of them are redundant. For one, ``Reporter.objects.all
().distinct()`` strikes me as less obvious than ``Reporter.objects.all
(distinct=True)``
In fact, I have trouble understanding why we need ``all()`` at all,
actually; what's the difference between these two?
::
Reporter.objects.all()
Reporter.objects.filter()
Why not rename "filter" to "list" (or "iterator" if we want to be
pedantic) and collapse the two methods into one?
Similarly, the chaining of filter/order_by/in_bulk seems crufty to
me; are these equivalent?
::
Reporter.objects.filter(fname="Joe").order_by("fname")
Reporter.objects.order_by("fname").filter(fname="Joe")
I'm a big fan of the "One True Way" principle, so that rubs me the
wrong way. Why not simply have order_by/distinct/etc. be kwargs to
the manager functions? If there's a good reason to do the "chained
methods" that's fine, but let's not be too clever for our own sakes, eh?
Adrian, thanks again for thinking this through -- I think this change
will make code a *lot* more readable, and of course a lot more fun.
Jacob