سؤال

كيف يمكنك إنشاء العرف عمليات البحث الميدانية في جانجو؟

عند تصفية مجموعات الاستعلام، يوفر Django مجموعة من عمليات البحث التي يمكنك استخدامها: __contains, __iexact, __in, ، وهكذا دواليك.أريد أن أكون قادرًا على تقديم بحث جديد لمديري، على سبيل المثال، يمكن لشخص ما أن يقول:

twentysomethings = Person.objects.filter(age__within5=25)

وارجع كل Person الأشياء التي يتراوح عمرها بين 20 و 30 عامًا.هل أحتاج إلى فئة فرعية QuerySet أو Manager فئة للقيام بذلك؟كيف سيتم تنفيذه؟

هل كانت مفيدة؟

المحلول

اعتبارا من Django 1.7، هناك طريقة بسيطة لتنفيذها. مثالك هو في الواقع مشابه جدا لل وثائق:

from django.db.models import Lookup

class AbsoluteValueLessThan(Lookup):
    lookup_name = 'lt'

    def as_sql(self, qn, connection):
        lhs, lhs_params = qn.compile(self.lhs.lhs)
        rhs, rhs_params = self.process_rhs(qn, connection)
        params = lhs_params + rhs_params + lhs_params + rhs_params
        return '%s < %s AND %s > -%s' % (lhs, rhs, lhs, rhs), params

AbsoluteValue.register_lookup(AbsoluteValueLessThan)

أثناء التسجيل، يمكنك فقط استخدام Field.register_lookup(AbsoluteValueLessThan) في حين أن.

نصائح أخرى

طريقة أكثر مرونة للقيام بذلك هي كتابة queryset مخصص وكذلك مدير مخصص. العمل من رمز Ozan:

class PersonQuerySet(models.query.QuerySet):
    def in_age_range(self, min, max):
        return self.filter(age__gte=min, age__lt=max)

class PersonManager(models.Manager):
    def get_query_set(self):
         return PersonQuerySet(self.model)

    def __getattr__(self, name):
        return getattr(self.get_query_set(), name)

class Person(models.Model):
    age = #...

    objects = PersonManager()

هذا يسمح لك بسلسلة الاستعلام المخصص الخاص بك. لذلك ستكون كل من هذه الاستفسارات صالحة:

Person.objects.in_age_range(20,30)

Person.objects.exclude(somefield = some_value).in_age_range(20, 30)

بدلا من إنشاء بحث حقل، ستكون أفضل الممارسات هي إنشاء طريقة إدارة، قد تبدو كبيرة مثل هذا:

class PersonManger(models.Manager):
    def in_age_range(self, min, max):
        return self.filter(age__gte=min, age__lt=max)

class Person(models.Model):
    age = #...

    objects = PersonManager()

ثم الاستخدام سيكون مثل ذلك:

twentysomethings = Person.objects.in_age_range(20, 30)

أولاً، اسمحوا لي أن أقول إنه لا توجد آلية Django موجودة تهدف إلى تسهيل ما تريد علنًا.

(تحرير - في الواقع منذ إصدار Django 1.7 يوجد: https://docs.djangoproject.com/en/1.7/howto/custom-lookups/ )

وقال ذلك، إذا كنت حقًا تريد تحقيق هذا، فئة فرعية QuerySet وتجاوز _filter_or_exclude() طريقة.ثم قم بإنشاء مدير مخصص يقوم بإرجاع مديرك المخصص فقط QuerySet (أو قرد التصحيح جانغو QuerySet, ، يوك).نحن نفعل هذا في com.neo4django لإعادة استخدام أكبر قدر ممكن من كود مجموعة استعلامات Django ORM أثناء إنشاء Neo4j الخاص Query أشياء.

جرب شيئًا (تقريبًا) مثل هذا، مقتبسًا من إجابة زاك.لقد تركت معالجة الأخطاء الفعلية لتحليل البحث الميداني كتمرين للقارئ :)

class PersonQuerySet(models.query.QuerySet):
    def _filter_or_exclude(self, negate, *args, **kwargs):
        cust_lookups = filter(lambda s: s[0].endswith('__within5'), kwargs.items())
        for lookup in cust_lookups:
            kwargs.pop(lookup[0])
            lookup_prefix = lookup[0].rsplit('__',1)[0]
            kwargs.update({lookup_prefix + '__gte':lookup[1]-5,
                           lookup_prefix + '__lt':lookup[1]+5})
        return super(PersonQuerySet, self)._filter_or_exclude(negate, *args, **kwargs)

class PersonManager(models.Manager):
    def get_query_set(self):
         return PersonQuerySet(self.model)

class Person(models.Model):
    age = #...

    objects = PersonManager()

الملاحظات النهائية - من الواضح، إذا كنت تريد ربط عمليات البحث الميدانية المخصصة، فسيكون هذا أمرًا صعبًا للغاية.أيضًا، عادةً ما أكتب هذا بشكل أكثر وظيفية وأستخدم أدوات itertools للأداء، لكنني اعتقدت أنه من الواضح تركه جانبًا.استمتع!

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top