简体   繁体   中英

Single Django model, multiple tables?

I know this exact same question has been previously asked, but I was hoping for a 'better' answer (that does not involve modifying class attributes at runtime). This was the question:

Single Django model, multiple tables?

I have the same problem - I am looking for a solution similar to the responder's first reply, but that actually works. If there is no better solution, can anyone comment on how reliable the responder's solution is? It seems to me that the delay between changing the database name and querying the database could end up returning results from the wrong table:

query 1: change the name

query 2: change the name again

query 1: get results (but using the incorrect name from query 2)

Edit: The model is intended for use on ~15 tables - so inheritance is impractical, since it would require a new model name every time.

Thanks

PS My apologies if this is not the correct way of asking for an elaboration on a question.

for a dynamic table and database interhangeable model with a more sexy behaviour than the one in your linked question you may use simple methods or properties:

import copy

class MyModel(models.Model):
    # anything
    @property
    def table_name(self):
        return self._meta.db_table

    @table_name.setter
    def table_name(self, value):
        new_meta = copy.copy(self._meta)
        new_meta.db_table = value
        self._meta = new_meta

    @classmethod
    def set_qs_for_table(cls, qs, table):
        my_class = copy.copy(cls)
        my_options = copy.copy(my_class._meta)
        my_class._meta = my_options
        qs.model = my_class

You may try something like this...

The copy part is to avoid danger of shared options between models. It took me time to find this part of the solution. but for the rest it looks sexy and straightforward.

Of course once in python code you may use

qs = MyClass.objects.all()
MyClass.set_qs_for_table(qs, "this_table")
my_instance = qs[0]
my_instance.table_name = "that_table"
my_instance.save(using="this_db")

A very useful snippet.

from django.db import models
shard_tables = {}
class ShardMixin():
    @classmethod
    def shard(cls, id=None):
        def get_ext(id):   # the multi tables rule
            return str(id % 100)  
        ext = get_ext(id)
        _db_table = "%s%s" % (cls._meta.db_table , ext)  # your table name
        if _db_table not in shard_tables:
            class Meta:
                db_table = _db_table
            attrs = {
                '__module__': cls.__module__,
                'Meta': Meta,
            }
            shard_tables[_db_table] = type("%s%s" % (cls.__name__, ext), (cls, ), attrs)
        return shard_tables[_db_table]

class User(models.Model, ShardMixin):
    username = models.CharField(max_length=255, verbose_name=" username")
    class Meta:
        abstract = True
        db_table = "user_"

users = User.shard(id=3).objects.values()
print(users)

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