On Sep 23, 2:01 am, Russell Keith-Magee <russ...@keith-magee.com> wrote: > On Wed, Sep 22, 2010 at 11:31 PM, Klaas van Schelven > > <klaasvanschel...@gmail.com> wrote: > >> I'm yet to see a genuine case of (a) -- every time I've seen (a), it's > >> really masked version of (b), (c) or (d). > > > I disagree. I think there are very specific problems, that has not > > been adressed by any of the responses above. > > Let's focus on one for now: how to extend models in any given app. > > > As stated in the original mail, there are at least two problems with > > this in Django: > > 1. How to provide the models in the first place? Everything that's not > > abstract is hard to extend; providing abstract models feels really > > awkward. > > If a model isn't abstract but needs to be, then that speaks to > applications not being built to be as extensible as possible. Django > hasn't always had abstract models -- they were added just before 1.0 > landed (IIRC). > > Unfortunately, it's very difficult to migrate from a concrete model > back to an abstract model, so it's not easy to introduce an abstract > model into an existing app without breaking backwards compatibility. > There are also complications around handling foreign keys to abstract > models. This is an area where there is room for improvement; there > have been some very recent discussions on this very topic. Alex Gaynor > discussed some of the issues and approaches in his recent DjangoCon > presentation [1]. > > [1]http://djangocon.blip.tv/file/4108781/
Thanks for the video. I'll try to make my case again with the insight I've gained over the last couple of mails. Let me reiterate that a large part of the reusable app problem has been solved. However, the following has not: Reusing a small set of functionality around some typical, extensible data structures. Again, examples: * A reusable address book * A reusable "who's at the office" calendar * A reusable small library tool (which books are in our library) * A reusable time tracking tool In any of the above, the data structure is typical and revolves around a few related model classes. The views revolve around common CRUD for the objects, and around "whatever makes the app special". Special stuff is, in the case of time tracking: various ways of inputting time and searching for it. In the case of an address book: displaying relevant lists, detail views. However, pretty much every actual use of the reusable app will involve some additions to the models. Contacts in the USA? We'll add a State field to your address model. Your particular use case requires us to categorize time-lines in a specific manner? We'll slap a foreign key on it to some "TimeLineCategory". The key is, that this new extended address, time-line or whatever should become the idea of an address, timeline or whatever from the perspective of the app. So, we run into a few problems: * How do we extend the models from the original extendible application? For this to work, we need to provide hooks in the application for extendiblity. In the case of models, such a hook would be twofold: 1. an abstract model to extend to provide a baseline (a default with the minimum amount of fields) 2. something overridable that is referred to by the rest of our app, providing the concrete instance of [1] in the plain vanilla app, and the concrete instance plus extensions in our extended app. (the actual hook) * how do we refer to ourselves from the various parts of the extendible application? Self-referral with overrides is a solved problem in the object oriented world ("inheritance"). However, it's impossible in Django's standard way of organizing apps, because we all use modules (not classes or instances) for the various parts of the app ("models.py", "views.py" etc). It is not possible to pass context into a module (other than monkey patching it) Every views.py begins with a bunch of imports from the associated models.py, tying the views into those particular app's models. My alternative would be like so: class View(...): def page_detail(self, request, pk=None): page = self.models.Page.objects.get(pk=pk) return render_to_response(.... page ...) For models: class Models(...): def get_Page(self): class Page(models.Model): #abstract category = models.ForeignKey(self.models.Category) return Page Page = property(get_Page) (The above is a bit less elegant than the views example because models are classes and the following therefor does not work:) class Models(...) class Page(self, model.Model): ... category = models.ForeignKey(self.models.Category) If anyone has an example of how to do this without a property I'd be much obliged. As said, I'll try to come up with something in the evening hours that allows for this and still feels Django-esque. (Which should make conversion of my own apps easier as well). > > > 2. How to tie in the models into the views? Long view parameter lists > > that are used from urls are ugly and repetitive. Moreover: it may not > > be possible to solve the entire problem this way (think admins, think > > forms). > > I'm afraid I have no idea what you're talking about here. HTTP is a > stateless protocol. The only reliable way you have to pass around > state is the arguments in a URL (technically, the request, so you can > use cookies too). This is one of the core *features* of the HTTP > protocol. Django provides a way (technically, several ways) of mapping > URLs to specific callables, and provides a way to hierarchically > organize those callables based on argument structure. > > I fail to see either the 'ugly', or the set of problems that can't be > solved. And it's somewhat spurious to say that "admin and forms" are > two things that Django can't do when Django ships with a forms > library, and Django's automated admin is one of the major initial > selling points of the framework. > Views.py methods generally have two types of parameters: 1. Those that are passed in via urls.py from the request path. Love 'em, couldn't live without 'em. This is what you're talking about. 2. Those we add (with usefull defaults) to make our app "reusable". What I was saying, is that I consider these in particular as unusable in the general sense. If I subclass the idea of address in an address book app (to add some field), would it make sense to refer to the subclassed address class in every call to every single view function? I'd say no. I'd rather say "give me my views where each view understands that it should use the improved address class). > > > > > > If we forget about Django's status quo for a minute and take > > extendability of related webfeatures as a goal, an obvious solution > > would be using a class. Classes are surely the poster child for > > extendability. The class would contain everything that's relevant for > > an app: all models, views, admin stuff etc, in addition to the > > relevant internal API ('hooks'). Like so: > > > class AbstractPage(models.Model): > > body = models.TextField() > > > class Meta: > > abstract = True > > > class MyApp(object): > > def get_models(self): > > # returns something that Django understands, i.e. a list of > > Model classes > > # or simply lists the models, so that the cache picks up on it > > > def get_page_class(self): > > class Page(AbstractPage): > > pass > > return Page > > > def page_detail(self, request, pk=None): > > page = self.get_page(pk) > > # or: > > page = self.get_page_class.objects.get(pk=pk) > > return render_to_response('myapp/page_detail.html', locals()) > > > def get_urls(self): > > # something that can be included by django > > > Obviously we can choose anything that python permits to create > > organization of the above once it starts growing. Standardization > > would be a good idea as well. > > However, the main point is that a structure like the above would allow > > for very simple extension on the app level, like so: > > > class CustomizedMyApp(object): > > def get_page_class(self): > > class Page(AbstractPage): > > title = models.CharField(max_length=255) > > return Page > > > AFAIK this is currently not possible. But I may be misinformed. > > I think you'll find you are. Why is what you are describing not > possible right now? Django is, at the end of the day, a machine for > turning a HTTP request into a function call, and turning the response > for that function call into a HTTP response. If you want to use a > particular class structure to compose that logic, go right ahead. > There's nothing in Django stopping you. Agreed, I was wrong. I'll take it up to some real projects and report back. > > This may mean that you discover some magnificent class structure for > composing full websites from parts. What will convince me isn't a > dozen lines in an email -- it's a fully fledged project, with the > complexity of something like a CMS. > > And it isn't me you need to convince anyway -- it's the wider > community. Trust me -- if you find the magic formula for perfect > reusability, my opinion won't matter. You'll be beating away > contributors with a stick. :-) I don't need to convince anyone, I was looking for input and a "Teddy Bear"/"Rubber Duck". > > > The main stumbling block is that an app is somehow special to Django, > > specifically in that it is a directory, containing a file 'models.py'. > > The name of the app directory is included in INSTALLED_APPS in your > > settings.py. I guess other stuff might break as well (do urlpatterns > > and reverse views work for any method, rather than functions in the > > top level of a module?). > > *This* is the stumbling block? Honestly? Can you please describe an > occasion where the fact that you need to predeclare the application > modules (and it is the *module*, not the directory) that you intend to > use has been an impediment to reusability? I fail to see how this is > any different to complaining that Python requires you to put "import > os.path" before you can do directory path manipulations. My understanding of what happens with installed_apps was incorrect on various levels. You're right. > > Django's idea of apps is great, because it gives us such an easy way > > to start. However, I think it breaks down in the above example. Would > > it be possible to rewrite Django so that the INSTALLED_APPS way of > > working would remain available, but would be a shortcut/facade to a > > manual registration of the various parts that entail an app? I think > > so. > > You seem to be implying that your example is fundamentally constrained > by the existence of INSTALLED_APPS. Either I'm missing something, or > you haven't explained some subtle detail, because I simply don't see > the limitation. > > > Hope to hear from you all, I will play a bit with some code in the > > meantime. > > > p.s. > > Thinking about it some more: it's not weird at all that apps are hard > > to extend, since apps are limited to being modules. Modules are not a > > unit for extension. > > Why not? > > If you want to write a custom Email class, you don't put the code in > the Python standard library. You write a "my.custom.email" module, and > put an extension class in it. Why can't a module be used to organize > extensions? Made you say "class" :-) Modules cannot be extended because they cannot refer to parts of their extended self from the original. See above. Klaas > > Yours, > Russ Magee %-) -- You received this message because you are subscribed to the Google Groups "Django users" group. To post to this group, send email to django-us...@googlegroups.com. To unsubscribe from this group, send email to django-users+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-users?hl=en.