Как проверить пользовательские теги шаблонов в Django?

Самый простой способ - использовать функцию tuple _ , снабженную SQLAlchemy:

from sqlalchemy import tuple_

session.query(Foo).filter(tuple_(Foo.a, Foo.b, Foo.c).in_(items))

Это работает с PostgreSQL, но ломается с SQLite.

К счастью, существует обходное решение, которое должно работать во всех базах данных.

Начните с отображения всех элементов с помощью выражения and_:

conditions = (and_(c1=x, c2=y, c3=z) for (x, y, z) in items)

И затем создайте фильтр or_, который охватывает все условия:

q.filter(or_(*conditions))

Вот простой пример:

#/usr/bin/env python
from sqlalchemy import create_engine
from sqlalchemy import Column, Integer
from sqlalchemy.sql import and_, or_
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('sqlite:///')
session = sessionmaker(bind=engine)()
Base = declarative_base()

class Foo(Base):
    __tablename__ = 'foo'

    id = Column(Integer, primary_key=True)
    a = Column(Integer)
    b = Column(Integer)
    c = Column(Integer)

    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

    def __repr__(self):
        return '(%d %d %d)' % (self.a, self.b, self.c)

Base.metadata.create_all(engine)

session.add_all([Foo(1, 2, 3), Foo(3, 2, 1), Foo(3, 3, 3), Foo(1, 3, 4)])
session.commit()
items = ((1, 2, 3), (3, 3, 3))
conditions = (and_(Foo.a==x, Foo.b==y, Foo.c==z) for (x, y, z) in items)
q = session.query(Foo)
print q.all()
q = q.filter(or_(*conditions))
print q
print q.all()

Какие выходы:

$ python test.py 
[(1 2 3), (3 2 1), (3 3 3), (1 3 4)]
SELECT foo.id AS foo_id, foo.a AS foo_a, foo.b AS foo_b, foo.c AS foo_c 
FROM foo 
WHERE foo.a = :a_1 AND foo.b = :b_1 AND foo.c = :c_1 OR foo.a = :a_2 AND foo.b = :b_2 AND foo.c = :c_2
[(1 2 3), (3 3 3)]

34
задан Dominic Rodger 6 May 2010 в 05:42
поделиться

4 ответа

Это короткий отрывок из одного из моих тестовых файлов, где self.render_template является простым вспомогательным методом в TestCase:

    rendered = self.render_template(
        '{% load templatequery %}'
        '{% displayquery django_templatequery.KeyValue all() with "list.html" %}'
    )
    self.assertEqual(rendered,"foo=0\nbar=50\nspam=100\negg=200\n")

    self.assertRaises(
        template.TemplateSyntaxError,
        self.render_template,
        '{% load templatequery %}'
        '{% displayquery django_templatequery.KeyValue all() notwith "list.html" %}'
    )

Он очень простой и использует тестирование методом черного ящика. Он просто берет строку в качестве источника шаблона, отображает ее и проверяет, соответствует ли результат ожидаемой строке.

Метод render_template довольно упрощен:

from django.template import Context, Template

class MyTest(TestCase):
    def render_template(self, string, context=None):
        context = context or {}
        context = Context(context)
        return Template(string).render(context)
35
ответ дан 27 November 2019 в 16:46
поделиться

Вы, ребята, направили меня на верный путь. Можно проверить, что контекст был правильно изменен после рендеринга:

class TemplateTagsTestCase(unittest.TestCase):        
    def setUp(self):    
        self.obj = TestObject.objects.create(title='Obj a')

    def testViewsForOjbect(self):
        ViewTracker.add_view_for(self.obj)
        t = Template('{% load my_tags %}{% views_for_object obj as views %}')
        c = Context({"obj": self.obj})
        t.render(c)
        self.assertEqual(c['views'], 1)
17
ответ дан 27 November 2019 в 16:46
поделиться

Если вы не хотите менять структуру на что-то другое , у вас действительно нет выбора - вам понадобится большой оператор if, чтобы указать, с каким полем вы имеете дело. Вы можете скрыть это (и упростить запись) с помощью макросов, но это та же самая структура, и вам придется просто с ней разобраться.

Вот пример того, как вы могли бы написать этот макрос - он действительно упрощает использование, но он все еще не «короткий».

//Assumption: at the time you want to use this, you've got two strings, one with the 
// name of the field to set (key), one with the value to set (value). I also assume

typedef struct MyType {
  int  fieldA;
  int  fieldB;
} MyType;

// fldnamedef - name of the field in the structure definition (const char *)
// convfunc - name of a function that takes a value, returns a fldtypedef
// s - structure to put data into
// key - const char * pointing to input field name
// value - const char * pointing to input field value
#define IF_FIELD_SET(fldnamedef, convfunc, s,  key, value) {\
  if (strcmp(#fldnamedef, key) == 0) {\
    s.fldnamedef = convfunc(value);\
  }\
}


int main()
{
  MyType t={0,0};

  IF_FIELD_SET(fieldA, atoi, t, "fieldA", "2");

  printf("%d,%d\n",t.fieldA, t.fieldB);
}

А вот вывод препроцессора, в который преобразуется строка IF_FIELD_SET:

0
ответ дан 27 November 2019 в 16:46
поделиться

Когда я тестировал свои теги шаблона, я бы сам тег возвращал строку, содержащую текст или dict I работал с ... вроде как с другим предложением.

Поскольку теги могут изменять контекст и / или возвращать строку для визуализации, я обнаружил, что быстрее всего просто просмотреть визуализированную строку.

Вместо:

return ''

Получите:

return str(my_data_that_I_am_testing)

Пока вы не будете счастливы.

0
ответ дан 27 November 2019 в 16:46
поделиться
Другие вопросы по тегам:

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