SITE's -- an idea to make them transparent/easier to use

1 view
Skip to first unread message

Ian Holsman

unread,
Nov 20, 2005, 10:12:41 PM11/20/05
to django-d...@googlegroups.com
hi.

I was thinking it might be a good idea to have a
meta.SiteModel class to inherit from for site-specific models. (ie..
you have 5 sites with articles stored in the same table) and it would
do all the hard work for you.

so instead of having something like
class Article( meta.Model):
site = ForeignKey( core.site)
...

and then having to remember add 'sites__id__exact=SITE_ID' each time
you query the table.

you could do something like

class Article( meta.SiteModel):
...

and meta.SiteModel would
- add the site field for you
- automatically append sites_id_exact in ALL queries (by checking the
klass in things like function_get_values_iterator)
- modify the uniqueness contstraints of the other fields so that they
include the site in the key. (allowing you to have the same slug value
over multiple sites)

why bother?
for me I like the idea that I can site-enable an application with a
minimum of fuss, and not having to remember to add the site_id__exact
query in every view I have.


Regards
ian

--
I...@Holsman.net -- ++61-3-9877-0909
If everything seems under control, you're not going fast enough. -
Mario Andretti

Simon Willison

unread,
Nov 21, 2005, 5:37:00 AM11/21/05
to django-d...@googlegroups.com

On 21 Nov 2005, at 03:12, Ian Holsman wrote:

> so instead of having something like
> class Article( meta.Model):
> site = ForeignKey( core.site)
> ...
>
> and then having to remember add 'sites__id__exact=SITE_ID' each time
> you query the table.
>
> you could do something like
>
> class Article( meta.SiteModel):
> ...
>
> and meta.SiteModel would
> - add the site field for you
> - automatically append sites_id_exact in ALL queries (by checking the
> klass in things like function_get_values_iterator)
> - modify the uniqueness contstraints of the other fields so that they
> include the site in the key. (allowing you to have the same slug value
> over multiple sites)

This is yet another case for some kind of mixin functionality.
Inheritance isn't really suitable for this because there are various
kinds of functionality we might want to add to a model, and multiple
inheritance is ugly. We really want something like:

class Article(meta.Model):
class Mixins:
site = SiteMixin()
taggable = TaggableMixin()
searchable = FullTextSearchMixin('headline', 'body')

etc.

Cheers,

Simon

Ian Holsman

unread,
Nov 21, 2005, 6:02:57 AM11/21/05
to django-d...@googlegroups.com
On 11/21/05, Simon Willison <swil...@gmail.com> wrote:

> This is yet another case for some kind of mixin functionality.
> Inheritance isn't really suitable for this because there are various
> kinds of functionality we might want to add to a model, and multiple
> inheritance is ugly. We really want something like:
>
> class Article(meta.Model):
> class Mixins:
> site = SiteMixin()
> taggable = TaggableMixin()
> searchable = FullTextSearchMixin('headline', 'body')
>

you can achieve the other 2 specialized fields, and you dont' need
mixins for them.

see http://svn.zilbo.com/svn/django/snippets/tag.py for an example of
it being done for tagging, or how hugo has implemented it
https://simon.bofh.ms/django-projects/stuff/trunk/tagging/utils.py

the difference with the 'site' is that effects all the queries, as it
is a kind of dynamic filter, as it affects ALL sql queries. and
inheritance would work well here.

another possibility would be for row-level authorizations.


> etc.
>
> Cheers,
>
> Simon

hugo

unread,
Nov 21, 2005, 6:20:17 AM11/21/05
to Django developers
>the difference with the 'site' is that effects all the queries, as it
>is a kind of dynamic filter, as it affects ALL sql queries. and
>inheritance would work well here.
>another possibility would be for row-level authorizations.

Actually both of them would work with Mixins, too - and Mixins would
help making other stuff more simple. So it's more a case of "Mixins are
the more general way". I'm all for mixins, but I would love it if we
could do them just with Pythons multiple inheritance:

class Poll(meta.Mode, SiteMixin, SearchMixin('title')):
...

