2017-10-11 5 views
2

Prologue:Comment faire/utiliser une fonction de base de données personnalisée dans Django

Ceci est une question qui se pose souvent SO:

et peut être appliqué à ce qui précède, ainsi que dans les domaines suivants:

Je voulais composer un exemple sur le SO Documentation, mais étant donné qu'il se est arrêté le 8 Août, 2017, je vais suivre la suggestion de this widely upvoted and discussed meta answer et écris mon exemple en tant que message auto-répondu.

Bien sûr, je serais plus qu'heureux de voir une approche différente aussi !!


Question:

Django/GeoDjango a quelques fonctions de base de données comme Lower() ou MakeValid() qui peut être utilisé comme ceci:

Author.objects.create(name='Margaret Smith') 
author = Author.objects.annotate(name_lower=Lower('name')).get() 
print(author.name_lower) 

Est-il possible d'utiliser et/ou créer ma propre fonction de base de données personnalisée basée sur des fonctions de base de données existantes comme:

Comment puis-je appliquer/utiliser ces fonctions dans Django/GeoDjango ORM?

Répondre

2

Django fournit l'expression Func() pour faciliter l'appel des fonctions de base de données dans un queryset:

Func() expressions sont le type de base de toutes les expressions qui impliquent des fonctions de base de données comme COALESCE et INFÉRIEUR, ou agrégats comme SOMME.

Il y a 2 options sur la façon d'utiliser une fonction de base de données dans Django/GeoDjango ORM:

Pour plus de commodité, supposons que le modèle est nommé MyModel et que la sous-chaîne est stockée dans une variable nommée subst:

from django.contrib.gis.db import models as gis_models 

class MyModel(models.Model): 
    name = models.CharField() 
    the_geom = gis_models.PolygonField() 
  1. utilisation Func() pour appeler la fonction d irectly:

    Nous aurons également besoin les éléments suivants pour rendre nos requêtes travail:

    La requête:

    MyModel.objects.aggregate(
        pos=Func(F('name'), Value(subst), function='POSITION') 
    ) 
    
  2. Créer votre propre fonction de base de données extension Func:

    Nous pouvons étendre Func classe pour créer nos propres fonctions de base de données:

    class Position(Func): 
        function = 'POSITION' 
    

    et de l'utiliser dans une requête:

    MyModel.objects.aggregate(pos=Position('name', Value(subst))) 
    

GeoDjango Annexe:

En GeoDjango la méthode Func() get remplacé par GeoFunc() et il est utilisé de la même manière.


fonction de base de données Généraliser personnalisée Annexe:

Dans le cas où vous souhaitez créer une fonction de base de données personnalisée (option 2) et que vous voulez être en mesure de l'utiliser avec une base de données sans le savoir à l'avance , vous pouvez utiliser la méthode de as_<database-name>Func, à condition que la fonction que vous souhaitez utiliser existe dans chaque base de données:

class Position(Func): 
    function = 'POSITION' # MySQL method 

    def as_sqlite(self, compiler, connection): 
     #SQLite method 
     return self.as_sql(compiler, connection, function='INSTR') 

    def as_postgresql(self, compiler, connection): 
     # PostgreSQL method 
     return self.as_sql(compiler, connection, function='STRPOS')