Bonus points for a clear problem description, so thanks for doing that.
Nothing jumps out at me as obviously wrong, unfortunately.
You don't mention how you're using this when it fails -- is it part of a
script or a view or what? In any case, I would try removing the call to
get_model(). Even if you just test that the model name is what you think
should return the Student model and then explicitly set the class you're
creating to be Student, instead of whatever get_model() returns. I
*hope* that won't make a difference, because get_model() and friends
give me a nose-bleed (and James Bennett gets far too much enjoyment out
of watching me fix those bugs), but it would be nice to know one way or
the other.
Are you using get_model() at the interactive prompt? Does it work there
instead of failing?
I'll try to make some time later on today to experiment with the code
you've given here and see if I can repeat it (in the middle of something
right now and just rest my brain by answering email, so not able to do
it this minute, sorry).
Right now, though, it's not obvious what you're doing that is strange.
Which is a shame.
Regards,
Malcolm
I can't reproduce this exception. Try to print import_object_dict just
before "new_object =
model_import_info.model_for_import.objects.create(**import_object_dict)".
> Note that I am NOT yet trying to SAVE the Student object, just instantiate it.
Actually Model.objects.create() do try to save() object. If you don't
want it, call Model(**import_object_dict)
M.
It's working using SVN HEAD with your model and this view:
http://dpaste.com/111590/. Could you try to use that dict and
Student(**mydict) instead of
"model_import_info.model_for_import.objects.create" ?
Regards,
M
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
>>> mydict = {'city': u'Columbus', 'first_name': u'Jimmy', 'last_name': u'Jones', 'zip': 43215.0, 'title': u'Mr.', 'dob': '1956-12-29', 'phone_primary': u'614-468-5940', 'state': u'OH', 'address': u'142, Quilly Lane', 'type': u'Student', 'email': u'Miles...@spambob.com'}