Re: Allowing custom attributes in Meta classes

2013-09-10 Thread Andy McCurdy

On Sep 10, 2013, at 7:05 PM, Russell Keith-Magee  
wrote:

> I share James' reservations about this as a feature -- attaching flags to 
> Meta is something I can see being abused in all sorts of ways -- but that 
> doesn't mean there's no legitimate uses for extensions to Meta. For example, 
> the USERNAME_FIELD added in support of custom users should, arguably, be a 
> Meta option -- but there was no way we could add that without making a Meta 
> option available to every class.

For what it's worth, I've loosely copied Django's "metaclass w/ Meta options" 
pattern for several projects. In cases where I needed a bit more flexibility, 
the metaclass looked for a well named attribute on the class that would specify 
the options class to use. For example:


class Model(object):
# _meta is a ModelOptions instance
__OPTIONS_CLASS__ = ModelOptions


class Foo(Model):
# _meta is a ModelOptions instance, inheriting Model's __OPTION_CLASS__


class User(Model):
# _meta is a UserModelOptions instance that looks
# for a USERNAME_FIELD option
__OPTIONS_CLASS__ = UserModelOptions

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.
For more options, visit https://groups.google.com/groups/opt_out.


Re: pre_init/post_init vs. performance

2012-07-15 Thread Andy McCurdy

On Jul 14, 2012, at 6:37 PM, Russell Keith-Magee wrote:

> 
> My only concern is:
> 
>> We could store which fields have these hooks upon ModelBase.__new__
>> construction and so skip most fields and overhead in __init__.
> 
> I'm not sure if I'm misreading your intentions here, but just to be
> sure -- I'd like to avoid explicitly naming certain field types as
> "special" in ModelBase if at all possible. If we explicitly name
> certain fields in ModelBase, then it means that third-parties with the
> same requirement won't be able to exploit the same API entry point. In
> the case of GenericForeignKey specifically, it also means that we
> would be introducing a dependency (even if it was name-only) on
> contrib into core -- which is something we've been trying to move away
> from.



I think Jeremy means doing something like this in ModelBase.__new__:


meta.fields_needing_init = [field for field in fields if hasattr(field, 
'model_pre_init')]


And in ModelBase.__init__:


for field in self._meta.fields_needing_init:
field.model_pre_init(*args, **kwargs)


This way, in ModelBase.__init__, only the fields that actually need to be 
initialized have this method called.


-andy

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-developers@googlegroups.com.
To unsubscribe from this group, send email to 
django-developers+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en.



Re: Smart extends

2010-10-15 Thread Andy McCurdy
We are in complete agreement ;)

2010/10/15 J. Pablo Martín Cobos <goi...@gmail.com>

