简体   繁体   中英

How can I copy all field definitions from one model class to another?

I have a model ( Patch ) which has an author field and I need to generate several reports, always filtering out the rows whose author doesn't contain the string '@example.com'. Given that Patch is defined in a separate django app, which I don't want to change, my idea was to create a DB view (say, ExampleComPatch , accessed using a non-managed model class) that filters out all the rows I'm not interested in, and then put the reporting methods under that new model class.

To avoid code duplication, I made my new model class inherit from Patch. That works fine with only a couple caveats:

  1. My view needs to have all the columns defined in Patch plus an extra 'patch_ptr_id' one, as django thinks I want real inheritance in the DB as well
  2. Since it's a non-managed model class, the tests that use that view need to create it manually

However, since django thinks I want real inheritance, whenever I delete an instance of Patch, it ends up going through all its sub-objects (eg the rows in ExampleComPatch that link to it), which means tests that have no relation whatsoever to ExampleComPatch may now need to create the DB view manually if they need to delete() a row from the Patch table.

I think inheritance may not be the best option here, but I'd really like to avoid the code duplication, so I'm wondering if there's a way to copy over all field definitions from Patch to ExampleComPatch. Or maybe even a completely different approach that would allow me to use a DB view (to reduce complexity of my reporting methods) with the reporting methods defined outside of Patch as they don't make much sense there.

Proxy models are your ticket. Something like so:

from somewhere import Patch

class FilteredPatchManager(models.Manager):
    def get_query_set(self, *args, **kwargs):
        return super(FilteredPatchManager, self).get_query_set().exclude(author__contains='@example.com')


class FilteredPatch(Patch)
    objects = FilteredPatchManager()

    class Meta:
        proxy = True

Then, use FilteredPatch.objects for queries instead of Patch.objects .

I think you're making things much more complex than they need to be. If I understand correctly, you want to exclude certain objects from some standard get queries - if that's the case, you should look into

Modifying initial Manager QuerySets

Basically, you can customize what get queries return, like this:

# First, define the Manager subclass.
class PatchManger(models.Manager):
    def get_query_set(self):
        return super(PatchManager, self).get_query_set().exclude(author__contains='@example.com')

# Then hook it into the Patch model explicitly.
class Patch(models.Model):
    author = models.CharField(max_length=100)

    objects = PatchManager() # The custom manager.

Hope I understood your problem correctly...

Cheers,

Martin

Why do you need to inherit or copy code at all? You can import the model into your current app and filter where necessary - if you like, you can create a function in your app that wraps the filter, so you just call that function to return the filtered instances.

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