Менеджер Django, объединяющий в цепочку

Вы можете реализовать анимацию UIView, как здесь: http://maniacdev.com/2013/02/ios-uiview-category-allowing-you-to-set-up-customizable-animation-properties

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"cornerRadius"];
animation.duration = DURATION;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
animation.toValue = @(NEW_CORNER_RADIUS);
animation.fillMode = kCAFillModeForwards;
animation.removedOnCompletion = NO;
[view.layer addAnimation:animation forKey:@"setCornerRadius:"];

29
задан Adam 2 May 2009 в 05:49
поделиться

3 ответа

См. Этот фрагмент в Djangosnippets: http://djangosnippets.org/snippets/734/

Вместо того, чтобы помещать свои пользовательские методы в менеджер, вы создаете подкласс самого запроса. Это очень просто и отлично работает. Единственная проблема, с которой я столкнулся, связана с наследованием модели, вы всегда должны определять менеджера в подклассах модели (просто: «objects = QuerySetManager ()» в подклассе), даже если они будут наследовать набор запросов. Это будет иметь больше смысла, когда вы используете QuerySetManager.

21
ответ дан 28 November 2019 в 01:59
поделиться

Вот конкретное решение моей проблемы с использованием пользовательского QuerySetManager от Саймона, с которым Скотт связался.

from django.db import models
from django.contrib import admin
from django.db.models.query import QuerySet
from django.core.exceptions import FieldError

class MixinManager(models.Manager):    
    def get_query_set(self):
        try:
            return self.model.MixinQuerySet(self.model).filter(deleted=False)
        except FieldError:
            return self.model.MixinQuerySet(self.model)

class BaseMixin(models.Model):
    admin = models.Manager()
    objects = MixinManager()

    class MixinQuerySet(QuerySet):

        def globals(self):
            try:
                return self.filter(is_global=True)
            except FieldError:
                return self.all()

    class Meta:
        abstract = True

class DeleteMixin(BaseMixin):
    deleted = models.BooleanField(default=False)

    class Meta:
        abstract = True

    def delete(self):
        self.deleted = True
        self.save()

class GlobalMixin(BaseMixin):
    is_global = models.BooleanField(default=True)

    class Meta:
        abstract = True

Любой миксин в будущем, который хочет добавить дополнительную функциональность к набору запросов, просто должен расширить BaseMixin (или иметь его где-нибудь в своей иерархии). Каждый раз, когда я пытаюсь отфильтровать установленный запрос, я помещаю его в try-catch на тот случай, если это поле на самом деле не существует (т. Е. Оно не расширяет этот миксин). Глобальный фильтр вызывается с помощью globals (), тогда как фильтр удаления вызывается автоматически (если что-то удаляется, я никогда не хочу, чтобы это отображалось). Использование этой системы допускает следующие типы команд:

TemporaryModel.objects.all() # If extending DeleteMixin, no deleted instances are returned
TemporaryModel.objects.all().globals() # Filter out the private instances (non-global)
TemporaryModel.objects.filter(...) # Ditto about excluding deleteds

Следует отметить, что фильтр удаления не влияет на интерфейсы администратора, поскольку диспетчер по умолчанию объявляется первым (делая его по умолчанию). Я не помню, когда они сменили администратора на использование Model._default_manager вместо Model.objects, но все удаленные экземпляры все равно будут отображаться в администраторе (в случае, если вам нужно удалить их).

8
ответ дан Adam 14 October 2019 в 08:55
поделиться

I spent a while trying to come up with a way to build a nice factory to do this, but I'm running into a lot of problems with that.

The best I can suggest to you is to chain your inheritance. It's not very generic, so I'm not sure how useful it is, but all you would have to do is:

class GlobalMixin(DeleteMixin):
    is_global = models.BooleanField(default=True)

    objects = GlobalManager()

    class Meta:
        abstract = True

class GlobalManager(DeleteManager):
    def globals(self):
        return self.get_query_set().filter(is_global=1)

If you want something more generic, the best I can come up with is to define a base Mixin and Manager that redefines get_query_set() (I'm assuming you only want to do this once; things get pretty complicated otherwise) and then pass a list of fields you'd want added via Mixins.

It would look something like this (not tested at all):

class DeleteMixin(models.Model):
    deleted = models.BooleanField(default=False)

    class Meta:
        abstract = True

def create_mixin(base_mixin, **kwargs):
    class wrapper(base_mixin):
        class Meta:
            abstract = True
    for k in kwargs.keys():
        setattr(wrapper, k, kwargs[k])
    return wrapper

class DeleteManager(models.Manager):
    def get_query_set(self):
        return super(DeleteManager, self).get_query_set().filter(deleted=False)

def create_manager(base_manager, **kwargs):
    class wrapper(base_manager):
        pass
    for k in kwargs.keys():
        setattr(wrapper, k, kwargs[k])
    return wrapper

Ok, so this is ugly, but what does it get you? Essentially, it's the same solution, but much more dynamic, and a little more DRY, though more complex to read.

First you create your manager dynamically:

def globals(inst):
    return inst.get_query_set().filter(is_global=1)

GlobalDeleteManager = create_manager(DeleteManager, globals=globals)

This creates a new manager which is a subclass of DeleteManager and has a method called globals.

Next, you create your mixin model:

GlobalDeleteMixin = create_mixin(DeleteMixin,
                                 is_global=models.BooleanField(default=False),
                                 objects = GlobalDeleteManager())

Like I said, it's ugly. But it means you don't have to redefine globals(). If you want a different type of manager to have globals(), you just call create_manager again with a different base. And you can add as many new methods as you like. Same for the manager, you just keep adding new functions that will return different querysets.

So, is this really practical? Maybe not. This answer is more an exercise in (ab)using Python's flexibility. I haven't tried using this, though I do use some of the underlying principals of dynamically extending classes to make things easier to access.

Let me know if anything is unclear and I'll update the answer.

2
ответ дан 28 November 2019 в 01:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: