# Τεκμηρίωση του Django - 5.2.8

# How to create custom model fields

## Εισαγωγή

Το άρθρο μοντέλα εξηγεί πως να χρησιμοποιήσετε τις στάνταρντ κλάσεις πεδίων του Django – `CharField`, `DateField` κλπ. Στις περισσότερες περιπτώσεις αυτές οι κλάσεις θα σας είναι αρκετές. Ωστόσο, η έκδοση του Django που χρησιμοποιείτε ίσως να μην καλύπτει τις ανάγκες και τις απαιτήσεις σας ή θα θέλατε να χρησιμοποιήσετε ένα πεδίο μοντέλου το οποίο είναι εντελώς διαφορετικό από αυτά που έρχονται με το Django.

Οι τύποι των προεγκατεστημένων πεδίων του Django δεν καλύπτουν όλους τους πιθανούς τύπους στηλών μιας βάσης δεδομένων (υπόψιν ότι μερικές βάσεις έχουν αποκλειστικά δικούς τους τύπους στηλών που δεν βρίσκονται σε κάποια άλλη βάση) – μόνο τους βασικούς τύπους, όπως `VARCHAR` και `INTEGER`. Για περισσότερους τύπους στηλών, όπως γεωγραφικά πολύγονα ή ακόμη και τύπους που μπορεί να δημιουργήσει ο χρήστης όπως οι PostgreSQL custom types, μπορείτε να ορίσετε τις δικές σας Django `Field` subclasses.

Εναλλακτικά, μπορείτε να έχετε ένα πολύπλοκο Python object το οποίο να μπορεί κάπως να γίνει serialized για να μπορέσει να αναπαρασταθεί ως στάνταρντ στήλη στη βάση δεδομένων. Αυτή είναι μια άλλη περίπτωση όπου μια subclass της `Field` θα σας βοηθήσει να χρησιμοποιήσετε το object σας με τα μοντέλα σας.

### Το object του παραδείγματος μας

Creating custom fields requires a bit of attention to detail. To make things easier to follow, we’ll use a consistent example throughout this document: wrapping a Python object representing the deal of cards in a hand of Bridge. Don’t worry, you don’t have to know how to play Bridge to follow this example. You only need to know that 52 cards are dealt out equally to four players, who are traditionally called north, east, south and west. Our class looks something like this:

    class Hand:
        """A hand of cards (bridge style)"""

        def __init__(self, north, east, south, west):
            # Input parameters are lists of cards ('Ah', '9s', etc.)
            self.north = north
            self.east = east
            self.south = south
            self.west = west

        # ... (other possibly useful methods omitted) ...

This is an ordinary Python class, with nothing Django-specific about it. We’d like to be able to do things like this in our models (we assume the `hand` attribute on the model is an instance of `Hand`):

    example = MyModel.objects.get(pk=1)
    print(example.hand.north)

    new_hand = Hand(north, east, south, west)
    example.hand = new_hand
    example.save()

Εκχωρούμε στο και ανακτούμε από το attribute `hand` του μοντέλου μας όπως ακριβώς θα κάναμε με κάθε άλλη κλάση της Python. Το κόλπο είναι να πούμε στο Django πως να διαχειριστεί την αποθήκευση στην και τη φόρτωση από τη βάση δεδομένων αυτού του object.

Για να χρησιμοποιήσουμε την κλάση `Hand` στα μοντέλα μας, δεν χρειάζεται να αλλάξουμε αυτή την κλάση καθόλου. Αυτό είναι ιδανικό, καθώς σημαίνει ότι μπορείτε να γράψετε Django μοντέλα για ήδη υπάρχουσες κλάσεις χωρίς να χρειαστεί να πειράξετε τον πηγαίο κώδικα.

Σημείωση

Ίσως να θέλετε, μόνο, να επωφεληθείτε από τους δικούς σας τύπους στηλών στη βάση δεδομένων και να διαχειριστείτε τα δεδομένα σας ως στάνταρντ τύπους Python objects στα μοντέλα σας, πχ strings, floats κλπ. Αυτή η περίπτωση είναι παρόμοια με το παράδειγμα μας, `Hand`, όπου θα υποδεικνύουμε τυχόν διαφορές καθώς προχωράμε.

## Βασική θεωρία

### Αποθηκευτικός χώρος στη βάση δεδομένων

Let’s start with model fields. If you break it down, a model field provides a way to take a normal Python object – string, boolean, `datetime`, or something more complex like `Hand` – and convert it to and from a format that is useful when dealing with the database. (Such a format is also useful for serialization, but as we’ll see later, that is easier once you have the database side under control).

Τα πεδία σε ένα μοντέλο πρέπει με κάποιο τρόπο να μετατραπούν ούτως ώστε να μπορέσει να τα δεχτεί ο αντίστοιχος τύπος στήλης της βάσης δεδομένων. Διαφορετικές βάσεις δεδομένων προσφέρουν διαφορετικά σετ από έγκυρους τύπους στηλών, αλλά ο κανόνας είναι ο ίδιος: αυτοί είναι οι μοναδικοί τύποι με τους οποίους θα μπορείτε να δουλεύετε. Οτιδήποτε θέλετε να αποθηκεύσετε στη βάση δεδομένων, πρέπει να προσαρμοστεί σε έναν από αυτούς τους τύπους.

Normally, you’re either writing a Django field to match a particular database column type, or you will need a way to convert your data to, say, a string.

For our `Hand` example, we could convert the card data to a string of 104 characters by concatenating all the cards together in a predetermined order – say, all the north cards first, then the east, south and west cards. So `Hand` objects can be saved to text or character columns in the database.

### Τι κάνει μια κλάση τύπου Field;

Όλα τα πεδία του Django (και όταν λέμε πεδία σε αυτό το άρθρο, εννοούμε πάντα πεδία μοντέλων και όχι πεδία φορμών) είναι subclasses της κλάσης `django.db.models.Field`. Οι περισσότερες πληροφορίες που καταγράφει το Django σχετικά με ένα πεδίο είναι κοινές για όλα τα πεδία – όνομα, βοηθητικό κείμενο, μοναδικότητα κοκ. Η αποθήκευση όλων αυτών των πληροφοριών γίνεται από την κλάση `Field`. Θα πούμε με λεπτομέρειες τι μπορεί να κάνει η `Field` σε λίγο. Για τώρα, αρκεί να πούμε ότι όλα τα πεδία κληρονομούν από την κλάση `Field` και παραμετροποιούν διάφορα βασικά κομμάτια της συμπεριφοράς της.

Είναι σημαντικό να συνειδητοποιήσετε ότι η κλάση ενός πεδίου του Django (πχ `CharField`, `BooleanField` κλπ) δεν αποθηκεύεται στα attributes των μοντέλων σας. Τα attributes του μοντέλου περιέχουν συνηθισμένα Python objects. Η κλάσεις των πεδίων που ορίζετε σε ένα μοντέλο αποθηκεύονται στην ουσία σε μια `Meta` κλάση όταν δημιουργείται το μοντέλο (οι ακριβείς λεπτομέρειες του πως γίνεται αυτό, δεν έχουν σημασία τώρα). Αυτό γίνεται επειδή οι κλάσεις των πεδίων δεν είναι απαραίτητες όταν απλώς δημιουργείτε και αλλάζετε τα attributes. Αντ’ αυτού οι κλάσεις προσφέρουν τον μηχανισμό για την μετατροπή μεταξύ του attribute και αυτού που είναι αποθηκευμένο στη βάση δεδομένων ή για την αποστολή στον serializer.

Κρατήστε στο μυαλό σας τα ακόλουθα, όταν δημιουργείτε δικά σας πεδία. Η subclass `Field` του Django που γράφετε, σας προσφέρει έναν μηχανισμό μετατροπής μεταξύ Python instances και τιμών database/serializer με διάφορους τρόπους (πχ, υπάρχουν διαφορές μεταξύ της αποθήκευσης της τιμής και της χρησιμοποίησης της στα lookups). Αν αυτό ακούγεται κάπως περίπλοκο, μην ανησυχείτε – θα γίνει κατανοητό στα παραδείγματα παρακάτω. Να θυμάστε, μόνο, ότι συχνά θα καταλήγετε με τη δημιουργία δύο κλάσεων, όταν γράφετε δικά σας πεδία:

- Η πρώτη κλάση θα είναι το Python object που θα χρησιμοποιούν οι χρήστες. Θα το αναθέσουν σε ένα attribute του μοντέλου, θα διαβάζουν από αυτό για να βλέπουν τα δεδομένα που αντιστοιχούν σε αυτό, θα αποθηκεύουν δεδομένα μέσω αυτού κλπ. Αυτή η κλάση είναι η `Hand` στο παράδειγμα μας.

- Η δεύτερη κλάση θα είναι μια subclass της `Field`. Αυτή είναι μια κλάση η οποία ξέρει πως να μετατρέψει την πρώτη σας κλάση σε δεδομένα που καταλαβαίνει η βάση δεδομένων και αντίστροφα τα δεδομένα που είναι αποθηκευμένα στη βάση δεδομένων σε object που καταλαβαίνει η Python.

## Γράφοντας μια subclass ενός πεδίου

Όταν σχεδιάζετε τη subclass της κλάσης `Field` (το δικό σας νέο πεδίο, αν θέλετε), θα πρέπει πρώτα να σκεφτείτε με ποια από τις ήδη υπάρχουσες κλάσεις `Field` το νέο σας πεδίο μοιάζει περισσότερο. Ίσως να μπορείτε να κάνετε subclass ένα ήδη υπάρχον Django πεδίο και να γλυτώσετε τον εαυτό σας πολύτιμο χρόνο. Αν όχι, θα πρέπει να κάνετε subclass την κλάση `Field`, απ” όπου όλα κληρονομούν.

Η αρχικοποίηση (initialization) του νέου σας πεδίου έχει να κάνει με τον διαχωρισμό των arguments που είναι συγκεκριμένα για αυτό που θέλετε να κάνει το πεδίο σας και των συνηθισμένων arguments. Στην μέθοδο `__init__()` της κλάσης `Field` (ή στην parent κλάση) περνάτε τα arguments που είναι συγκεκριμένα για το πεδίο σας.

Στο παράδειγμα μας, θα ονομάσουμε το πεδίο μας `HandField`. (Είναι, γενικά, καλή πρακτική να καλείτε τη subclass της `Field` ως `<Something>Field`, ούτως ώστε να εύκολα αναγνωρίσιμη ως μια subclass της `Field`). Η `HandField` δεν συμπεριφέρεται ως ένα ήδη υπάρχον Django πεδίο (πχ `CharField` ή `TextField`), οπότε θα κάνουμε subclass απ’ ευθείας από την `Field`:

    from django.db import models

    class HandField(models.Field):
        description = "A hand of cards (bridge style)"

        def __init__(self, *args, **kwargs):
            kwargs["max_length"] = 104
            super().__init__(*args, **kwargs)

Η `HandField` δέχεται τις περισσότερες από τις στάνταρντ επιλογές πεδίων (δείτε τη λίστα παρακάτω), αλλά εδώ εξασφαλίζουμε ότι έχει ένα συγκεκριμένο μέγιστο μήκος, αφού το μέγιστο που χρειάζεται είναι 52 τιμές φύλλων μαζί με το χρώμα του καθενός, πχ άσσος μπαστούνι (As, ace of spades) ή τρία κούπα (3h, 3 of hearts) κλπ: 104 χαρακτήρες στο σύνολο.

Σημείωση

Many of Django’s model fields accept options that they don’t do anything with. For example, you can pass both `editable` and `auto_now` to a `django.db.models.DateField` and it will ignore the `editable` parameter (`auto_now` being set implies `editable=False`). No error is raised in this case.

This behavior simplifies the field classes, because they don’t need to check for options that aren’t necessary. They pass all the options to the parent class and then don’t use them later on. It’s up to you whether you want your fields to be more strict about the options they select, or to use the more permissive behavior of the current fields.

Η μέθοδος `Field.__init__()` δέχεται τις ακόλουθες παραμέτρους:

- `verbose_name`

- `name`

- `primary_key`

- `max_length`

- `unique`

- `blank`

- `null`

- `db_index`

- `rel`: Χρησιμοποιείται για συσχετισμένα πεδία (όπως το `ForeignKey`). Για προχωρημένους χρήστες μόνο.

- `default`

- `editable`

- `serialize`: Αν είναι `False`, το πεδίο δεν θα γίνει serialized όταν το μοντέλο περάσει στους serializers του Django. Η προεπιλεγμένη τιμή είναι `True`.

- `unique_for_date`

- `unique_for_month`

- `unique_for_year`

- `choices`

- `help_text`

- `db_column`

- `db_tablespace`: Μόνο για τη δημιουργία περιεχομένων (indexes), αν η βάση δεδομένων υποστηρίζει τα tablespaces. Τις πιο πολλές φορές, μπορείτε να αγνοείτε αυτή την επιλογή.

- `auto_created`: Είναι `True` αν το πεδίο δημιουργήθηκε αυτόματα, όπως το `OneToOneField` που χρησιμοποιείται από την κληρονομικότητα των μοντέλων. Για προχωρημένους χρήστες μόνο.

Όλες οι επιλογές χωρίς εξήγηση, στην ανωτέρω λίστα, έχουν την ίδια έννοια με τα συνηθισμένα πεδία του Django. Δείτε στο άρθρο εγχειρίδιο πεδίων των μοντέλων για παραδείγματα και λεπτομέρειες.

### Deconstruction του πεδίου

The counterpoint to writing your `__init__()` method is writing the `deconstruct()` method. It’s used during model migrations to tell Django how to take an instance of your new field and reduce it to a serialized form - in particular, what arguments to pass to `__init__()` to recreate it.

Αν δεν έχετε προσθέσει τυχόν έξτρα επιλογές στη μέθοδο `__init__()` του δικού σας πεδίου, δεν χρειάζεται να γράψετε κάποια νέα μέθοδο `deconstruct()`. Αν, ωστόσο, αλλάξετε τα arguments που περνούν στην `__init__()` (όπως κάναμε στην κλάση `HandField` που αλλάξαμε το `kwargs['max_length']`), θα χρειαστεί να προσθέσετε τις τιμές που περάσατε.

`deconstruct()` returns a tuple of four items: the field’s attribute name, the full import path of the field class, the positional arguments (as a list), and the keyword arguments (as a dict). Note this is different from the `deconstruct()` method for custom classes which returns a tuple of three things.

Ως συντάκτης του δικού σας πεδίου, δεν θα σας απασχολήσουν τα δύο πρώτα στοιχεία του tuple. Η κύρια κλάση της `Field` έχει όλο τον απαραίτητο κώδικα για να υπολογίσει το όνομα και το import path του πεδίου σας. Ωστόσο, σίγουρα θα σας απασχολήσουν τα positional και keyword arguments, αφού αυτά είναι τα στοιχεία που πιθανόν να αλλάξετε.

Για παράδειγμα, στην κλάση `HandField` θέτουμε το `max_length` μέσα στην `__init__()`. Η μέθοδος `deconstruct()` της κλάσης `Field` (την οποία καλούμε - `super(HandField, self).deconstruct()`) θα δει ότι έχει οριστεί το `max_length` και θα το επιστρέψει μέσα στο `kwargs` dictionary. Για λόγους αναγνωσιμότητας μπορούμε να το διαγράψουμε από το dictionary και έτσι το `kwargs` να είναι κενό. Όταν, επομένως, πάρουμε αυτό το tuple των τεσσάρων στοιχείων και προσπαθήσουμε να χτίσουμε ένα instance του `HandField` δεν έχει πολύ νόημα το `kwargs` να περιέχει το `max_length` αφού κατά το χτίσιμο του instance θα κληθεί η `__init__` η οποία το ορίζει μέσα της:

    from django.db import models

    class HandField(models.Field):
        def __init__(self, *args, **kwargs):
            kwargs["max_length"] = 104
            super().__init__(*args, **kwargs)

        def deconstruct(self):
            name, path, args, kwargs = super().deconstruct()
            del kwargs["max_length"]
            return name, path, args, kwargs

If you add a new keyword argument, you need to write code in `deconstruct()` that puts its value into `kwargs` yourself. You should also omit the value from `kwargs` when it isn’t necessary to reconstruct the state of the field, such as when the default value is being used:

    from django.db import models

    class CommaSepField(models.Field):
        "Implements comma-separated storage of lists"

        def __init__(self, separator=",", *args, **kwargs):
            self.separator = separator
            super().__init__(*args, **kwargs)

        def deconstruct(self):
            name, path, args, kwargs = super().deconstruct()
            # Only include kwarg if it's not the default
            if self.separator != ",":
                kwargs["separator"] = self.separator
            return name, path, args, kwargs

Πιο περίπλοκα παραδείγματα είναι πέρα από τους σκοπούς αυτού του άρθρου, αλλά να θυμάστε – για κάθε παραμετροποίηση του instance του Field, η μέθοδος `deconstruct()` πρέπει να επιστρέφει arguments τα οποία αν περάσετε στην `__init__` θα ξαναφτιάξετε το πεδίο σας.

Δώστε μεγάλη προσοχή στην περίπτωση που δώσετε τυχόν νέες προεπιλεγμένες τιμές στα arguments της superclass της `Field`. Πρέπει να εξασφαλίσετε ότι πάντοτε περιλαμβάνονται παρά εξαφανίζονται όταν λαμβάνουν την παλιά προεπιλεγμένη τιμή.

In addition, try to avoid returning values as positional arguments; where possible, return values as keyword arguments for maximum future compatibility. If you change the names of things more often than their position in the constructor’s argument list, you might prefer positional, but bear in mind that people will be reconstructing your field from the serialized version for quite a while (possibly years), depending how long your migrations live for.

You can see the results of deconstruction by looking in migrations that include the field, and you can test deconstruction in unit tests by deconstructing and reconstructing the field:

    name, path, args, kwargs = my_field_instance.deconstruct()
    new_instance = MyField(*args, **kwargs)
    self.assertEqual(my_field_instance.some_attribute, new_instance.some_attribute)

### Field attributes not affecting database column definition

You can override `Field.non_db_attrs` to customize attributes of a field that don’t affect a column definition. It’s used during model migrations to detect no-op `AlterField` operations.

Για παράδειγμα:

    class CommaSepField(models.Field):
        @property
        def non_db_attrs(self):
            return super().non_db_attrs + ("separator",)

### Αλλάζοντας την base class του δικού σας πεδίου

Δεν μπορείτε να αλλάξετε την base class ενός παραμετροποιήσιμου πεδίου επειδή το Django δεν ανιχνεύει την αλλαγή και δεν θα δημιουργήσει migration για αυτή την αλλαγή. Για παράδειγμα αν ξεκινήσετε με αυτό:

    class CustomCharField(models.CharField): ...

και μετά αποφασίσετε ότι θέλετε να χρησιμοποιήσετε αντί αυτού ένα `TextField`, δεν μπορείτε να αλλάξετε την subclass όπως:

    class CustomCharField(models.TextField): ...

Αντιθέτως, πρέπει να δημιουργήσετε μια νέα κλάση πεδίου και να ενημερώσετε τα μοντέλα σας για να αναφερθούν σε αυτό:

    class CustomCharField(models.CharField): ...

    class CustomTextField(models.TextField): ...

Όπως συζητήθηκε στο αφαιρώντας πεδία μοντέλων, θα πρέπει να διατηρήσετε την αρχική κλάση `CustomCharField` στον κώδικα σας όσο έχετε migrations τα οποία αναφέρονται σε αυτή.

