{"title":"How to write custom lookups","version":"6.0","locale":"el","docname":"howto/custom-lookups","url":"/el/6.0/howto/custom-lookups/","canonical":"https://djangodocs.dev/el/6.0/howto/custom-lookups/","summary":"Το Django προσφέρει μια μεγάλη ποικιλία από προεγκατεστημένα lookups για το φιλτράρισμα (π.χ exact και icontains ) των δεδομένων σας από την βάση δεδομένων. Το…","html":"<h1>How to write custom lookups<a class=\"heading-anchor\" href=\"#how-to-write-custom-lookups\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>Το Django προσφέρει μια μεγάλη ποικιλία από <a class=\"reference internal\" href=\"/el/6.0/ref/models/querysets/#field-lookups\"><span class=\"std std-ref\">προεγκατεστημένα lookups</span></a> για το φιλτράρισμα (π.χ <code class=\"docutils literal notranslate\"><span class=\"pre\">exact</span></code> και <code class=\"docutils literal notranslate\"><span class=\"pre\">icontains</span></code>) των δεδομένων σας από την βάση δεδομένων. Το παρών εγχειρίδιο εξηγεί πως να γράψετε δικά σας lookups και πως να αλλάξετε τη συμπεριφορά των ήδη υπαρχουσών lookups. Για την σχετική αναφορά στο API των lookups, δείτε στο άρθρο <a class=\"reference internal\" href=\"/el/6.0/ref/models/lookups/\"><span class=\"doc\">Lookup API reference</span></a>.</p>\n<section id=\"a-lookup-example\">\n<h2>A lookup example<a class=\"heading-anchor\" href=\"#a-lookup-example\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Let’s start with a small custom lookup. We will write a custom lookup <code class=\"docutils literal notranslate\"><span class=\"pre\">ne</span></code>\nwhich works opposite to <code class=\"docutils literal notranslate\"><span class=\"pre\">exact</span></code>. <code class=\"docutils literal notranslate\"><span class=\"pre\">Author.objects.filter(name__ne='Jack')</span></code>\nwill translate to the SQL:</p>\n<div class=\"code-block\" data-language=\"sql\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">SQL</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"SQL code\"><code><span class=\"ss\">&quot;author&quot;</span><span class=\"p\">.</span><span class=\"ss\">&quot;name&quot;</span><span class=\"w\"> </span><span class=\"o\">&lt;&gt;</span><span class=\"w\"> </span><span class=\"s1\">&#39;Jack&#39;</span>\n</code></pre></div>\n<p>Η παραπάνω εντολή SQL είναι ανεξάρτητη από τη βάση δεδομένων που χρησιμοποιείτε, οπότε δεν θα χρειαστεί να ανησυχούμε γι” αυτό. Όλες οι βάσεις καταλαβαίνουν αυτή τη σύνταξη.</p>\n<p>There are two steps to making this work. Firstly we need to implement the\nlookup, then we need to tell Django about it:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.db.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Lookup</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">NotEqual</span><span class=\"p\">(</span><span class=\"n\">Lookup</span><span class=\"p\">):</span>\n    <span class=\"n\">lookup_name</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;ne&quot;</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">as_sql</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">compiler</span><span class=\"p\">,</span> <span class=\"n\">connection</span><span class=\"p\">):</span>\n        <span class=\"n\">lhs</span><span class=\"p\">,</span> <span class=\"n\">lhs_params</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">process_lhs</span><span class=\"p\">(</span><span class=\"n\">compiler</span><span class=\"p\">,</span> <span class=\"n\">connection</span><span class=\"p\">)</span>\n        <span class=\"n\">rhs</span><span class=\"p\">,</span> <span class=\"n\">rhs_params</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">process_rhs</span><span class=\"p\">(</span><span class=\"n\">compiler</span><span class=\"p\">,</span> <span class=\"n\">connection</span><span class=\"p\">)</span>\n        <span class=\"n\">params</span> <span class=\"o\">=</span> <span class=\"n\">lhs_params</span> <span class=\"o\">+</span> <span class=\"n\">rhs_params</span>\n        <span class=\"k\">return</span> <span class=\"s2\">&quot;</span><span class=\"si\">%s</span><span class=\"s2\"> &lt;&gt; </span><span class=\"si\">%s</span><span class=\"s2\">&quot;</span> <span class=\"o\">%</span> <span class=\"p\">(</span><span class=\"n\">lhs</span><span class=\"p\">,</span> <span class=\"n\">rhs</span><span class=\"p\">),</span> <span class=\"n\">params</span>\n</code></pre></div>\n<p>To register the <code class=\"docutils literal notranslate\"><span class=\"pre\">NotEqual</span></code> lookup we will need to call <code class=\"docutils literal notranslate\"><span class=\"pre\">register_lookup</span></code> on\nthe field class we want the lookup to be available for. In this case, the\nlookup makes sense on all <code class=\"docutils literal notranslate\"><span class=\"pre\">Field</span></code> subclasses, so we register it with\n<code class=\"docutils literal notranslate\"><span class=\"pre\">Field</span></code> directly:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.db.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Field</span>\n\n<span class=\"n\">Field</span><span class=\"o\">.</span><span class=\"n\">register_lookup</span><span class=\"p\">(</span><span class=\"n\">NotEqual</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>Το registration του lookup μπορεί να γίνει και με τη χρήση ενός decorator ως εξής:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.db.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Field</span>\n\n\n<span class=\"nd\">@Field</span><span class=\"o\">.</span><span class=\"n\">register_lookup</span>\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">NotEqualLookup</span><span class=\"p\">(</span><span class=\"n\">Lookup</span><span class=\"p\">):</span> <span class=\"o\">...</span>\n</code></pre></div>\n<p>Τώρα μπορούμε να χρησιμοποιήσουμε το <code class=\"docutils literal notranslate\"><span class=\"pre\">foo__ne</span></code> για κάθε τύπο πεδίου του <code class=\"docutils literal notranslate\"><span class=\"pre\">foo</span></code>. Θα χρειαστεί να βεβαιωθείτε ότι το registration του lookup, γίνεται πριν προσπαθήσετε να δημιουργήσετε querysets χρησιμοποιώντας το. Θα μπορούσατε να τοποθετήσετε τον παραπάνω κώδικα μέσα στο αρχείο <code class=\"docutils literal notranslate\"><span class=\"pre\">models.py</span></code> ή να κάνετε register το lookup μέσα στη μέθοδο <code class=\"docutils literal notranslate\"><span class=\"pre\">ready()</span></code> στο αντίστοιχο <code class=\"docutils literal notranslate\"><span class=\"pre\">AppConfig</span></code> της εφαρμογής σας.</p>\n<p>Ρίχνοντας μια πιο προσεκτική ματιά στην υλοποίηση αυτού του lookup, το πρώτο απαραίτητο attribute που χρειάζεται είναι το <code class=\"docutils literal notranslate\"><span class=\"pre\">lookup_name</span></code>. Αυτό επιτρέπει στο Django ORM να καταλάβει πως να μεταφράσει το <code class=\"docutils literal notranslate\"><span class=\"pre\">name__ne</span></code> και να χρησιμοποιήσει την κλάση <code class=\"docutils literal notranslate\"><span class=\"pre\">NotEqual</span></code> για να παράξει την SQL. Συμβατικά, αυτά τα ονόματα είναι πάντα πεζοί χαρακτήρες (μόνο γράμματα) και η μοναδική αυστηρή απαίτηση είναι να μην περιέχουν δύο συνεχόμενες κάτω παύλες, <code class=\"docutils literal notranslate\"><span class=\"pre\">__</span></code>.</p>\n<p>Έπειτα χρειάζεται να ορίσουμε την μέθοδο <code class=\"docutils literal notranslate\"><span class=\"pre\">as_sql</span></code>. Αυτή δέχεται ως όρισμα ένα <code class=\"docutils literal notranslate\"><span class=\"pre\">SQLCompiler</span></code> object, με το όνομα <code class=\"docutils literal notranslate\"><span class=\"pre\">compiler</span></code> και την ενεργή σύνδεση της βάσης δεδομένων με το όνομα <code class=\"docutils literal notranslate\"><span class=\"pre\">connection</span></code>. Τα <code class=\"docutils literal notranslate\"><span class=\"pre\">SQLCompiler</span></code> objects δεν βρίσκονται κάπου γραμμένα στο εγχειρίδιο του Django αλλά το μόνο πράγμα που χρειάζεται να ξέρετε γι” αυτά είναι ότι έχουν μια μέθοδο <code class=\"docutils literal notranslate\"><span class=\"pre\">compile()</span></code> η οποία επιστρέφει ένα tuple που περιέχει ένα SQL string και κάποιες παραμέτρους οι οποίες “γεμίζουν” αυτό το SQL string. Στις περισσότερες περιπτώσεις δεν θα χρειαστεί να την χρησιμοποιήσετε και μπορείτε να συνεχίσετε με τις μεθόδους <code class=\"docutils literal notranslate\"><span class=\"pre\">process_lhs()</span></code> και <code class=\"docutils literal notranslate\"><span class=\"pre\">process_rhs()</span></code>.</p>\n<p>Ένα <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code> συνεργάζεται με δύο τιμές, την <code class=\"docutils literal notranslate\"><span class=\"pre\">lhs</span></code> και την <code class=\"docutils literal notranslate\"><span class=\"pre\">rhs</span></code>, οι οποίες είναι σύντμηση των λέξεων left-hand side (αριστερό μέρος) και right-hand side (δεξί μέρος). Το αριστερό μέρος αναφέρεται συνήθως σε κάποιο πεδίο αλλά μπορεί να είναι οτιδήποτε αρκεί να έχει υλοποιήσει το <a class=\"reference internal\" href=\"/el/6.0/ref/models/lookups/#query-expression\"><span class=\"std std-ref\">API για εκφράσεις ερωτημάτων</span></a>. Το δεξί μέρος είναι η τιμή η οποία δίνεται από τον χρήστη. Στο παράδειγμα <code class=\"docutils literal notranslate\"><span class=\"pre\">Author.objects.filter(name__ne='Jack')</span></code>, το αριστερό μέρος αναφέρεται στο πεδίο <code class=\"docutils literal notranslate\"><span class=\"pre\">name</span></code> του μοντέλου <code class=\"docutils literal notranslate\"><span class=\"pre\">Author</span></code> και το string <code class=\"docutils literal notranslate\"><span class=\"pre\">'Jack'</span></code> αποτελεί το δεξί μέρος.</p>\n<p>Καλούμε την <code class=\"docutils literal notranslate\"><span class=\"pre\">process_lhs</span></code> και την <code class=\"docutils literal notranslate\"><span class=\"pre\">process_rhs</span></code> για να μετατρέψουμε το <code class=\"docutils literal notranslate\"><span class=\"pre\">Author.objects.filter(name__ne='Jack')</span></code> στις τιμές που χρειαζόμαστε για την SQL χρησιμοποιώντας το <code class=\"docutils literal notranslate\"><span class=\"pre\">compiler</span></code> object που περιγράψαμε παραπάνω. Αυτές οι μέθοδοι επιστρέφουν tuples που περιέχουν λίγη SQL και κάποιες παραμέτρους που θα “γεμίσουν” αυτή την SQL. Ότι ακριβώς χρειαζόμαστε για να επιστρέψει η μέθοδος <code class=\"docutils literal notranslate\"><span class=\"pre\">as_sql</span></code>. Στο παραπάνω παράδειγμα, η <code class=\"docutils literal notranslate\"><span class=\"pre\">process_lhs</span></code> επιστρέφει <code class=\"docutils literal notranslate\"><span class=\"pre\">('&quot;author&quot;.&quot;name&quot;',</span> <span class=\"pre\">[])</span></code> και η <code class=\"docutils literal notranslate\"><span class=\"pre\">process_rhs</span></code> επιστρέφει <code class=\"docutils literal notranslate\"><span class=\"pre\">('&quot;%s&quot;',</span> <span class=\"pre\">['Jack'])</span></code>. Όπως θα είδατε, δεν υπάρχουν παράμετροι για το αριστερό μέρος, αλλά αυτό εξαρτάται από την περίπτωση. Όπως και να έχει πάντως, θα πρέπει πάντα να περιλαμβάνονται στο τελικό tuple προς επιστροφή (η μεταβλητή <code class=\"docutils literal notranslate\"><span class=\"pre\">params</span></code> στην <code class=\"docutils literal notranslate\"><span class=\"pre\">as_sql</span></code>).</p>\n<p>Στο τέλος ενώνουμε τα μέρη σε μια SQL εντολή με τη χρήση του <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;&gt;</span></code> και παρέχουμε όλες τις παραμέτρους για το query (ερώτημα). Αυτό που επιστρέφουμε είναι ένα tuple που περιέχει την παραγόμενη SQL εντολή και τις παραμέτρους, κενές ή όχι. Το tuple που θα επιστραφεί, αναφερόμενοι στην ανωτέρω <code class=\"docutils literal notranslate\"><span class=\"pre\">as_sql</span></code>, είναι το <code class=\"docutils literal notranslate\"><span class=\"pre\">('&quot;author&quot;.&quot;name&quot;</span> <span class=\"pre\">&lt;&gt;</span> <span class=\"pre\">&quot;%s&quot;',</span> <span class=\"pre\">['Jack'])</span></code>.</p>\n</section>\n<section id=\"a-transformer-example\">\n<h2>A transformer example<a class=\"heading-anchor\" href=\"#a-transformer-example\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Το παραπάνω lookup που φτιάξαμε είναι ωραίο, αλλά σε αρκετές περιπτώσεις θα θέλετε να έχετε τη δυνατότητα να ενώνετε τα lookups μεταξύ τους. Για παράδειγμα, ας υποθέσουμε ότι χτίζουμε μια εφαρμογή όπου θέλουμε να κάνουμε χρήση της μεθόδου <code class=\"docutils literal notranslate\"><span class=\"pre\">abs()</span></code>, που επιστρέφει το απόλυτο ενός αριθμού. Έχουμε ένα μοντέλο με το όνομα <code class=\"docutils literal notranslate\"><span class=\"pre\">Experiment</span></code> το οποίο καταγράφει μια τιμή έναρξης (start), μια τέλους (end) και την αλλαγή (αρχή – τέλος). Θα θέλαμε να βρούμε όλα τα πειράματα (experiments) όπου η αλλαγή ήταν ίση με μια συγκεκριμένη τιμή (<code class=\"docutils literal notranslate\"><span class=\"pre\">Experiment.objects.filter(change__abs=27)</span></code>) ή η αλλαγή ήταν μικρότερη ή ίση μιας συγκεκριμένης τιμής (<code class=\"docutils literal notranslate\"><span class=\"pre\">Experiment.objects.filter(change__abs__lt=27)</span></code>). Εδώ βλέπετε τη σύνδεση μεταξύ των lookups που αναφέραμε πριν (<code class=\"docutils literal notranslate\"><span class=\"pre\">abs__lt</span></code>).</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Σημείωση</p>\n<p>Αυτό το παράδειγμα είναι λίγο πολύ σκηνοθετημένο αλλά επιδεικνύει όμορφα τις  λειτουργίες που είναι δυνατόν να υλοποιηθούν χωρίς την εξάρτηση πάνω σε μια συγκεκριμένη βάση δεδομένων και χωρίς να ξαναγράφουμε κώδικα που υπάρχει ήδη στο Django.</p>\n</aside>\n<p>We will start by writing an <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValue</span></code> transformer. This will use the\nSQL function <code class=\"docutils literal notranslate\"><span class=\"pre\">ABS()</span></code> to transform the value before comparison:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.db.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Transform</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">AbsoluteValue</span><span class=\"p\">(</span><span class=\"n\">Transform</span><span class=\"p\">):</span>\n    <span class=\"n\">lookup_name</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;abs&quot;</span>\n    <span class=\"n\">function</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;ABS&quot;</span>\n</code></pre></div>\n<p>Επόμενο βήμα είναι κάνουμε register την κλάση μας με το πεδίο <code class=\"docutils literal notranslate\"><span class=\"pre\">IntegerField</span></code>:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.db.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">IntegerField</span>\n\n<span class=\"n\">IntegerField</span><span class=\"o\">.</span><span class=\"n\">register_lookup</span><span class=\"p\">(</span><span class=\"n\">AbsoluteValue</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>We can now run the queries we had before.\n<code class=\"docutils literal notranslate\"><span class=\"pre\">Experiment.objects.filter(change__abs=27)</span></code> will generate the following SQL:</p>\n<div class=\"code-block\" data-language=\"sql\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">SQL</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"SQL code\"><code><span class=\"k\">SELECT</span><span class=\"w\"> </span><span class=\"p\">...</span><span class=\"w\"> </span><span class=\"k\">WHERE</span><span class=\"w\"> </span><span class=\"k\">ABS</span><span class=\"p\">(</span><span class=\"ss\">&quot;experiments&quot;</span><span class=\"p\">.</span><span class=\"ss\">&quot;change&quot;</span><span class=\"p\">)</span><span class=\"w\"> </span><span class=\"o\">=</span><span class=\"w\"> </span><span class=\"mi\">27</span>\n</code></pre></div>\n<p>By using <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code> instead of <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code> it means we are able to chain\nfurther lookups afterward. So\n<code class=\"docutils literal notranslate\"><span class=\"pre\">Experiment.objects.filter(change__abs__lt=27)</span></code> will generate the following\nSQL:</p>\n<div class=\"code-block\" data-language=\"sql\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">SQL</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"SQL code\"><code><span class=\"k\">SELECT</span><span class=\"w\"> </span><span class=\"p\">...</span><span class=\"w\"> </span><span class=\"k\">WHERE</span><span class=\"w\"> </span><span class=\"k\">ABS</span><span class=\"p\">(</span><span class=\"ss\">&quot;experiments&quot;</span><span class=\"p\">.</span><span class=\"ss\">&quot;change&quot;</span><span class=\"p\">)</span><span class=\"w\"> </span><span class=\"o\">&lt;</span><span class=\"w\"> </span><span class=\"mi\">27</span>\n</code></pre></div>\n<p>Σημειώστε ότι στην περίπτωση που δεν υπάρχει άλλο lookup στο τέλος, το Django μεταφράζει το <code class=\"docutils literal notranslate\"><span class=\"pre\">change__abs=27</span></code> ως <code class=\"docutils literal notranslate\"><span class=\"pre\">change__abs__exact=27</span></code>.</p>\n<p>This also allows the result to be used in <code class=\"docutils literal notranslate\"><span class=\"pre\">ORDER</span> <span class=\"pre\">BY</span></code> and <code class=\"docutils literal notranslate\"><span class=\"pre\">DISTINCT</span> <span class=\"pre\">ON</span></code>\nclauses. For example <code class=\"docutils literal notranslate\"><span class=\"pre\">Experiment.objects.order_by('change__abs')</span></code> generates:</p>\n<div class=\"code-block\" data-language=\"sql\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">SQL</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"SQL code\"><code><span class=\"k\">SELECT</span><span class=\"w\"> </span><span class=\"p\">...</span><span class=\"w\"> </span><span class=\"k\">ORDER</span><span class=\"w\"> </span><span class=\"k\">BY</span><span class=\"w\"> </span><span class=\"k\">ABS</span><span class=\"p\">(</span><span class=\"ss\">&quot;experiments&quot;</span><span class=\"p\">.</span><span class=\"ss\">&quot;change&quot;</span><span class=\"p\">)</span><span class=\"w\"> </span><span class=\"k\">ASC</span>\n</code></pre></div>\n<p>And on databases that support distinct on fields (such as PostgreSQL),\n<code class=\"docutils literal notranslate\"><span class=\"pre\">Experiment.objects.distinct('change__abs')</span></code> generates:</p>\n<div class=\"code-block\" data-language=\"sql\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">SQL</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"SQL code\"><code><span class=\"k\">SELECT</span><span class=\"w\"> </span><span class=\"p\">...</span><span class=\"w\"> </span><span class=\"k\">DISTINCT</span><span class=\"w\"> </span><span class=\"k\">ON</span><span class=\"w\"> </span><span class=\"k\">ABS</span><span class=\"p\">(</span><span class=\"ss\">&quot;experiments&quot;</span><span class=\"p\">.</span><span class=\"ss\">&quot;change&quot;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>Για να βρει το Django τον τύπο των lookups που επιτρέπονται μετά το δικό μας (<code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValue</span></code>), κοιτάζει το attribute <code class=\"docutils literal notranslate\"><span class=\"pre\">output_field</span></code> το οποίο δεν χρειάστηκε να το ορίσουμε στο συγκεκριμένο παράδειγμα γιατί έτυχε ο αριθμός που συγκρίνουμε, στο δεξί μέρος, να είναι ακέραιος (27). Αν μπερδευτήκατε, ας το ξεκαθαρίσουμε: Η <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code> προσφέρει τη μετατροπή ενός πεδίου (πχ του <code class=\"docutils literal notranslate\"><span class=\"pre\">change</span></code>) σε κάποια άλλη τιμή (πχ από -27 που μπορεί να ήταν, σε 27) προτού συγκριθεί με το δεξί μέρος και γίνει το lookup στη βάση δεδομένων. Ο τύπος της νέας αυτής τιμής (πχ 27 αντί -27) δηλώνεται στο <code class=\"docutils literal notranslate\"><span class=\"pre\">output_field</span></code> του δικού μας <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValue</span> <span class=\"pre\">``.</span> <span class=\"pre\">Δεν</span> <span class=\"pre\">το</span> <span class=\"pre\">δηλώσαμε</span> <span class=\"pre\">γιατί</span> <span class=\"pre\">και</span> <span class=\"pre\">οι</span> <span class=\"pre\">δύο</span> <span class=\"pre\">τιμές</span> <span class=\"pre\">είναι</span> <span class=\"pre\">τύπου</span> <span class=\"pre\">int.</span> <span class=\"pre\">Αν</span> <span class=\"pre\">υποθέσουμε</span> <span class=\"pre\">όμως</span> <span class=\"pre\">ότι</span> <span class=\"pre\">έχουμε</span> <span class=\"pre\">πιο</span> <span class=\"pre\">περίπλοκα</span> <span class=\"pre\">πεδία</span> <span class=\"pre\">(πχ</span> <span class=\"pre\">καρτεσιανές</span> <span class=\"pre\">συντεταγμένες</span> <span class=\"pre\">ή</span> <span class=\"pre\">μιγαδικούς</span> <span class=\"pre\">αριθμούς)</span> <span class=\"pre\">τότε</span> <span class=\"pre\">ίσως</span> <span class=\"pre\">θα</span> <span class=\"pre\">θέλαμε</span> <span class=\"pre\">να</span> <span class=\"pre\">προσδιορίσουμε</span> <span class=\"pre\">τον</span> <span class=\"pre\">τύπο</span> <span class=\"pre\">της</span> <span class=\"pre\">νέας</span> <span class=\"pre\">τιμής</span> <span class=\"pre\">ως</span> <span class=\"pre\">``FloatField</span></code> για περαιτέρω lookups. Αυτό μπορεί να γίνει θέτοντας το attribute `` output_field`` ως property της δικής μας κλάσης, ως εξής:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.db.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">FloatField</span><span class=\"p\">,</span> <span class=\"n\">Transform</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">AbsoluteValue</span><span class=\"p\">(</span><span class=\"n\">Transform</span><span class=\"p\">):</span>\n    <span class=\"n\">lookup_name</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;abs&quot;</span>\n    <span class=\"n\">function</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;ABS&quot;</span>\n\n    <span class=\"nd\">@property</span>\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">output_field</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">FloatField</span><span class=\"p\">()</span>\n</code></pre></div>\n<p>Με αυτό τον τρόπο είμαστε σίγουροι ότι το δικό μας transformation θα επιστρέψει μια τιμή τύπου float και τα επόμενα lookups (αν υπάρχουν, πχ το lte στο <code class=\"docutils literal notranslate\"><span class=\"pre\">abs__lte</span></code>) θα “δουν” την τιμή αυτή ως float και όχι ως int όπως ήταν στην αρχή. Ένα άλλο πολύ κοινό παράδειγμα της <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code> είναι η μετατροπή ενός <code class=\"docutils literal notranslate\"><span class=\"pre\">DateField</span></code> στην τιμή του έτους μόνο. Για παράδειγμα, θα θέλατε να δείτε ποια πειράματα έγιναν το έτος 2016. Θα θέλατε να το γράψετε ως εξής: <code class=\"docutils literal notranslate\"><span class=\"pre\">Experiment.objects.filter(date__year=2016)</span></code>. Το <code class=\"docutils literal notranslate\"><span class=\"pre\">date</span></code> είναι το πεδίο του μοντέλου μας, τύπου <code class=\"docutils literal notranslate\"><span class=\"pre\">DateField</span></code> και το <code class=\"docutils literal notranslate\"><span class=\"pre\">year</span></code> το lookup (που υπάρχει ήδη μέσα στο Django). Το <code class=\"docutils literal notranslate\"><span class=\"pre\">year</span></code> lookup “ξηλώνει” μόνο το έτος από την ημερομηνία και το συγκρίνει με το 2016. Έτσι, μετατρέπεται η ημερομηνία (<code class=\"docutils literal notranslate\"><span class=\"pre\">DateField</span></code>) σε έτος (<code class=\"docutils literal notranslate\"><span class=\"pre\">IntegerField</span></code>) και συγκρίνεται με το δεξί μέρος.</p>\n</section>\n<section id=\"writing-an-efficient-abs-lt-lookup\">\n<h2>Γράφοντας ένα πιο αποτελεσματικό <code class=\"docutils literal notranslate\"><span class=\"pre\">abs__lt</span></code> lookup<a class=\"heading-anchor\" href=\"#writing-an-efficient-abs-lt-lookup\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Όταν χρησιμοποιούμε το παραπάνω <code class=\"docutils literal notranslate\"><span class=\"pre\">abs</span></code> lookup, η παραγόμενη SQL, σε μερικές περιπτώσεις, δεν χρησιμοποιεί αποτελεσματικά τα ευρετήρια (indexes) της βάσης δεδομένων. Πιο συγκεκριμένα, όταν χρησιμοποιούμε το <code class=\"docutils literal notranslate\"><span class=\"pre\">change__abs__lt=27</span></code>, αυτό είναι ισοδύναμο με το <code class=\"docutils literal notranslate\"><span class=\"pre\">change__gt=-27</span></code> AND <code class=\"docutils literal notranslate\"><span class=\"pre\">change__lt=27</span></code>. (Στη περίπτωση του <code class=\"docutils literal notranslate\"><span class=\"pre\">lte</span></code> θα μπορούσαμε να χρησιμοποιήσουμε την εντολή SQL <code class=\"docutils literal notranslate\"><span class=\"pre\">BETWEEN</span></code>).</p>\n<p>So we would like <code class=\"docutils literal notranslate\"><span class=\"pre\">Experiment.objects.filter(change__abs__lt=27)</span></code> to generate\nthe following SQL:</p>\n<div class=\"code-block\" data-language=\"sql\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">SQL</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"SQL code\"><code><span class=\"k\">SELECT</span><span class=\"w\"> </span><span class=\"p\">..</span><span class=\"w\"> </span><span class=\"k\">WHERE</span><span class=\"w\"> </span><span class=\"ss\">&quot;experiments&quot;</span><span class=\"p\">.</span><span class=\"ss\">&quot;change&quot;</span><span class=\"w\"> </span><span class=\"o\">&lt;</span><span class=\"w\"> </span><span class=\"mi\">27</span><span class=\"w\"> </span><span class=\"k\">AND</span><span class=\"w\"> </span><span class=\"ss\">&quot;experiments&quot;</span><span class=\"p\">.</span><span class=\"ss\">&quot;change&quot;</span><span class=\"w\"> </span><span class=\"o\">&gt;</span><span class=\"w\"> </span><span class=\"o\">-</span><span class=\"mi\">27</span>\n</code></pre></div>\n<p>Η υλοποίηση αυτού φαίνεται παρακάτω:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.db.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Lookup</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">AbsoluteValueLessThan</span><span class=\"p\">(</span><span class=\"n\">Lookup</span><span class=\"p\">):</span>\n    <span class=\"n\">lookup_name</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;lt&quot;</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">as_sql</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">compiler</span><span class=\"p\">,</span> <span class=\"n\">connection</span><span class=\"p\">):</span>\n        <span class=\"n\">lhs</span><span class=\"p\">,</span> <span class=\"n\">lhs_params</span> <span class=\"o\">=</span> <span class=\"n\">compiler</span><span class=\"o\">.</span><span class=\"n\">compile</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">lhs</span><span class=\"o\">.</span><span class=\"n\">lhs</span><span class=\"p\">)</span>\n        <span class=\"n\">rhs</span><span class=\"p\">,</span> <span class=\"n\">rhs_params</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">process_rhs</span><span class=\"p\">(</span><span class=\"n\">compiler</span><span class=\"p\">,</span> <span class=\"n\">connection</span><span class=\"p\">)</span>\n        <span class=\"n\">params</span> <span class=\"o\">=</span> <span class=\"n\">lhs_params</span> <span class=\"o\">+</span> <span class=\"n\">rhs_params</span> <span class=\"o\">+</span> <span class=\"n\">lhs_params</span> <span class=\"o\">+</span> <span class=\"n\">rhs_params</span>\n        <span class=\"k\">return</span> <span class=\"s2\">&quot;</span><span class=\"si\">%s</span><span class=\"s2\"> &lt; </span><span class=\"si\">%s</span><span class=\"s2\"> AND </span><span class=\"si\">%s</span><span class=\"s2\"> &gt; -</span><span class=\"si\">%s</span><span class=\"s2\">&quot;</span> <span class=\"o\">%</span> <span class=\"p\">(</span><span class=\"n\">lhs</span><span class=\"p\">,</span> <span class=\"n\">rhs</span><span class=\"p\">,</span> <span class=\"n\">lhs</span><span class=\"p\">,</span> <span class=\"n\">rhs</span><span class=\"p\">),</span> <span class=\"n\">params</span>\n\n\n<span class=\"n\">AbsoluteValue</span><span class=\"o\">.</span><span class=\"n\">register_lookup</span><span class=\"p\">(</span><span class=\"n\">AbsoluteValueLessThan</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>Υπάρχουν μερικά αξιοσημείωτα πράγματα εδώ. Πρώτα απ’ όλα το <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValueLessThan</span></code> δεν καλεί τη μέθοδο <code class=\"docutils literal notranslate\"><span class=\"pre\">process_lhs()</span></code>. Αντιθέτως, υπερπηδά τη μετατροπή του <code class=\"docutils literal notranslate\"><span class=\"pre\">lhs</span></code> που γίνεται από την <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValue</span></code> και χρησιμοποιεί την αρχική τιμή του <code class=\"docutils literal notranslate\"><span class=\"pre\">lhs</span></code> (το <code class=\"docutils literal notranslate\"><span class=\"pre\">self.lhs</span></code> είναι η τιμή μετά την μετατροπή ενώ το <code class=\"docutils literal notranslate\"><span class=\"pre\">self.lhs.lhs</span></code> είναι η αρχική τιμή του <code class=\"docutils literal notranslate\"><span class=\"pre\">change</span></code>). Αυτό γίνεται γιατί θέλουμε να έχουμε το <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;experiments&quot;.&quot;change&quot;</span></code> και όχι το <code class=\"docutils literal notranslate\"><span class=\"pre\">ABS(&quot;experiments&quot;.&quot;change&quot;)</span></code>. Είναι ασφαλής η αναφορά μας απ’ ευθείας στο <code class=\"docutils literal notranslate\"><span class=\"pre\">self.lhs.lhs</span></code> γιατί η <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code> κλάση <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValueLessThan</span></code> μπορεί να προσπελασθεί μόνο από την <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code> κλάση <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValue</span></code> (λόγω του register στην τελευταία γραμμή), δηλαδή το <code class=\"docutils literal notranslate\"><span class=\"pre\">lhs</span></code> θα είναι πάντα ένα instance της Transform κλάσης <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValue</span></code>.</p>\n<p>Επισημαίνεται επίσης το γεγονός ότι όχι μόνο και τα δύο μέρη (αριστερό και δεξί) χρησιμοποιούνται πολλές φορές μέσα στο SQL query αλλά και οι παράμετροι επίσης (<code class=\"docutils literal notranslate\"><span class=\"pre\">lhs_params</span></code> και <code class=\"docutils literal notranslate\"><span class=\"pre\">rhs_params</span></code>).</p>\n<p>Ο λόγος που γίνεται αυτό είναι γιατί, σε περίπτωση που το <code class=\"docutils literal notranslate\"><span class=\"pre\">self.rhs</span></code> είναι κάτι διαφορετικό από έναν ακέραιο (πχ μια αναφορά σε ένα <code class=\"docutils literal notranslate\"><span class=\"pre\">F()</span></code>) δε θα μπορούμε να κάνουμε τις μετατροπές στην Python.</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Σημείωση</p>\n<p>Στην πραγματικότητα, τα περισσότερα lookups που εμπεριέχουν το <code class=\"docutils literal notranslate\"><span class=\"pre\">__abs</span></code> θα μπορούσαν να υλοποιηθούν με την παραπάνω μέθοδο και στις περισσότερες βάσεις δεδομένων θα μπορέσετε να εκμεταλλευτείτε τη δυνατότητα των ευρετηρίων (indexes) τους. Ωστόσο, στην PostgreSQL ίσως θα θέλατε να προσθέσετε ένα ευρετήριο για το <code class=\"docutils literal notranslate\"><span class=\"pre\">abs(change)</span></code> το οποίο θα επιτρέψει σε αυτά τα queries να είναι πολύ αποτελεσματικά.</p>\n</aside>\n</section>\n<section id=\"a-bilateral-transformer-example\">\n<h2>Ένα παράδειγμα ενός διμερούς transformer<a class=\"heading-anchor\" href=\"#a-bilateral-transformer-example\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Το παράδειγμα της <code class=\"docutils literal notranslate\"><span class=\"pre\">Transformer</span></code> κλάσης <code class=\"docutils literal notranslate\"><span class=\"pre\">AbsoluteValue</span></code> που περιγράψαμε παραπάνω είναι μια μετατροπή η οποία εφαρμόζεται στο αριστερό μέρος του lookup (στο πεδίο <code class=\"docutils literal notranslate\"><span class=\"pre\">change</span></code>). Ίσως να υπάρξουν, μερικές περιπτώσεις όπου θα θέλατε η μετατροπή να εφαρμοστεί και στο αριστερό και στο δεξί μέρος. Για παράδειγμα, αν θέλετε να φιλτράρετε ένα queryset βασιζόμενο στην ισότητα των δύο μερών (αριστερό και δεξί) με την χρήση κάποιας SQL συνάρτησης.</p>\n<p>Let’s examine case-insensitive transformations here. This transformation isn’t\nvery useful in practice as Django already comes with a bunch of built-in\ncase-insensitive lookups, but it will be a nice demonstration of bilateral\ntransformations in a database-agnostic way.</p>\n<p>Ορίζουμε έναν transformer <code class=\"docutils literal notranslate\"><span class=\"pre\">UpperCase</span></code> ο οποίος χρησιμοποιεί την SQL συνάρτηση <code class=\"docutils literal notranslate\"><span class=\"pre\">UPPER()</span></code> για να μετατρέψει τις τιμές πριν την σύγκριση. Θέτουμε το attribute <a class=\"reference internal\" href=\"/el/6.0/ref/models/lookups/#django.db.models.Transform.bilateral\" title=\"django.db.models.Transform.bilateral\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">bilateral</span> <span class=\"pre\">=</span> <span class=\"pre\">True</span></code></a> για να υποδείξουμε ότι η μετατροπή θα πρέπει να γίνει όχι μόνο στο αριστερό μέρος, <code class=\"docutils literal notranslate\"><span class=\"pre\">lhs</span></code>, αλλά και στο δεξί, <code class=\"docutils literal notranslate\"><span class=\"pre\">rhs</span></code>:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.db.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Transform</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">UpperCase</span><span class=\"p\">(</span><span class=\"n\">Transform</span><span class=\"p\">):</span>\n    <span class=\"n\">lookup_name</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;upper&quot;</span>\n    <span class=\"n\">function</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;UPPER&quot;</span>\n    <span class=\"n\">bilateral</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n</code></pre></div>\n<p>Έπειτα το κάνουμε register με τους ανάλογους τύπους πεδίων:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.db.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">CharField</span><span class=\"p\">,</span> <span class=\"n\">TextField</span>\n\n<span class=\"n\">CharField</span><span class=\"o\">.</span><span class=\"n\">register_lookup</span><span class=\"p\">(</span><span class=\"n\">UpperCase</span><span class=\"p\">)</span>\n<span class=\"n\">TextField</span><span class=\"o\">.</span><span class=\"n\">register_lookup</span><span class=\"p\">(</span><span class=\"n\">UpperCase</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>Now, the queryset <code class=\"docutils literal notranslate\"><span class=\"pre\">Author.objects.filter(name__upper=&quot;doe&quot;)</span></code> will generate a\ncase insensitive query like this:</p>\n<div class=\"code-block\" data-language=\"sql\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">SQL</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"SQL code\"><code><span class=\"k\">SELECT</span><span class=\"w\"> </span><span class=\"p\">...</span><span class=\"w\"> </span><span class=\"k\">WHERE</span><span class=\"w\"> </span><span class=\"k\">UPPER</span><span class=\"p\">(</span><span class=\"ss\">&quot;author&quot;</span><span class=\"p\">.</span><span class=\"ss\">&quot;name&quot;</span><span class=\"p\">)</span><span class=\"w\"> </span><span class=\"o\">=</span><span class=\"w\"> </span><span class=\"k\">UPPER</span><span class=\"p\">(</span><span class=\"s1\">&#39;doe&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n</section>\n<section id=\"writing-alternative-implementations-for-existing-lookups\">\n<h2>Γράφοντας εναλλακτικές υλοποιήσεις για ήδη υπάρχοντα lookups<a class=\"heading-anchor\" href=\"#writing-alternative-implementations-for-existing-lookups\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Κάποιες φορές, μερικές βάσεις δεδομένων απαιτούν έναν διαφορετικό τρόπο γραφής της SQL για την ίδια λειτουργία. Για παράδειγμα, κάποιες βάσεις για να προσδιορίσουν τη λογική «όχι ίσο με», αντί του συμβόλου <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;&gt;</span></code> απαιτούν το <code class=\"docutils literal notranslate\"><span class=\"pre\">!=</span></code>. (Στην πραγματικότητα σχεδόν όλες οι βάσεις δεδομένων υποστηρίζουν και τα δύο αυτά σύμβολα, συμπεριλαμβανομένων και όλων των επίσημων βάσεων δεδομένων που υποστηρίζει το Django). Σε αυτό το παράδειγμα θα ξαναγράψουμε μια δικιά μας υλοποίηση, για την MySQL, της λειτουργίας NotEqual.</p>\n<p>We can change the behavior on a specific backend by creating a subclass of\n<code class=\"docutils literal notranslate\"><span class=\"pre\">NotEqual</span></code> with an <code class=\"docutils literal notranslate\"><span class=\"pre\">as_mysql</span></code> method:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">MySQLNotEqual</span><span class=\"p\">(</span><span class=\"n\">NotEqual</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">as_mysql</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">compiler</span><span class=\"p\">,</span> <span class=\"n\">connection</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">extra_context</span><span class=\"p\">):</span>\n        <span class=\"n\">lhs</span><span class=\"p\">,</span> <span class=\"n\">lhs_params</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">process_lhs</span><span class=\"p\">(</span><span class=\"n\">compiler</span><span class=\"p\">,</span> <span class=\"n\">connection</span><span class=\"p\">)</span>\n        <span class=\"n\">rhs</span><span class=\"p\">,</span> <span class=\"n\">rhs_params</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">process_rhs</span><span class=\"p\">(</span><span class=\"n\">compiler</span><span class=\"p\">,</span> <span class=\"n\">connection</span><span class=\"p\">)</span>\n        <span class=\"n\">params</span> <span class=\"o\">=</span> <span class=\"n\">lhs_params</span> <span class=\"o\">+</span> <span class=\"n\">rhs_params</span>\n        <span class=\"k\">return</span> <span class=\"s2\">&quot;</span><span class=\"si\">%s</span><span class=\"s2\"> != </span><span class=\"si\">%s</span><span class=\"s2\">&quot;</span> <span class=\"o\">%</span> <span class=\"p\">(</span><span class=\"n\">lhs</span><span class=\"p\">,</span> <span class=\"n\">rhs</span><span class=\"p\">),</span> <span class=\"n\">params</span>\n\n\n<span class=\"n\">Field</span><span class=\"o\">.</span><span class=\"n\">register_lookup</span><span class=\"p\">(</span><span class=\"n\">MySQLNotEqual</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>Μπορούμε, έπειτα, να κάνουμε register την κλάση αυτή με το <code class=\"docutils literal notranslate\"><span class=\"pre\">Field</span></code>. Η κλάση <code class=\"docutils literal notranslate\"><span class=\"pre\">MySQLNotEqual</span></code> αντικαθιστά την κλάση <code class=\"docutils literal notranslate\"><span class=\"pre\">NotEqual</span></code>, μόνο για τις MySQL βάσεις δεδομένων, αφού μοιράζονται το ίδιο <code class=\"docutils literal notranslate\"><span class=\"pre\">lookup_name</span></code>.</p>\n<p>Κατά τη διάρκεια μετάφρασης του query, το Django ψάχνει για τις μεθόδους``as_%s % connection.vendor`` και αν δεν βρει κάποια τότε χρησιμοποιεί την <code class=\"docutils literal notranslate\"><span class=\"pre\">as_sql</span></code>. Τα ονόματα των vendor για τις προεγκατεστημένες στο Django database backends είναι τα <code class=\"docutils literal notranslate\"><span class=\"pre\">sqlite</span></code>, <code class=\"docutils literal notranslate\"><span class=\"pre\">postgresql</span></code>, <code class=\"docutils literal notranslate\"><span class=\"pre\">oracle</span></code> και <code class=\"docutils literal notranslate\"><span class=\"pre\">mysql</span></code>.</p>\n</section>\n<section id=\"how-django-determines-the-lookups-and-transforms-which-are-used\">\n<h2>Πως προσδιορίζει το Django τα lookups και τα transforms που χρησιμοποιούνται<a class=\"heading-anchor\" href=\"#how-django-determines-the-lookups-and-transforms-which-are-used\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Σε μερικές περιπτώσεις θα θέλατε να αλλάξετε, δυναμικά, το <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code> ή το <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code> που επιστρέφεται ανάλογα το όνομα που δίνεται στο query παρά να μπείτε στη διαδικασία να φτιάξετε ένα για το καθένα. Θα μπορούσατε, για παράδειγμα, να έχετε ένα πεδίο το οποίο αποθηκεύει συντεταγμένες ή κάποια αυθαίρετη διάσταση και θέλετε να μπορείτε να γράφετε το <code class=\"docutils literal notranslate\"><span class=\"pre\">.filter(coords__x7=4)</span></code> και να σας επιστρέφει τα objects όπου η 7η συντεταγμένη έχει την τιμή 4. Για να το κάνετε αυτό, θα πρέπει να παρακάμψετε (override) την <code class=\"docutils literal notranslate\"><span class=\"pre\">get_lookup</span></code> με κάτι σαν αυτό:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">CoordinatesField</span><span class=\"p\">(</span><span class=\"n\">Field</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">get_lookup</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">lookup_name</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"n\">lookup_name</span><span class=\"o\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s2\">&quot;x&quot;</span><span class=\"p\">):</span>\n            <span class=\"k\">try</span><span class=\"p\">:</span>\n                <span class=\"n\">dimension</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">lookup_name</span><span class=\"o\">.</span><span class=\"n\">removeprefix</span><span class=\"p\">(</span><span class=\"s2\">&quot;x&quot;</span><span class=\"p\">))</span>\n            <span class=\"k\">except</span> <span class=\"ne\">ValueError</span><span class=\"p\">:</span>\n                <span class=\"k\">pass</span>\n            <span class=\"k\">else</span><span class=\"p\">:</span>\n                <span class=\"k\">return</span> <span class=\"n\">get_coordinate_lookup</span><span class=\"p\">(</span><span class=\"n\">dimension</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">get_lookup</span><span class=\"p\">(</span><span class=\"n\">lookup_name</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>Μετά θα ορίσετε τη μέθοδο <code class=\"docutils literal notranslate\"><span class=\"pre\">get_coordinate_lookup</span></code>, καταλλήλως, για να επιστρέφει μια subclass της <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code> η οποία θα χειριστεί την σχετική τιμή της μεταβλητής <code class=\"docutils literal notranslate\"><span class=\"pre\">dimension</span></code>.</p>\n<p>Ομοίως, υπάρχει μια μέθοδος για την <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code> με το όνομα <code class=\"docutils literal notranslate\"><span class=\"pre\">get_transform()</span></code>. Η μέθοδος <code class=\"docutils literal notranslate\"><span class=\"pre\">get_lookup()</span></code> θα πρέπει πάντα να επιστρέφει μια subclass της <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code> ενώ η <code class=\"docutils literal notranslate\"><span class=\"pre\">get_transform()</span></code> μια subclass της <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code>. Είναι σημαντικό να θυμάστε ότι τα objects της κλάσης <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code> μπορούν να φιλτραριστούν περαιτέρω ενώ τα objects της κλάσης <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code> όχι.</p>\n<p>Όταν φιλτράρετε και έχει απομείνει μόνο ένα lookup όνομα, το Django ψάξει για κάποιο <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code>. Αν υπάρχουν πολλά τότε θα ψάξει για κάποιο <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code>. Στην περίπτωση που υπάρχει μόνο ένα όνομα και δεν βρεθεί κάποιο <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code>, τότε το Django θα ψάξει για ένα <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code> και μετά το <code class=\"docutils literal notranslate\"><span class=\"pre\">exact</span></code> lookup πάνω σε αυτό το <code class=\"docutils literal notranslate\"><span class=\"pre\">Transform</span></code>. Στο τέλος, το Django, πάντα θα ψάχνει για ένα <code class=\"docutils literal notranslate\"><span class=\"pre\">Lookup</span></code>. Για να ξεκαθαρίσουμε λίγο το τοπίο:</p>\n<ul class=\"simple\">\n<li><p>Το <code class=\"docutils literal notranslate\"><span class=\"pre\">.filter(myfield__mylookup)</span></code> θα καλέσει την μέθοδο <code class=\"docutils literal notranslate\"><span class=\"pre\">myfield.get_lookup('mylookup')</span></code>.</p></li>\n<li><p>Το <code class=\"docutils literal notranslate\"><span class=\"pre\">.filter(myfield__mytransform__mylookup)</span></code> θα καλέσει τη μέθοδο <code class=\"docutils literal notranslate\"><span class=\"pre\">myfield.get_transform('mytransform')</span></code> και μετά την <code class=\"docutils literal notranslate\"><span class=\"pre\">mytransform.get_lookup('mylookup')</span></code>.</p></li>\n<li><p>Το <code class=\"docutils literal notranslate\"><span class=\"pre\">.filter(myfield__mytransform)</span></code> θα καλέσει πρώτα τη μέθοδο <code class=\"docutils literal notranslate\"><span class=\"pre\">myfield.get_lookup('mytransform')</span></code>, η οποία θα αποτύχει. Έπειτα θα καλέσει την μέθοδο <code class=\"docutils literal notranslate\"><span class=\"pre\">myfield.get_transform('mytransform')</span></code> και τέλος την <code class=\"docutils literal notranslate\"><span class=\"pre\">mytransform.get_lookup('exact')</span></code>.</p></li>\n</ul>\n</section>","rootId":"how-to-write-custom-lookups","toc":[{"title":"A lookup example","anchor":"a-lookup-example","children":[]},{"title":"A transformer example","anchor":"a-transformer-example","children":[]},{"title":"Γράφοντας ένα πιο αποτελεσματικό abs__lt lookup","anchor":"writing-an-efficient-abs-lt-lookup","children":[]},{"title":"Ένα παράδειγμα ενός διμερούς transformer","anchor":"a-bilateral-transformer-example","children":[]},{"title":"Γράφοντας εναλλακτικές υλοποιήσεις για ήδη υπάρχοντα lookups","anchor":"writing-alternative-implementations-for-existing-lookups","children":[]},{"title":"Πως προσδιορίζει το Django τα lookups και τα transforms που χρησιμοποιούνται","anchor":"how-django-determines-the-lookups-and-transforms-which-are-used","children":[]}],"breadcrumbs":[{"docname":"howto/index","title":"How-to guides","url":"/el/6.0/howto/"}],"prev":{"docname":"howto/writing-migrations","title":"How to create database migrations","url":"/el/6.0/howto/writing-migrations/"},"next":{"docname":"howto/outputting-csv","title":"How to create CSV output","url":"/el/6.0/howto/outputting-csv/"},"formats":{"html":"/el/6.0/howto/custom-lookups/","markdown":"/el/6.0/howto/custom-lookups.md","json":"/el/6.0/howto/custom-lookups.json"},"source":"https://github.com/django/django/blob/stable/6.0.x/docs/howto/custom-lookups.txt","official":"https://docs.djangoproject.com/el/6.0/howto/custom-lookups/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0","1.11","1.10"],"inLocales":["en","sv","zh-hans","ga","fr","ja","id","it","pt-br","ko","es","el","pl"]}