0

I have made a django app that creates models and database tables on the fly. This is, as far as I can tell, the only viable way of doing what I need. The problem arises of how to pass a dynamically created model between pages.

I can think of a few ways of doing such but they all sound horrible. The methods I can think of are:

  1. Use global variables within views.py. This seems like a horrible hack and likely to cause conflicts if there are multiple simultaneous users.
  2. Pass a reference in the URL and use some eval hackery to try and refind the model. This is probably stupid as the model could potentially be garbage collected en route.
  3. Use a place-holder app. This seems like a bad idea due to conflicts between multiple users.
  4. Having an invisible form that posts the model when a link is clicked. Again very hacky.

Is there a good way of doing this, and if not, is one of these methods more viable than the others?

P.S. In case it helps my app receives data (as a json string) from a pre-existing database, and then caches it locally (i.e. on the webserver) creating an appropriate model and table on the fly. The idea is then to present this data and do various filtering and drill downs on it with-out placing undue strain on the main database (as each query returns a few hundred results out of a database of hundreds of millions of data points.) W.R.T. 3, the tables are named based on a hash of the query and time stamp, however a place-holder app would have a predetermined name.

Thanks,

jhoyla

EDITED TO ADD: Thanks guys, I have now solved this problem. I ended up using both answers together to give a complete answer. As I can only accept one I am going to accept the contenttypes one, sadly I don't have the reputation to give upvotes yet, however if/when I ever do I will endeavor to return and upvote appropriately.

The solution in it's totality,

from django.contrib.contenttypes.models import ContentType
view_a(request):
    model = create_model(...)
    request.session['model'] =  ContentType.objects.get_for_model(model)
    ...

view_b(request):
    ctmodel = request.session.get('model', None)
    if not ctmodel:
        return Http404
    model = ctmodel.model_class()
    ...
jhoyla
  • 1,191
  • 1
  • 9
  • 26
  • Instead of copying the data into another database, have you considered using something like Memcache or another caching layer? – mipadi Jul 11 '12 at 16:38
  • what's the app name you are using? – Hassek Jul 11 '12 at 16:41
  • I in theory could use Memcache or something similar but getting new software approved by legal is a nightmare. Easier to just make one myself. – jhoyla Jul 12 '12 at 08:48
  • @Hassek The app_name I am using at the moment is 'query' + str(hash(query + time.now())) but that's likely to change eventually. – jhoyla Jul 12 '12 at 08:57
  • Could you provide a bit more information about the method you're using to create models dynamically? – supervacuo Jul 12 '12 at 16:51
  • Sure, I'm using the create_model function from the [link](https://code.djangoproject.com/wiki/DynamicModels) page. I've modified it slightly to add the functions I need using attrs.update(functions) where functions in a dictionary of function names to functions. – jhoyla Jul 12 '12 at 17:06
  • I did see that page, but noticed it dates back to Django < 1.2 (see the notice at the top of the page). Unless you've got very far in your development, perhaps you could try one of the solutions [suggested in that notice](http://stackoverflow.com/a/7934577/497056)? – supervacuo Jul 12 '12 at 23:49
  • As I said to @mipadi before, getting new software / plugins approved by legal is a nightmare. I have now however, solved the problem, thanks for all your help. – jhoyla Jul 13 '12 at 08:49

2 Answers2

2

My first thought would be to use content types and to pass the type/model information via the url.

scytale
  • 12,346
  • 3
  • 32
  • 46
  • That was my first thought, too. Having never created a model on-the-fly, does it cause all the normal things to happen, including creating the content-type-id? – Peter Rowell Jul 12 '12 at 02:15
  • It doesn't appear to show up in contenttypes. Presumably I can add it though? – jhoyla Jul 12 '12 at 08:27
  • Ok, so I can get a ContentType for my model with `django.contrib.contenttypes.models.ContentType.objects.get_for_model(model)` where model is my dynamically created model. How can I leverage this to access the model from another view? – jhoyla Jul 12 '12 at 17:40
  • well can you pass the content type id and model id to the view via the url? – scytale Jul 13 '12 at 08:04
  • Turns out you can, however because I'm using hashes to generate non-colliding names it makes for very long, ugly urls, that due to their transient nature can't be reused. The session option is cleaner. – jhoyla Jul 13 '12 at 09:12
1

You could also use Django's sessions framework, e.g.

def view_a(request):
    your_model = request.session.get('your_model', None)

    if type(your_model) == YourModel
        your_model.name = 'something_else'

    request.session['your_model'] = your_model

    ... 

def view_b(request):
    your_model = request.session.get('your_model', None)

    ...

You can store almost anything in the session dictionary, and managing it is also easy:

 del request.session['your_model']
supervacuo
  • 9,072
  • 2
  • 44
  • 61
  • Apparently you can't pickle modules made on the fly. You get: Exception Type: PicklingError Exception Value: Can't pickle : import of module 0f3ca88a74423fbbffe7b39805c5d794 failed This is because there is no such module. If I added pickle support to the model as a function would that be sufficient? – jhoyla Jul 12 '12 at 08:40
  • After a little research and experimentation it turns out, at least according to the python docs, that functions not defined at the top level are unpicklable. Is there some way to make session use marshal, or some variant thereof, instead of pickle? – jhoyla Jul 12 '12 at 10:55
  • 1
    Why not store the PK of the model in the session, and retrieve it from the database? – mipadi Jul 12 '12 at 15:18
  • You can't pickle property objects either. Session works by pickling the object. – jhoyla Jul 12 '12 at 16:19
  • Would it work to use the name of an already-loaded module rather than an invented one? A note on the [DynamicModels wiki page](https://code.djangoproject.com/wiki/DynamicModels) suggests this used to be necessary to have dynamic models at all, interestingly... – supervacuo Jul 12 '12 at 23:50
  • I say this as I can't see a way of using a different method of session storage in Django, but it still seems like the cleanest solution. – supervacuo Jul 12 '12 at 23:52
  • I tried using already loaded modules, but basically you ended up having to pass around lots of state information which by the time you had clicked through a few links was invariably out of date and crashed. I'm aware that this is just poor implementation on my part, but using content types is cleaner. – jhoyla Jul 13 '12 at 09:15