### Τεκμηριώνοντας το δικό σας πεδίο

As always, you should document your field type, so users will know what it is. In addition to providing a docstring for it, which is useful for developers, you can also allow users of the admin app to see a short description of the field type via the django.contrib.admindocs application. To do this provide descriptive text in a `description` class attribute of your custom field. In the above example, the description displayed by the `admindocs` application for a `HandField` will be “A hand of cards (bridge style)”.

Στην εμφάνιση του module `django.contrib.admindocs`, η περιγραφή του πεδίου ενσωματώνεται στο `field.__dict__` το οποίο επιτρέπει στην περιγραφή να συνεργαστεί με arguments του πεδίου. Για παράδειγμα, η περιγραφή του `CharField` είναι η:

    description = _("String (up to %(max_length)s)")

### Χρήσιμες μέθοδοι

Όταν φτιάξετε την subclass της κλάσης `Field`, μπορείτε, αν θέλετε, να παρακάμψετε (override) μερικές στάνταρντ μεθόδους, ανάλογα τη συμπεριφορά του πεδίου σας. Η λίστα με τις μεθόδους, παρακάτω, είναι περίπου κατά φθίνουσα σειρά σπουδαιότητας, οπότε ξεκινήστε από πάνω προς τα κάτω.

#### Δικά σας πεδία βάσης δεδομένων

Ας υποθέσουμς ότι έχετε δημιουργήσει ένα δικό σας πεδίο στη PostgreSQL με το όνομα `mytype`. Μπορείτε να κάνετε subclass τη κλάση `Field` και να υλοποιήσετε τη μέθοδο `db_type()`, ως εξής:

    from django.db import models

    class MytypeField(models.Field):
        def db_type(self, connection):
            return "mytype"

Όταν θα έχετε γράψει το `MytypeField`, μπορείτε να το χρησιμοποιήσετε σε οποιοδήποτε από τα μοντέλα σας, όπως ακριβώς με οποιοδήποτε άλλο τύπο `Field`:

    class Person(models.Model):
        name = models.CharField(max_length=80)
        something_else = MytypeField()

If you aim to build a database-agnostic application, you should account for differences in database column types. For example, the date/time column type in PostgreSQL is called `timestamp`, while the same column in MySQL is called `datetime`. You can handle this in a `db_type()` method by checking the `connection.vendor` attribute. Current built-in vendor names are: `sqlite`, `postgresql`, `mysql`, and `oracle`.

Για παράδειγμα:

    class MyDateField(models.Field):
        def db_type(self, connection):
            if connection.vendor == "mysql":
                return "datetime"
            else:
                return "timestamp"

The `db_type()` and `rel_db_type()` methods are called by Django when the framework constructs the `CREATE TABLE` statements for your application – that is, when you first create your tables. The methods are also called when constructing a `WHERE` clause that includes the model field – that is, when you retrieve data using QuerySet methods like `get()`, `filter()`, and `exclude()` and have the model field as an argument.

Some database column types accept parameters, such as `CHAR(25)`, where the parameter `25` represents the maximum column length. In cases like these, it’s more flexible if the parameter is specified in the model rather than being hardcoded in the `db_type()` method. For example, it wouldn’t make much sense to have a `CharMaxlength25Field`, shown here:

    # This is a silly example of hardcoded parameters.
    class CharMaxlength25Field(models.Field):
        def db_type(self, connection):
            return "char(25)"

    # In the model:
    class MyModel(models.Model):
        # ...
        my_field = CharMaxlength25Field()

The better way of doing this would be to make the parameter specifiable at run time – i.e., when the class is instantiated. To do that, implement `Field.__init__()`, like so:

    # This is a much more flexible example.
    class BetterCharField(models.Field):
        def __init__(self, max_length, *args, **kwargs):
            self.max_length = max_length
            super().__init__(*args, **kwargs)

        def db_type(self, connection):
            return "char(%s)" % self.max_length

    # In the model:
    class MyModel(models.Model):
        # ...
        my_field = BetterCharField(25)

Finally, if your column requires truly complex SQL setup, return `None` from `db_type()`. This will cause Django’s SQL creation code to skip over this field. You are then responsible for creating the column in the right table in some other way, but this gives you a way to tell Django to get out of the way.

Η μέθοδος `rel_db_type()` καλείται από πεδία τύπου `ForeignKey` και `OneToOneField` τα οποία δείχνουν σε ένα άλλο πεδίο για να καθορίσουν τον τύπο δεδομένων της στήλης. Για παράδειγμα, αν έχετε ένα πεδίο τύπου `UnsignedAutoField`, χρειάζεστε επίσης τα foreign keys τα οποία δείχνουν σε αυτό το πεδίο για να χρησιμοποιηθεί ο ίδιος τύπος δεδομένων:

    # MySQL unsigned integer (range 0 to 4294967295).
    class UnsignedAutoField(models.AutoField):
        def db_type(self, connection):
            return "integer UNSIGNED AUTO_INCREMENT"

        def rel_db_type(self, connection):
            return "integer UNSIGNED"

