Re: @url tag - getting rid of urlpatterns

2007-08-30 Thread Ilya Semenov

Ivan,

Thanks for reviewing the snippet.

> While the decorator looks nice it creates in my opinion at least as many
> problems as it solves.
>
> 1. You can apply decorators only to custom views, not to generic views.
> And as generic views are commonly used one still should keep a separate
> urls.py for them.

First of all, the decorator is fully optional. It doesn't replace
urlpatterns, it gently appends to them. There's nothing wrong in
writing:

urlpatterns = urlpatterns('',
('^news/$', 'django.views.generic.object_list',
{'queryset':..})
)

@url('^edit_news/$')
def edit_news(request):


Second, I think the use of generic views is over-estimated. Generic
views do not even support access restrictions (@user_passes_test) and
thus are most of the time proxied via custom one-line views.

> 2. One of the best things (again, in my opinion) of urls.py is that it
> shows whole user interface of an app in one place. You loose this
> feature with decorators scattered all over views.

While I see the rationale in your words, that position is very
arguable.

Encapsulation is one of the greatest programming principles. From the
architectural point of view, the app-level urls.py shouldn't bother
what members area urls are there in members module, since it can
safely delegate the responsibility to manage the list of members urls
and just pull the data when needed.

> BTW, do you know that you can use function objects instead of their
> names in url definition? So this:
>
>  urlpatterns = patterns(__name__,
>  (r'^index/$', 'index'),
>
> becomes just:
>
>  urlpatterns = patterns('',
>  (r'^index/$', index),

Sure, that way it is more natural. Alas, that won't work, since index
function is defined later in the module code. Alternatively, one
should put urlpatterns to the very end of the module file, which just
doesn't feel right to me.


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



@url tag - getting rid of urlpatterns

2007-08-29 Thread Ilya Semenov

I've been using django for almost a year and I was always frustrated
by its cumbersome urlpatterns system. While it is really flexible, it
doesn't provide any shortcuts for widely-used url and views naming
schemes.

Let me show in examples what I mean.

As everyone, I started with the tutorial and worked with the following
system:

=== urls.py ===
urlpatterns = patterns('',
(r'^$', 'apps.app1.views.index'),
(r'^news/$', 'apps.app1.views.news'),
(r'^members/profile/$', 'apps.app1.views.members.profile'),
(r'^members/secure/$', 'apps.app1.views.members.secure'),
(r'^app2/page/$', 'apps.app2.views.page'), # some other app
...
)

It becomes quite a large and hardy maintainable list when the number
of applications and views grows. I do believe in DRY principle and I
didn't like much that I had to repeat the URL bases and parent module
names again and again. So I kept reading the docs and involved the
system to the following:

=== urls.py ===
urlpatterns = patterns('',
(r'^', include('apps.app1.urls')),
(r'^app2', include('apps.app2.urls')),
)

=== apps/app1/urls/__init__.py ===
urlpatterns = patterns('apps.app1.views',
(r'^index/$', 'index'),
(r'^news/$', 'news'),
(r'^members', include('apps.app1.urls.members'),
)

=== apps/app1/urls/members.py ===
urlpatterns = patterns('apps.app1.views.members',
(r'^profile/$', 'profile'),
(r'^secure/$', 'secure'),
)

=== apps/app1/views/__init__.py ===
def index(request):
...
def news(request):
...

=== apps/app1/views/members.py ===
def profile(request):

def secure(request):
...

(I skipped app2.* files for easier reading)

While this system had less redundancy and easier to maintain (the DRY
benefits), it suffered from another DRY problem - there were two
packages with the same structure (apps.app1.urls.* and
apps.app1.views.*), with the highly related content. When I was
renaming a view, I had to browse through two package structures and
change the things twice. Still frustrating, you see.

So what I decided, why do we have to keep urlpatterns apart of the
views? Why wouldn't I put them in the same files? The architecture
became:

=== urls.py ===
urlpatterns = patterns('',
(r'^', include('apps.app1.views')), # note views, not urls
(r'^app2', include('apps.app2.views')),
)

=== apps/app1/views/__init__.py ===
urlpatterns = patterns(__name__, # sic!
(r'^index/$', 'index'),
(r'^news/$', 'news'),
(r'^members', include('apps.app1.views.members'),
)

def index(request):
...
def news(request):
...

=== apps/app1/views/members.py ===
urlpatterns = patterns(__name__,
(r'^profile/$', 'profile'),
(r'^secure/$', 'secure'),
)

def profile(request):

def secure(request):
...

This was a good change. I had 50% less files, and I put the related
info within the same modules. Also note the usage of __name__, which
increased the DRY factor a bit more :-)

Yet I wasn't fully satisfied. Whenever I renamed a view I had to patch
the urlpatterns as well.
I also remembered an old inconvenience I always felt with views
modules. If I place views functions in a views module, and place like
"normal" helper functions there as well, they got mixed. By looking at
the code it is sometimes hard to understand which function is a view,
and which function is a helper.
So what I created is the @url decorator which solved the both
problems:

=== urls.py ===
urlpatterns = patterns('',
(r'^', include('apps.app1.views')),
(r'^app2', include('apps.app2.views')),
)

=== apps/app1/views/__init__.py ===
@url(r'^index/$')
def index(request):
...

@url(r'^news/$')
def news(request):
...

urlpatterns += include_urlpatterns(r'^members',
'apps.app1.views.members')

=== apps/app1/views/members.py ===
@url(r'^profile/$)
def profile(request):


@url(r'^secure/$)
def secure(request):
...

@url(r'^path1/$', '^path2/$') # you can specify several patterns
def multipath_view(request):
...

def helper(): # easily distinguishable - no @url!
...

Summarizing, the benefits are:
- no more creating and supporting urlpattern maps (less files, less
code, more DRY)
- have the url associated with a view in-place
- easily see if a function is a view
- fully compatible with other chained decorators

Implementation problems, or possible improvements:
- it is hackish
- the speed isn't constant time, it is O(N) where N is the number of
currently loaded modules
- I would like to make it support the no-arguments syntax:

@url()
def profile(request):


and have the decorator automatically pull the function name as the url
pattern, but that doesn't seem possible if there are further
decorators (like @user_passes_test or @render_to)

The source code can be found at http://www.djangosnippets.org/snippets/395/



Re: Mysql sleeping queries

2007-06-21 Thread Ilya Semenov

Malcolm,

I traced the problem and submitted the patch, see details at
http://code.djangoproject.com/ticket/4650
I'm not completely sure about the logic of signals though, the change
may affect some middleware depending on it.


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



Re: Mysql sleeping queries

2007-06-20 Thread Ilya Semenov

Malcolm,

I'm having exactly the same problem.
Under Apache+mod_python, each HTTP request keeps a stale MySQL
connection.

I traced the changeset, it was 5481->4582.

I put some logging to django.db.backends.mysql.base:


  self.connection = Database.connect(**kwargs)
+ log.msg("connected to %s" % self.connection)

+ log.msg("closed %s" % self.connection)
  self.connection.close()


The output was (for 2 HTTP requests):
2007/06/20 19:56 NOVST [-] Log opened.
2007/06/20 19:56 NOVST [-] connected to <_mysql.connection open to
'localhost' at 867f5ec>
2007/06/20 19:56 NOVST [-] closed <_mysql.connection open to
'localhost' at 867f5ec>
2007/06/20 19:56 NOVST [-] connected to <_mysql.connection open to
'localhost' at 86c8af4>
2007/06/20 19:56 NOVST [-] connected to <_mysql.connection open to
'localhost' at 87fa7dc>
2007/06/20 19:56 NOVST [-] closed <_mysql.connection open to
'localhost' at 87fa7dc>
2007/06/20 19:56 NOVST [-] connected to <_mysql.connection open to
'localhost' at 8829fe4>

You see, 2 connections are opened and only 1 is closed per request.

As the result, there were two sleeping stale MySQL connections (output
of SHOW PROCESSLIST)
| 907 | root | localhost | corp2 | Sleep   |5 |   |
NULL |
| 909 | root | localhost | corp2 | Sleep   |2 |   |
NULL |

(Note the IDs had a gap between them).

If you have no time and/or can't reproduce the problem, I will try to
trace further and hopefully come up with a patch.


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



Re: select_related() and null=True

2007-03-06 Thread Ilya Semenov

David Cramer wrote:

> but I strongly encourage you to find a
> differently solution, as LEFT JOINs can be VERY costly on system
> resources.

I realize that under some circumstances, LEFT JOINs can be costly.
However, I don't hink my case is such. Let me recall the (I believe
very simple) model:

class Ticket(models.Model):
  is_resolved = models.BooleanField()
  resolved_by = models.ForeignKey(User, null=True)

What different approach could I choose? I'm writing real-life model -
a Ticket can either have a User (who resolved it), or not (if the
ticket has not been yet resolved). Listing all resolved Tickets with
corresponding Users is a simple real-life task, too.

How do I find a different approach? The only solution which comes to
my mind is to create a "special" User with id=0, and make all None
references point to it instead, but this seems very unnatural and
hackish to me.

Any other ideas?


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