Re: @url tag - getting rid of urlpatterns
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
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
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
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
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 -~--~~~~--~~--~--~---