#### Μετατρέποντας τιμές σε Python objects

Αν η δικιά σας κλάση `Field` ασχολείται με δομές δεδομένων (data structures) οι οποίες είναι πιο περίπλοκες από strings, dates, integers, ή floats, τότε ίσως χρειαστεί να παρακάμψετε (override) τις μέθοδους `from_db_value()` και `to_python()`.

Αν η μέθοδος `from_db_value()` έχει υλοποιηθεί στη subclass του πεδίου, τότε θα καλείται σε όλες τις περιπτώσεις που τα δεδομένα φορτώνονται από τη βάση δεδομένων, συμπεριλαμβανομένων των κλήσεων των aggregate και `values()`.

Η μέθοδος `to_python()` καλείται κατά το deserialization και κατά τη διάρκεια της μεθόδου `clean()` που χρησιμοποιείται από τις φόρμες.

Ως γενικός κανόνας, η μέθοδος `to_python()` θα πρέπει συνεργάζεται με οποιοδήποτε από τα ακόλουθα arguments:

- Ένα instance ενός σωστού τύπου (πχ, του `Hand` στο τρέχων παράδειγμα μας).

- Ένα string

- `None` (αν το πεδίο επιτρέπει `null=True`)

In our `HandField` class, we’re storing the data as a `VARCHAR` field in the database, so we need to be able to process strings and `None` in the `from_db_value()`. In `to_python()`, we need to also handle `Hand` instances:

    import re

    from django.core.exceptions import ValidationError
    from django.db import models
    from django.utils.translation import gettext_lazy as _

    def parse_hand(hand_string):
        """Takes a string of cards and splits into a full hand."""
        p1 = re.compile(".{26}")
        p2 = re.compile("..")
        args = [p2.findall(x) for x in p1.findall(hand_string)]
        if len(args) != 4:
            raise ValidationError(_("Invalid input for a Hand instance"))
        return Hand(*args)

    class HandField(models.Field):
        # ...

        def from_db_value(self, value, expression, connection):
            if value is None:
                return value
            return parse_hand(value)

        def to_python(self, value):
            if isinstance(value, Hand):
                return value

            if value is None:
                return value

            return parse_hand(value)

Σημειώστε ότι πάντα επιστρέφουμε ένα instance του `Hand` από αυτές τις μεθόδους. Αυτός είναι ο τύπος του Python object που θέλουμε να αποθηκεύσουμε στο attribute του model.

Όσον αφορά τη μέθοδο `to_python()`, αν κάτι πάει στραβά κατά τη μετατροπή της τιμής, θα πρέπει να κάνετε raise ένα `ValidationError` exception (όπως κάνουμε μέσα στην ``parse_hand ``).

#### Μετατρέποντας τα Python objects σε query values

Since using a database requires conversion in both ways, if you override `from_db_value()` you also have to override `get_prep_value()` to convert Python objects back to query values.

Για παράδειγμα:

    class HandField(models.Field):
        # ...

        def get_prep_value(self, value):
            return "".join(
                ["".join(l) for l in (value.north, value.east, value.south, value.west)]
            )

Προειδοποίηση

Αν τα δικά σας πεδία χρησιμοποιούν του τύπους `CHAR`, `VARCHAR` ή `TEXT` της MySQL, θα πρέπει να σιγουρευτείτε ότι η μέθοδος `get_prep_value()` επιστρέφει πάντα μεταβλητές τύπου string. Όταν κάνετε ένα ερώτημα στη MySQL σχετικά με αυτά τα πεδία και η τιμή που δίνετε στο query είναι τύπου integer τότε η MySQL συμπεριφέρεται κάπως αναπάντεχα και τα αποτελέσματα από το query να μην είναι αυτά που περιμένετε. Αυτό το πρόβλημα δεν θα υπάρξει αν επιστρέφετε, πάντα, μια μεταβλητή τύπου string στη μέθοδο `get_prep_value()`.

#### Μετατρέποντας τα query values σε database values

Κάποιοι τύποι δεδομένων (πχ ημερομηνίες) χρειάζεται να είναι σε κάποια συγκεκριμένη μορφή πριν χρησιμοποιηθούν με κάποια βάση δεδομένων. Η μέθοδος `get_db_prep_value()` είναι το μέρος όπου αυτές οι μετατροπές πρέπει να γίνουν. Η σύνδεση (της βάση δεδομένων) που χρησιμοποιείται με το query περνάει ως το όρισμα με το όνομα `connection`. Αυτό σας επιτρέπει να χρησιμοποιείτε διαφορετική λογική μετατροπής με διαφορετικούς τύπους βάσης δεδομένων, αν αυτό είναι απαραίτητο.

Για παράδειγμα, το Django χρησιμοποιεί την ακόλουθη μέθοδο για πεδία τύπου `BinaryField`:

    def get_db_prep_value(self, value, connection, prepared=False):
        value = super().get_db_prep_value(value, connection, prepared)
        if value is not None:
            return connection.Database.Binary(value)
        return value

