En hints
soll Ihrem Datenbank-Router helfen zu entscheiden, wo er seine Daten lesen oder schreiben soll. Er kann sich mit zukünftigen Versionen von Python weiterentwickeln, aber im Moment gibt es nur eine Art von Hinweisen, die vom Django-Framework gegeben werden können, und das ist der instance
an dem es arbeitet.
Ich habe diesen sehr einfachen Datenbank-Router geschrieben, um zu sehen, was Django kann:
# routers.py
import logging
logger = logging.getLogger("my_project")
class DebugRouter(object):
"""A debugging router"""
def db_for_read(self, model, **hints):
logger.debug("db_for_read %s" % repr((model, hints)))
return None
def db_for_write(self, model, **hints):
logger.debug("db_for_write %s" % repr((model, hints)))
return None
def allow_relation(self, obj1, obj2, **hints):
logger.debug("allow_relation %s" % repr((obj1, obj2, hints)))
return None
def allow_syncdb(self, db, model):
logger.debug("allow_syncdb %s" % repr((db, model)))
return None
Sie deklarieren dies in settings.py
:
DATABASE_ROUTERS = ["my_project.routers.DebugRouter"]
Vergewissern Sie sich, dass die Protokollierung richtig konfiguriert ist, um Debug-Ausgaben auszugeben (z. B. auf stderr):
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
[...some other handlers...]
'stderr': {
'level': 'DEBUG',
'class': 'logging.StreamHandler'
}
},
'loggers': {
[...some other loggers...]
'my_project': {
'handlers': ['stderr'],
'level': 'DEBUG',
'propagate': True,
},
}
}
Dann können Sie eine Django-Shell öffnen und ein paar Anfragen testen, um zu sehen, welche Daten Ihr Router erhält:
$ ./manage.py shell
[...]
>>> from my_project.my_app.models import User
>>> User.objects.get(pk = 1234)
db_for_read (<class 'my_project.my_app.models.User'>, {})
<User: User object>
>>> user = User.objects.create(name = "Arthur", title = "King")
db_for_write (<class 'my_project.my_app.models.User'>, {})
>>> user.name = "Kong"
>>> user.save()
db_for_write (<class 'my_project.my_app.models.User'>, {'instance':
<User: User object>})
>>>
Wie Sie sehen können, ist die hints
ist immer leer, wenn noch keine Instanz (im Speicher) vorhanden ist. Sie können also keine Router verwenden, wenn Sie Abfrageparameter (z. B. die ID des Objekts) benötigen, um zu bestimmen, welche Datenbank abgefragt werden soll. Es könnte in Zukunft möglich sein, wenn Django die Query- oder Queryset-Objekte in der hints
dict.
Um also Ihre Frage zu beantworten, würde ich sagen, dass Sie zunächst einen benutzerdefinierten Manager erstellen müssen, wie von Aaron Merriam vorgeschlagen. Aber das Überschreiben nur des create
Methode reicht nicht aus, denn Sie müssen auch in der Lage sein, ein Objekt aus der entsprechenden Datenbank zu holen. Etwas wie dies könnte funktionieren (noch nicht getestet):
class CustomManager(models.Manager)
def self.find_database_alias(self, pk):
return #... implement the logic to determine the shard from the pk
def self.new_object_database_alias(self):
return #... database alias for a new object
def get(self, *args, **kargs):
pk = kargs.get("pk")
if pk is None:
raise Exception("Sharded table: you must provide the primary key")
db_alias = self.find_database_alias(pk)
qs = self.get_query_set().using(db_alias)
return qs.get(*args, **kargs)
def create(self, *args, **kwargs):
db_alias = self.new_object_database_alias()
qs = super(CustomManager, self).using(db_alias)
return qs.create(*args, **kwargs)
class ModelA(models.Model):
objects = CustomManager()
Prost