Hi Malcolm,

Thank you VERY much for taking the time to explain this to me. It
makes perfect sense and since yesterday I've delved a bit deeper (than
ever) into the django code itself to understand a little more. You are
ABSOLUTELY right to point out that I'm in user-beware country. I don't
apologize for that so much. I think the batchimport project has some
usefulness to folks and it's worth the risk -- **IF** I do it
right. ;-) (if you think otherwise, PLEASE let me know)

Even since yesterday I've begun a good scouring of the project to
reduce touching the internals as much as possible.

I apologize for not giving more details. I am always trying to balance
giving enough information while trying to avoid scaring people away
with too much detail. I didn't think it through enough I suppose. I
kept being stymied by the thing "working" on the command line. My
mistake.

Anyway. I understand the whole thing MUCH better now and have already
spent a little time reviewing the really "cutting edge" aspects of
this project like, you know, "how lists work in python." ;-)

Ugh.

Kicking Myself Diligently,
Keyton

On Jan 22, 3:10 am, Malcolm Tredinnick <malc...@pointy-stick.com>
wrote:
> On Wed, 2009-01-21 at 19:38 -0800,KeytonWeissinger wrote:
> > OK. I figured it out and it was VERY STRANGE. Maybe some one reading
> > this can tell me WWWHHHYYY my solution works. For now, it's voodoo to
> > me...
>
> You're going to kick yourself after this. The reason for the failure
> turns out to be really easy to understand, now that your show the
> code. :-)
>
>
>
> > Turns out that some of my code (in the view where I was having
> > trouble) called some code that looked sort of like this:
>
> Hmm .. you didn't exactly simplify your failing case to the smallest
> possible example, did you? All this extra stuff would have set off a lot
> of alarm bells about other places to look (although my first thought
> would have been whether you could do without it and retest to see if
> that changed anything).
>
> Before getting into the more-or-less two line explanation, some
> background information. Firstly, model._meta is obviously internal API,
> so there are some shortcuts taken for performance and maintainability
> reasons. We don't send the black helicopters after people who access it,
> but it's very much "user beware" country. It's one of the areas that is
> currently intentionally undocumented, for example (we'll eventually drop
> some documentation about internal datastructures into docs/internals/,
> but have had other things to do so far).
>
> Of relevance to this particular case, we use lists a lot internally and
> return references to them from certain methods. We use lists, rather
> than tuples, because they are updated a fair bit during creation and all
> the extra copying isn't free (updating a tuple requires a copy). Lists
> are just nicer to work with, generally.
>
> > field_list = model._meta.fields
>
> Have a look at the implementation here
> (django.db.models.options.Options._fields(), since _meta.fields is a
> property). It returns a reference to a list. A *reference*, not a copy!
>
> Your code would have worked if you wrote
>
>         # Work with a copy of the fields list.
>         field_list = model._meta.fields[:]
>
> > field_list.extend(model._meta.many_to_many)
>
> Here you update that reference in place. So you've just corrupted one of
> the internal data structures of self._meta.
>
> That's pretty much going to guarantee that the wheels will fall off at
> some point in the future. If not in the way you saw, in some other
> really hard to debug fashion.
>
> It's kind of a Python trap and if you're designing a public API, you
> would generally return a copy of the list if the caller wasn't expected
> to change the internal structure. In the Options class, we "know" (in
> quotes, because there are people who call it from public code, but
> that's their problem, not ours) that the only callers are functions that
> are read-only on the data structure, so we save a bit of time and code
> complexity. We could return a copy each time, but we access self._fields
> a *lot*, particularly in queryset operations. Things might have changed
> a bit in the last six months (although not dramatically), but when I was
> working on the queryset-refactor branch, I spent a lot of time profiling
> various common execution paths and a lot of the newer shared data
> structures in Options are implemented based on that work (self.fields
> used to be a simple list, for example, but when model inheritance came
> in, it became, internally, more complicated).
>
> Regards,
> Malcolm
--~--~---------~--~----~------------~-------~--~----~
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 
django-users+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to