简体   繁体   中英

How to serialize and deserialize Django ORM query (not queryset)?

My use case is that I need to store queries in DB and retrieve them from time to time and evaluate. Thats needed for mailing-app where every user can subscribe to a web-site content selected by individually customized query. Most basic solution is to store raw SQL and use it with RawQuerySet . But I wonder is there better solutions?

At first glance, it is really dangerous to hand out query building job to others, since they can do anything (even delete all your data in your database or drop entire table etc.)

Even you let them build a specific part of the query, it is still open to Sql Injection . If it is ok for all those dangers, then you may try the following.

This is and old script I used and let users set a specific part of the query. Basics are using string.Template and eval (the evil part)

Define your Model:

class SomeModel(Model):
    usr = ForeingKey(User)
    ct = ForeignKey(ContentType) # we will choose related DB table with this
    extra_params = TextField() # store extra filtering criteria in here

Lets execute all queries belongs to a user. Say we have a User query with extra_params is_staff and 'username__iontains'

usr: somebody

ct: User

extra_params: is_staff=$stff_stat, username__icontains='$uname'

$ defines placeholders in extra_params

from string import Template
for _qry in SomeModel.objects.filter(usr='somebody'): # filter somebody's queries
    cts = Template(_qry.extra_params) # take extras with Template
    f_cts = cts.substitute(stff_stat=True, uname='Lennon') # sustitute placeholders with real time filtering values 
    # f_cts is now `is_staff=True, username__icontains='Lennon'`
    qry = Template('_qry.ct.model_class().objects.filter($f_cts)') # Now, use Template again to place our extras into a django `filter` query. We also select related model in here with `_qry.ct.model_class()`
    exec_qry = qry.substitute(f_cts=f_cts)
    # now we have `User.objects.filter(is_staff=True, username__icontains='Lennon')
    query = eval(exec_qry) # lets evaluate it!

If you have all relted imports done,then you an use Q or any other query building option in your extra_params. Also You can use other methods to form Create or Update queries.

You can read more about Template form there. But as I said. It is REALLY DANGEROUS to give a such option to other users.

Also you may need to read about Django Content Type

Update: As @GillBates mentioned, you can use a dictonary structure to create the query. In this case, you will not need Template anymore. You can use json for such data transfer (or any other if you wish). Assuming you use json to get the data from an outer source following code is a scratch that uses some variables from the upper code block.

input_data : '{"is_staff"=true, "username__icontains"="Lennon"}'

import json
_data = json.loads(input_data)
result_set = _qry.ct.model_class().objects.filter(**_data)

According to your answer,

User passes some content-specific parameters into a form, then view function, that recieves POST, constructs query

one option is to store parameters (pickle'd or json'ed, or in a model) and reconstruct query with regular django means. This is somewhat more robust solution, since it can handle some datastructure changes.

You could create a new model user_option and store the selections in this table. From your question, it's hard to determine whether it is a better solution, but it would make your user's choices more explicit in your data structure.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM