Предоставляя пользователю возможность добавлять ограничения SQL, Django - PullRequest
2 голосов
/ 04 ноября 2011

У меня странная потребность, клиент попросил меня реализовать веб-приложение для поддержки его базы данных.Так как я люблю Джанго, я решил использовать его.

Дополнительная потребность, с которой я сталкиваюсь, заключается в следующем: у пользователя должна быть дополнительная «сила» для создания ограничений модели, таких как проверка диапазона IntegerField, и все это ничего не зная о Python.

Итак, у меня есть некоторые идеи, но я не уверен, что является (если есть) правильным.Вот мои мысли:

  1. Реализация проверки на стороне шаблона с использованием JavaScript
  2. Реализация скрипта Python и удобного для пользователя способа использовать его для записи файла models.py (это звучит ужасно)
  3. Напишите некоторые административные действия, используя ограничение необработанного SQL CHECK, но я до сих пор не знаю, как

Разрешается ли этот запрос?Можете ли вы дать мне совет о простейшем способе сделать это?

Заранее спасибо,

- Flavio

1 Ответ

1 голос
/ 05 ноября 2011

Да, это действительно возможно.Для решения проблемы мы будем использовать менеджер пользовательских объектов и объекты динамического Q .Вот пример.

  1. Создать подходящую модель для хранения информации об ограничениях.Обратите внимание, что мы создаем ForeginKey для ContentType, чтобы связать наше ограничение с конкретным классом модели.

    #your_app/models.py
    from django.contrib.contenttypes.models import ContentType
    from django.contrib.auth.models import User
    
    class PerUserConstraint(models.Model):
        user = models.ForeignKey(User)
        content_type = models.ForeignKey(ContentType)
        field_name = models.CharField(max_length = 255)
        predicate = models.CharField(max_length = 255) #for example, 'contains' etc.
        filter_value = models.CharField(max_length = 255)
    
  2. Создайте собственный менеджер, зарегистрируйте его ствои модели.

     #your_app/models.py
     from django.db.models.query_utils import Q
    
     class ConstraintedManager(models.Manager):
         def get_constrainted_query(self, user):
             qs = self.model.objects.all()
             content_type = ContentType.objects.get_for_model(self.model.__class__)
             constraints = PerUserConstraint.objects.filter(
                                                  user = user,
                                                  content_type = content_type
             )
             if constraints:
                 filters = []
                 for constraint in constraints:
                     filters.append(('%s__%s' % (constraint.field_name, constraint.predicate), constraint.value)
                 # at this point filters should look like this:
                 # [('question__contains', 'dinner'), ('question__contains', 'meal')]
                 q_list = [Q(x) for x in filters]
                 return qs.filter(reduce(operator.and_, q_list))
                 # which is something like 
                 # return qs.filter(Q(question__contains = 'dinner') & Q(question__contains = 'meal'))
    
            else:
                return qs     
    
     class YourModel(models.Model):
         #some fields
         ... 
         c = ConstraintedManager()
    

Таким образом, в ваших представлениях вы сможете использовать его так: YourModel.c.get_constrainted_query(user)

Обратите внимание, что я не тестировал этот код, но янадеюсь, вы поняли концепцию.

Чтобы переопределить запросы внутри ModelAdmin, используйте методы this и this .

...