> Hi Andrew,
>
> I think you agree with me in all. Thank you very much for your long e-mail.
> I think you have explain the problem better than me. To use the urls for
> overwrite the templates "leads terrible looking URL", it's really true.
>
> If you don't think you agree with me in all, please tell me. Because as my
> english is not very good I don't know if  I have understand you perfect.
>
> --
> Pablo Martín
>
> 2010/10/15 Andy McCurdy <sed...@gmail.com>
>
>>
>> On Fri, Oct 15, 2010 at 6:09 AM, Andrew Godwin <and...@aeracode.org>wrote:
>>
>>> So, from what I can work out, this is a proposal for an {% extends %} tag
>>> which allows you to extend from the parent template of the same name (so it
>>> looks back in the list of possible templates, and picks the one that comes
>>> before yours, in your case inheriting from the admin version of the template
>>> with the same name?
>>>
>>> I'd like to know what sort of use cases you think this is necessary in -
>>> in the example you provide, admin/change_list.html, the recommended way of
>>> doing what you're doing would be to set change_list_template on the
>>> ModelAdmin class to point to a different template which itself inherits from
>>> admin/change_list.html, rather than having two with the same name, which
>>> could be potentially confusing.
>>
>>
>> At Whiskey, we have a custom extends tag that accomplishes the same thing
>> -- the ability to extend templates of the same name. For a quick background,
>> we have a fairly large number of apps that we reuse on multiple sites. Each
>> app provides a set of templates with "sane default" functionality. We end up
>> customizing a fair number of these templates on a per-site basis to simply
>> add some additional context for users. For example, we have a generic forum
>> app. On our video game site, we've added our users' XBOX Live scores under
>> their usernames when displaying forum messages. This gives viewers an idea
>> how much the author actually knows about the game being discussed. We do
>> these kinds of things quite frequently.
>>
>> We've named our custom extends tag "extends" and simply add it to the
>> system builtins. This way, all template extending goes through our tag.
>>
>> We chose to use this custom extends method rather than the established
>> "have your view accept a template parameter, then manually specify the
>> template from the urls.py module" pattern for several reasons:
>>
>> - We found having more template names was more confusing. Across all of
>> our apps, we already have close to 1,000 unique template names. Adding more
>> for these common customizations would lead to more confusion of our
>> designers.
>>
>> - Specifying overridden templates in urls.py leads to terrible looking URL
>> files. It's also a gross violation of DRY. Consider this example:
>>
>> forums/urls.py:
>> --
>> ...
>> url(r'topic/$', views.topic, name='forum-topic'),
>> ...
>>
>> site/urls.py
>> --
>> ...
>> (r'fourms/$', include('forums.urls')),
>> ...
>>
>> Now if I want to override the template that displays a forum topic, I have
>> to not only include the forums.urls above, I also have to copy/paste the
>> forum-topic url into site/urls.py to simply add extra kwargs specifying the
>> template name to the view. This gets gross real quick:
>>
>> site/urls.py
>> --
>> ...
>> from forums import views
>> url(r'forums/topic/$', forum_views.topic, name='forum-topic',
>> kwargs={'template': 'overridden_template.html'}),
>> (r'fourms/$', include('forums.urls')),
>> ...
>>
>>
>> - One or two of the 3rd party apps we use don't allow for template
>> customize through view kwargs. Since our tag is loaded as the default
>> extends tag, we can customize these templates for free without having to
>> write any Python code.
>>
>> - Finally, I don't really want our designers in Python code if I can help
>> it. Even if it's just copy/pasting from one urls file to another. And I
>> certainly don't want to be asked every time they want to override a template
>> to make a 1 line change.
>>
>> -andy
>>
>> --
>> You received this message because you are subscribed to the Google Groups
>> "Django developers" group.
>> T

Re: Smart extends

2010-10-15 Thread Andy McCurdy
2010/10/15 Łukasz Rekucki 

> 2010/10/15 J. Pablo Martín Cobos :
> >
> > Really the problem comes when we reuse a application: from other people,
> > from Django (i.e. django.contrib.admin), or even my own that we reuse in
> > some projects. Usually you want to change slight things and usually you
> want
> > only to change the visualization mode, you want to change the templates.
> You
> > need to adapt the application to your project.
> >
>
> It's a pretty good use case. But there's a problem with your original
> proposal: the admin provides a default "x.html" . Then you have some
> 3rd party application "A" that enhances the "x.html". And now comes
> your application "B" that also wants to extend "x.html". So you write:
>
> {% extends "x.html" %}
>
> Which "x.html" should be chosen ? the one from admin or the one from
> external app "A" ? Both are valid uses. There is a dangerous
> temptation to say "next that would be loaded after this", but that
> depends on loaders and application order  - lets don't go that way.
>
> Instead, IMHO, a good way to do this would be verbose about from which
> application you want the template to be loaded:
>
> {% extends admin:"x.html" %} # extend x.html from admin
> {% extends A:"x.html" %} #  extend x.html from application A
>
> Unfortunately for this approach, templates aren't provided or bound to
> applications - they're provided by loaders. It might be a good idea to
> extend the loader protocol to me "namespace" aware.
>
> My 2cents.
>
>
Ya, if you're using the AppDirectory loader already, you get this for free.
Of course if Django were to accept this, it would need to work with all the
loaders. For our implementation, we've made our own template loader
subclasses the AppDirectory one.

-andy

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-develop...@googlegroups.com.
To unsubscribe from this group, send email to 
django-developers+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en.



Re: Smart extends

2010-10-15 Thread Andy McCurdy
On Fri, Oct 15, 2010 at 6:09 AM, Andrew Godwin  wrote:

> So, from what I can work out, this is a proposal for an {% extends %} tag
> which allows you to extend from the parent template of the same name (so it
> looks back in the list of possible templates, and picks the one that comes
> before yours, in your case inheriting from the admin version of the template
> with the same name?
>
> I'd like to know what sort of use cases you think this is necessary in - in
> the example you provide, admin/change_list.html, the recommended way of
> doing what you're doing would be to set change_list_template on the
> ModelAdmin class to point to a different template which itself inherits from
> admin/change_list.html, rather than having two with the same name, which
> could be potentially confusing.


At Whiskey, we have a custom extends tag that accomplishes the same thing --
the ability to extend templates of the same name. For a quick background, we
have a fairly large number of apps that we reuse on multiple sites. Each app
provides a set of templates with "sane default" functionality. We end up
customizing a fair number of these templates on a per-site basis to simply
add some additional context for users. For example, we have a generic forum
app. On our video game site, we've added our users' XBOX Live scores under
their usernames when displaying forum messages. This gives viewers an idea
how much the author actually knows about the game being discussed. We do
these kinds of things quite frequently.

We've named our custom extends tag "extends" and simply add it to the system
builtins. This way, all template extending goes through our tag.

We chose to use this custom extends method rather than the established "have
your view accept a template parameter, then manually specify the template
from the urls.py module" pattern for several reasons:

- We found having more template names was more confusing. Across all of our
apps, we already have close to 1,000 unique template names. Adding more for
these common customizations would lead to more confusion of our designers.

- Specifying overridden templates in urls.py leads to terrible looking URL
files. It's also a gross violation of DRY. Consider this example:

forums/urls.py:
--
...
url(r'topic/$', views.topic, name='forum-topic'),
...

site/urls.py
--
...
(r'fourms/$', include('forums.urls')),
...

Now if I want to override the template that displays a forum topic, I have
to not only include the forums.urls above, I also have to copy/paste the
forum-topic url into site/urls.py to simply add extra kwargs specifying the
template name to the view. This gets gross real quick:

site/urls.py
--
...
from forums import views
url(r'forums/topic/$', forum_views.topic, name='forum-topic',
kwargs={'template': 'overridden_template.html'}),
(r'fourms/$', include('forums.urls')),
...


- One or two of the 3rd party apps we use don't allow for template customize
through view kwargs. Since our tag is loaded as the default extends tag, we
can customize these templates for free without having to write any Python
code.

- Finally, I don't really want our designers in Python code if I can help
it. Even if it's just copy/pasting from one urls file to another. And I
certainly don't want to be asked every time they want to override a template
to make a 1 line change.

-andy

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-develop...@googlegroups.com.
To unsubscribe from this group, send email to 
django-developers+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en.



Re: #12012 Logging: Final call for comments

2010-09-30 Thread Andy McCurdy
Russ,

This will be a welcomed addition to debugging Django apps. I have a question
about startup.py. I notice that startup runs after settings are loaded, but
before models. Does this mean that code within startup.py cannot safely
access the ORM? If the ORM is fully accessible in startup.py, it's safe to
ignore the rest of the mail.

If I cannot access models from startup.py, I have two concerns:

1. It seems fairly limiting. We currently have a hacked together startup
system for several ORM-related tasks. I'd love to replace this with yours,
assuming I don't lose functionality. Most notable, we have configuration
stored in the DB that is used to determine application behavior. Another use
case is using the startup system to add some of our template tags libraries
to builtins. Some of these template tag libs import models. Would this end
up causing circular reference issues?

We used to have these kinds of tasks load on the first request Django
processed using the request_started signal. However, this was limiting
because management commands and celery tasks never received the signal. We
need a system where no matter how our Django is loaded, startup happens.

2. What kind of error message am I going to receive if I do access models?
Debugging circular references is quite painful. At the very least, we should
consider a user trying to import models (or something else that imports
models) a common error and attempt to present a concise error message.

-andy

On Thu, Sep 30, 2010 at 6:56 AM, Russell Keith-Magee <
russ...@keith-magee.com> wrote:

> Hi all,
>
> A final call for comment before I commit #12012 to trunk. Barring
> objection, my intention is to commit this early next week.
>
> I've integrated the suggestions that have arisen since the first draft:
>
>  * This patch has docs :-) There aren't any tests though, and I think
> it's going to have to stay that way; this is one of those areas where
> it's almost impossible to test because it's very difficult to mock out
> early stages of app configuration. The good news is that the complex
> logic is all contained inside Python's logging library itself, and the
> logging calls that have been introduced are all exercised as part of a
> normal test run.
>
>  * I've modified the interpretation of LOGGING_CONFIG such that a
> value of None means "don't configure logging"
>
>  * I've modified the global-settings and project template logging
> settings. They are now at parity.
>
>  * I've modified the logging information that is provided in the 4XX
> loggers so that a status code is provided as logging context. 4XX
> messages are all still logged as warnings, but if you want to change
> this, you now have enough detail in the log record to use a log filter
> for that purpose.
>
> If you have any objections, now is the time to raise them.
>
> Yours,
> Russ Magee %-)
>
> --
> You received this message because you are subscribed to the Google Groups
> "Django developers" group.
> To post to this group, send email to django-develop...@googlegroups.com.
> To unsubscribe from this group, send email to
> django-developers+unsubscr...@googlegroups.com
> .
> For more options, visit this group at
> http://groups.google.com/group/django-developers?hl=en.
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-develop...@googlegroups.com.
To unsubscribe from this group, send email to 
django-developers+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en.



Re: logialogin_required does not check User.is_active

2010-04-15 Thread Andy McCurdy
On Thu, Apr 15, 2010 at 9:50 AM, Harro  wrote:

> I think the problem isn't the login_required, but it simply does what
> it says it does: Check if the user is logged in.
>
> For me a user with is_active set to false shouldn't be allowed to
> login, they either just created an account and still need to verify it
> or they indicated that they wanted their account "removed", in which
> case it's marked inactive so it doesn't cascade delete all their
> related items too.
>

Or the third case, when a staff user de-activates the user for some reason.
 In this scenario, the user is still logged in, and simply using
@login_required will continue to allow the user to access resources that are
meant to be restricted.

To correct this behavior, we've subclassed the Authentication middleware and
the LazyUser object it sets on the request.  Our LazyUser ensures the user
is active, otherwise it creates an AnonymousUser instance.

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-develop...@googlegroups.com.
To unsubscribe from this group, send email to 
django-developers+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en.



post_delete signal is sent when no objects are deleted

2009-07-08 Thread Andy McCurdy

If two different threads have a reference to a single model instance,
both can call the instance's delete() method.  Only one of the threads
will perform the actual deletion from the database, but both will send
a post_delete signal.  This can cause a number of race conditions with
signal handlers connected to post_delete.  A fairly common pattern for
a signal handler it to perform an action such as:

===
class Foo(models.Model):
count_of_bars = models.IntegerField()

class Bar(models.Model):
foo = models.ForeignKey(Foo)

def update_bar_count(sender, instance, **kwargs):
instance.foo.count_of_bars -= 1
instance.foo.save()

models.signals.post_delete.connect(update_bar_count, Bar)
===

In this case, if the same Bar instance is deleted by two different
threads, the "count_of_bars" column on the corresponding Foo record
will be off by 1

To solve this, the affected row count would need to be examined after
a delete query, which indicates whether the object was deleted by this
thread.  If the affected row count is 1, then we know the current
thread performed the deletion and should be responsible for sending
the post_delete signal.  If the affected row count is 0, then the
object was deleted by another thread, and the current thread should
*not* send a post_delete signal.

Unfortunately, there's another complexity.  Calling delete() on a
model instance also deletes records from other models that are foreign
keyed to the record being deleted.  (In the above example, if a Foo is
deleted, all the related Bars are also deleted.)  The
django.db.models.query.delete_objects function is optimized to perform
these deletes in batches using an IN() query.  This implementation
makes it impossible to determine which rows the current thread
actually deleted anytime the affected row count is less than the
number of rows requested to be deleted.  This could be corrected by
changing delete_objects, making it execute a separate delete query for
each object being deleted.  While this would not be as efficient, it
seems like the only way to correctly send post_delete signals.

I've started working on a patch/tests that implements the above
solution.  I'd like to get thoughts from others about this issue and
the proposed solution prior to making a new ticket.

Thanks,
-andy
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-developers@googlegroups.com
To unsubscribe from this group, send email to 
django-developers+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en
-~--~~~~--~~--~--~---