(Yes, that's a parameterized class up there. I am bad, I know ;-) )

That would require the "get rid of magic model modules", though, as
otherwise it's a real pain to build with the current dynamic module
creation code (yes, I tried to get MI to work with the current model
and stopped working on it, because it's just too complicated to do to
be worth it).

bye, Georg

Kevin

unread,
Nov 21, 2005, 2:17:54 PM11/21/05
to Django developers
I have what I think is a similar problem where my model has an online
boolean flag. That way I can take the model offline but not delete it.
Eg.

class Article(meta.Model):
online = meta.BooleanField()

But now my views are littered with:

articles.get_list(online__exact=True)

I'd much prefer to have this online check to be done "behind the
scenes" so I don't forget to test for it in someplace....

Simon Willison

unread,
Nov 22, 2005, 12:19:40 PM11/22/05
to django-d...@googlegroups.com

On 21 Nov 2005, at 19:17, Kevin wrote:

> class Article(meta.Model):
> online = meta.BooleanField()
>
> But now my views are littered with:
>
> articles.get_list(online__exact=True)
>
> I'd much prefer to have this online check to be done "behind the
> scenes" so I don't forget to test for it in someplace....

Rails has a neat solution to this problem: http://api.rubyonrails.com/
classes/ActiveRecord/Base.html#M000728

Article.with_scope(:find => { :conditions => "blog_id = 1" }) do
Article.find(1) # => SELECT * from articles WHERE blog_id = 1
AND id = 1
end

In the above block, all find operations automatically have a "WHERE
blog_id = 1" clause added to them.

I'm not sure if this would be easy or even wise to duplicate in
Django, but it's an interesting solution.

Cheers,

Simon

Adrian Holovaty

unread,
Nov 22, 2005, 12:26:51 PM11/22/05
to django-d...@googlegroups.com
On 11/22/05, Simon Willison <swil...@gmail.com> wrote:
> Rails has a neat solution to this problem: http://api.rubyonrails.com/
> classes/ActiveRecord/Base.html#M000728
>
> Article.with_scope(:find => { :conditions => "blog_id = 1" }) do
> Article.find(1) # => SELECT * from articles WHERE blog_id = 1
> AND id = 1
> end
>
> In the above block, all find operations automatically have a "WHERE
> blog_id = 1" clause added to them.
>
> I'm not sure if this would be easy or even wise to duplicate in
> Django, but it's an interesting solution.

Django has where_constraints, which is undocumented and is a way of
adding arbitrary clauses to every lookup.

class Foo(meta.Model):
bar = meta.CharField(maxlength=3)
is_published = meta.BooleanField()
class META:
where_constraints = {'is_published__exact': True}

foos.get_list() returns all Foo objects with is_published set to True.

Adrian

--
Adrian Holovaty
holovaty.com | djangoproject.com | chicagocrime.org

Kevin

unread,
Nov 22, 2005, 1:09:33 PM11/22/05
to Django developers
In my same sample scenario, would this prevent me from accessing the
"offline" articles in the admin or from python? Can you create a more
specific query in get_list() that cancels that where_constraints? eg,

If I changed my model to:
class Article(Model):
online = BooleanField()

class META:
where_constraints = {'online__exact': True}

would this return all the offline articles or would it return nothing?

offline_articles = articles.get_list(online__exact=False)

Kevin

unread,
Nov 22, 2005, 9:42:21 PM11/22/05
to Django developers
Ok, I jumped into Django's code and it seems that the where_constraints
is instead an array of sql strings, not the keyword mapping.

so instead of:
where_constraints = {'online__exact: True}
you would need:
where_constraints = ['online = true']

Unfortunately, this basically makes it impossible to retrieve any row
in the database that doesn't match the clause. So in my example, if
you set the online field to false, you can never retrieve that article
without resorting to altering the database outside of django.

Andreas Stuhlmüller

unread,
Dec 2, 2005, 3:15:59 AM12/2/05
to django-d...@googlegroups.com
Actually, you can.

>>> from django.models.article import articles
>>> original_constraints = articles.Klass._meta.where_constraints
>>> articles.Klass._meta.where_constraints = []
>>> articles.get_list(online__exact=False)
>>> articles.Klass._meta.where_constraints = original_constraints

But is this safe or will it eventually cause problems?

Andreas
Reply all
Reply to author
Forward
0 new messages