On Jan 26, 2006, at 10:28 AM, Adrian Holovaty wrote:
The reason is consistency. If we enforce the "_set" thing (or whatever
other name we come up with), that means there's a simple rule to
remember:
[snip]
Make sense? But, yeah, I realize that the "sites" attribute name in
that model is essentially meaningless. Any other ideas?

It seems to me that the translation from ``sites`` in the model to ``site_set`` in the instance is "worse" than having an inconsistency between m2m and o2m relations. In fact, I don't really have a problem with the two relation types behaving differently.

I'd suggest that m2m relations use the attribute name, and that we introduce an option for ForeignKey that lets you override the o2m name::

    class Article:
        writer = meta.ForeignKey(Reporter, related_name="articles")
        sites = meta.ManyToManyField(Site)

    s = Site.objects.get(pk=1)
    r = Reporter.objects.get(pk=1)

    s.article_set.all()
    r.articles.all()

That is, if ``related_name`` isn't given then ``OBJECT_set`` is used.

<impression voice="DHH">Convention over Configuration!</impression>

I was thinking this would behave exactly as before --

    1. Manager.get() always performs a lookup.
    2. Any other default manager method only actually hits the
database when iterated (or repr()'d?).
    3. object.foreign_key performs a lookup only the first time --
unless select_related=True was used on the lookup of the parent
object, in which case the value would already be cached.
4. object.m2m_set is esentially a manager, so it behaves as for 1 and 2.

Perfect.

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 ()``.

We haven't had this up to this point, but -- sure. :)

That's a good point; is it worth adding this method at all? Is anyone actually going to need it?

I believe Django currently *does* cache many-to-many lookups, so I'd
been thinking it would continue to do so -- but I don't really mind
either way.

I'm also OK either way, but let's make it clear (somewhere) which it is.

Two reasons for making distinct a method instead of a keyword argument --

1. As Hugo pointed out, this makes it possible to chain queries.
2. It makes it possible to leave the "__exact" off, because we can be
positive any keyword argument to filter() is a field lookup, not a
meta argument such as "distinct" or "limit". For example, if you have
a field name called "distinct", you'd be able to do
Reporter.objects.filter(distinct='blah'), which would be the
equivalent of Reporter.objects.filter(distinct__exact='blah').
Granted, this is more of a side benefit than a reason *to* do it, but
I like it because it lets us trim the "__exact", which is the most
common lookup type.

Yeah, I'm convinced -- I had trouble reproducing your reasoning, but now that you explain it it makes perfect sense.

It's for readability, like Hugo said, but I'm not 100% sold on it
either way. Come to think of it, get() accepts filter arguments, so,
if we have a list(), it'd be nice and consistent if list() also
accepted filter arguments.

That's kinda what I would expect. The only problem is that list() doesn't actually return a list -- it returns a Query that can be iterated over... Hm...

OK, what about this: make ``objects`` callable::

        Before                                  After

        Article.objects.get_list()              Article.objects()
        Article.objects.get_list(**kw)          Article.objects(**kw)
        Article.objects.get_object(**kw)        Article.objects.get(**kw)
        Article.objects.get_values(**kw)        Article.objects.values(**kw)

That's more concise in the common case -- I'd guess that get_list() is far and away the most common method used -- and it does away with the filter/all distinction.

Thoughts?

Jacob

Reply via email to