Object queries in Django

The Django framework comes with an ORM, which provides some powerful and convenient querying functions that are not table dependent. Take the following example:

class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')
    
    

Question.objects.all()

Question.objects.get(pk=1)

As you can see from the example, the objects.all and objects.get functions are not defined in class Question and may or may not be defined in its parent class models.model. So how do we do this in web.py? You don’t need to implement it yourself if you choose to use SQLAlchemy.

implementation

Train of thought

Notice that a call like question.objects.all () directly accesses the class property objects and calls the method all() on the objects property. Objects can be either an instance or a class. Personally, I think (and I haven’t seen a Django implementation) that this should be an instance, because the instantiation process can pass some table information to make a function like all() work. After the analysis, we can list the problems we need to solve:

  1. You need to implement a Model’s superclass, Model, from which the actual table can inherit to obtain its own undefined functionality.

  2. Once the actual model class (such as Question) is defined, it should have the lookup effect of objects.all() if not instantiated.

As you can see from the above requirements, we need to implement these functions when the class is defined, rather than waiting until the class is instantiated. Implement the function when the class is defined? That’s what metaclass does. So the implementation process might look something like this:

  1. Implement a Model class, its binding methods and table add, delete, change related.

  2. Modify the metaclass of the Model class to ModelMetaClass. During the definition of the metaclass, add a Objects object to the class, which is an instance of ModelDefaultManager class and realizes the query function of the table.

code

Said not to code is playing rogue, I still give it. Note: The database operations used are all interfaces in Web.py’s DB library.

# -* -coding: UTF-8 -* -import web import config # def _connect_to_db(): return web.database(dbn="sqlite", db=config.dbname) def init_db(): db = _connect_to_db() for statement in config.sql_statements: db.query(statement) class ModelError(Exception): """Exception raised by all models. Attributes: msg: Error message. """ def __init__(self, msg=""): self.msg = msg def __str__(self): return "ModelError: %s" % self.msg class ModelDefaultManager(object): """ModelManager implements query functions against a model. Attributes: cls: The class to be managed. """ def __init__(self, cls): self.cls = cls self._table_name = cls.__name__.lower() def all(self): db = _connect_to_db() results = db.select(self._table_name) return [self.cls(x) for x in results] def get(self, query_vars, where): results = self.filter(query_vars, where, limit=1) if len(results) > 0: return results[0] else: return None def filter(self, query_vars, where, limit=None): db = _connect_to_db() try: results = db.select(self._table_name, vars=query_vars, where=where, limit=limit) except (Exception) as e: raise ModelError(str(e)) return [self.cls(x) for x in results] class ModelMetaClass(type): def __new__(cls, classname, bases, attrs): new_class = super(ModelMetaClass, cls).__new__(cls, classname, bases, attrs) objects = ModelDefaultManager(new_class) setattr(new_class, "objects", objects) return new_class class Model(object): """Parent class of all models. """ __metaclass__ = ModelMetaClass def __init__(self): pass def _table_name(self): return self.__class__.__name__.lower() def insert(self, **kargs): db = _connect_to_db() try: with db.transaction(): db.insert(self._table_name(), **kargs) except (Exception) as e: raise ModelError(str(e)) def delete(self, where, using=None, vars=None): db = _connect_to_db() try: with db.transaction(): db.delete(self._table_name(), where, vars=vars) except (Exception) as e: raise ModelError(str(e)) def save(self, where, vars=None, **kargs): db = _connect_to_db() try: with db.transaction(): db.update(self._table_name(), where, vars, **kargs) except (Exception) as e: raise ModelError(str(e))

use

First define the corresponding class of the table:

class Users(Model):
    ...
    

It works the same way as Django:

user_list = Users.objects.all()