Σε περίπτωση που το δικό σας πεδίο χρειάζεται μια ξεχωριστή μετατροπή όταν αποθηκεύεται, δηλαδή όχι την ίδια μετατροπή που χρησιμοποιείται για συνηθισμένες παραμέτρους ενός query, μπορείτε να παρακάμψετε (override) τη μέθοδο `get_db_prep_save()`.

#### Επεξεργασία τιμών πριν την αποθήκευση

Αν θέλετε να επεξεργαστείτε την τιμή ακριβώς πριν την αποθήκευση της (στη βάση δεδομένων), μπορείτε να χρησιμοποιήσετε τη μέθοδο `pre_save()`. Για παράδειγμα, η κλάση του Django `DateTimeField` χρησιμοποιεί αυτή τη μέθοδο για να θέσει το attribute στη σωστή τιμή, όταν το `auto_now` ή το `auto_now_add` είναι `True`.

Αν παρακάμψετε αυτή τη μέθοδο, θα πρέπει να επιστρέψετε στο τέλος την τιμή του attribute. Θα πρέπει, επίσης, να ενημερώσετε το αντίστοιχο attribute του μοντέλου σας αν κάνετε τυχόν αλλαγές στην τιμή ούτως ώστε τυχόν κώδικας που αναφέρεται στο μοντέλο θα βλέπει πάντα τη σωστή τιμή.

#### Προσδιορίζοντας το πεδίο της φόρμας για ένα πεδίο μοντέλου

Για να παραμετροποιήσετε το πεδίο της φόρμας (form field) που χρησιμοποιείται από την κλάση `ModelForm`, μπορείτε να παρακάμψετε (override) τη μέθοδο `formfield()`.

Η κλάση του πεδίου της φόρμας μπορεί να οριστεί μέσω των arguments `form_class` και `choices_form_class`. Το τελευταίο χρησιμοποιείται σε περίπτωση που το πεδίο έχει ορίσει την παράμετρο choices, ενώ το πρώτο όχι. Αν αυτά τα arguments δεν δηλωθούν, τότε το πεδίο `CharField` ή `TypedChoiceField` θα χρησιμοποίηθεί.

Ολόκληρο το `kwargs` dictionary περνάει ως όρισμα απ” ευθείας στη μέθοδο `__init__()` του πεδίου της φόρμας. Συνήθως, το μόνο που πρέπει να κάνετε είναι να θέσετε ένα καλό `kwargs` ως προεπιλογή για το argument `form_class` (και ίσως για το `choices_form_class`) και μετά να δώσετε τον έλεγχο στην parent class. Αυτό ίσως απαιτήσει να γράψετε ένα δικό σας πεδίο φόρμας (και ίσως ένα widget φόρμας). Δείτε στο εγχειρίδιο για φόρμες, για πληροφορίες σχετικά με αυτό.

If you wish to exclude the field from the `ModelForm`, you can override the `formfield()` method to return `None`.

Συνεχίζοντας το παράδειγμα μας, μπορούμε να γράψουμε τη μέθοδο `formfield()` ως εξής:

    class HandField(models.Field):
        # ...

        def formfield(self, **kwargs):
            # Exclude the field from the ModelForm when some condition is met.
            some_condition = kwargs.get("some_condition", False)
            if some_condition:
                return None

            # Set up some defaults while letting the caller override them.
            defaults = {"form_class": MyFormField}
            defaults.update(kwargs)
            return super().formfield(**defaults)

Αυτό προϋποθέτει ότι έχουμε κάνει import μια κλάση φόρμας `MyFormField` (η οποία έχει το δικό της προεπιλεγμένο widget). Το παρών άρθρο δεν καλύπτει τη συγγραφή δικών σας πεδίων για φόρμες.

#### Προσομοιώνοντας προεγκατεστημένους (built-in) τύπους πεδίων

Αν έχετε δημιουργήσει μια μέθοδο `db_type()`, δεν θα χρειαστεί να ανησυχείτε για τη μέθοδο `get_internal_type()` – δεν θα χρησιμοποιηθεί πολύ. Μερικές φορές, όμως, η μονάδα αποθήκευσης της βάσης δεδομένων σας είναι παρόμοια, σε επίπεδο τύπου, με κάποιο άλλο πεδίο, οπότε μπορείτε να χρησιμοποιήσετε τη λογική αυτού του άλλου πεδίου για να δημιουργήσετε τη σωστή τύπου στήλη.

Για παράδειγμα:

    class HandField(models.Field):
        # ...

        def get_internal_type(self):
            return "CharField"

Ανεξαρτήτως της βάσης δεδομένων που χρησιμοποιούμε, αυτό θα σημαίνει ότι η εντολή `migrate` και άλλες SQL εντολές, θα χρησιμοποιούν τη σωστή τύπου στήλη για την αποθήκευση ενός string.

Αν η μέθοδος `get_internal_type()` επιστρέφει ένα string το οποίο δεν είναι γνωστό στο Django για την βάση δεδομένων που χρησιμοποιείται – δηλαδή, δεν εμφανίζεται στο `django.db.backends.<db_name>.base.DatabaseWrapper.data_types` – το string θα εξακολουθήσει να χρησιμοποιείται από τον serializer, αλλά η προεπιλεγμένη μέθοδος `db_type()` θα επιστρέψει `None`. Δείτε το εγχειρίδιο της μεθόδου `db_type()` για περιπτώσεις που αυτό μπορεί να φανεί χρήσιμο. Είναι μια καλή ιδέα να θέσετε ένα όμορφα περιγραφικό string ως τύπο πεδίου για τον serializer αν πρόκειται να χρησιμοποιήσετε την έξοδο του serializer σε κάποιο άλλο μέρος, εκτός του Django.

#### Μετατρέποντας τα δεδομένα του πεδίου για το serialization

To customize how the values are serialized by a serializer, you can override `value_to_string()`. Using `value_from_object()` is the best way to get the field’s value prior to serialization. For example, since `HandField` uses strings for its data storage anyway, we can reuse some existing conversion code:

    class HandField(models.Field):
        # ...

        def value_to_string(self, obj):
            value = self.value_from_object(obj)
            return self.get_prep_value(value)

### Μερικές γενικές συμβουλές

Η συγγραφή ενός δικού σας πεδίου μπορεί να είναι μια περίπλοκη διαδικασία, ειδικά όταν πραγματοποιείτε περίπλοκες μετατροπές μεταξύ Python objects και μορφών της βάσης δεδομένων και του serialization. Παρακάτω παρουσιάζονται δύο συμβουλές για να ομαλοποιήσουν τα πράγματα:

1. Look at the existing Django fields (in django/db/models/fields/__init__.py) for inspiration. Try to find a field that’s similar to what you want and extend it a little bit, instead of creating an entirely new field from scratch.

2. Put a `__str__()` method on the class you’re wrapping up as a field. There are a lot of places where the default behavior of the field code is to call `str()` on the value. (In our examples in this document, `value` would be a `Hand` instance, not a `HandField`). So if your `__str__()` method automatically converts to the string form of your Python object, you can save yourself a lot of work.

## Γράφοντας μια subclass ενός πεδίου τύπου `FileField`

Επιπροσθέτως των παραπάνω μεθόδων, τα πεδια που ασχολούνται με αρχεία έχουν μερικές ακόμη απαιτήσεις, τις οποίες πρέπει να λάβετε υπόψιν σας. Η πλειονότητα των μηχανισμών που προσφέρει ένα πεδίο τύπου `FileField`, όπως ο έλεγχος της μονάδας αποθήκευσης της βάσης δεδομένων (database storage) καθώς και της ανάκτησης, μπορεί να μείνει ανέπαφος, αφήνοντας τις subclasses να χειριστούν την πρόκληση της υποστήριξης ενός συγκεκριμένου τύπου αρχείου.

Το Django προσφέρει μια κλάση `File`, που χρησιμοποιείται ως μεσάζων (proxy) στα περιεχόμενα και λειτουργίες του αρχείου. Αυτή η κλάση μπορεί να γίνει subclass προκειμένου να παραμετροποιηθεί η πρόσβαση στο αρχείο και το ποιες μέθοδοι θα είναι διαθέσιμες. Βρίσκεται στο `django.db.models.fields.files` και η προεπιλεγμένη συμπεριφορά του εξηγείται στο εγχειρίδιο για αρχεία.

Once a subclass of `File` is created, the new `FileField` subclass must be told to use it. To do so, assign the new `File` subclass to the special `attr_class` attribute of the `FileField` subclass.

### Μερικές προτάσεις

Πέρα από τις παραπάνω λεπτομέρειες, υπάρχουν μερικές κατευθυντήριες γραμμές οι οποίες μπορούν να βελτιώσουν την αποδοτικότητα και την αναγνωσιμότητα του κώδικα του πεδίου σας.

1. The source for Django’s own `ImageField` (in django/db/models/fields/files.py) is a great example of how to subclass `FileField` to support a particular type of file, as it incorporates all of the techniques described above.

2. Όσο μπορείτε να κάνετε cache τα attributes του αρχείου. Εφόσον τα αρχεία μπορεί να αποθηκεύονται σε απομακρυσμένα συστήματα αποθήκευσης, η ανάκτηση τους μπορεί να κοστίσει επιπλέον άσκοπο χρόνο ή ακόμη και χρήματα. Όταν ένα αρχείο ανακτάται ούτως ώστε να δείτε κάποιες πληροφορίες σχετικά με τα περιεχόμενα του, κάντε cache (αποθηκεύστε τα στη λανθάνουσα μνήμη) όσα περισσότερα δεδομένα μπορείτε για να μειώσετε τον αριθμό μελλοντικών προσπελάσεων του αρχείου για την απόκτηση των ίδιων πληροφοριών.