2016-06-08 11 views
0

Ich möchte Felder von Django-Modellen um einige benutzerdefinierte Feldoptionen erweitern, da ich eine Anwendung erstelle, die mit Modellen verwendet wird, die nur einem allgemeinen Schema folgen. Die Idee ist, dass die App immer noch mit neu definierten Modellen arbeiten sollte und dass die gesamte Konfiguration direkt in models.py passieren sollte. Daher möchte ich einige Optionen als Schlüsselwortargumente übergeben, z. Definieren, ob das Feld in einer externen Darstellung angezeigt werden soll. Das Problem besteht darin, dass das Übergeben neuer Schlüsselwortargumente den Fehler unerwarteter Schlüsselwortargumente verursacht. Bisher habe ich so etwas wie diese zurückgegriffen, was ich denke, ist eine Art hässlich:Django: Anfügen von benutzerdefinierten Feldoptionen zum Angeben der externen Darstellung

class CustomCharField(models.CharField): 

    def __init__(self, *args, **kwargs): 
     self.custom_option = kwargs['custom_option'] 
     del kwargs['custom_option'] 
     super().__init__(*args, **kwargs) 

Gäbe es eine saubere Lösung?

Darüber hinaus frage ich mich, ob dieser Ansatz überhaupt richtig ist oder ob es eine andere bevorzugte Möglichkeit gibt, eine externe Repräsentation eines Modells in Django zu codieren, etwa marshmallow für Flask.

+0

@Jamo Wirklich hängt davon ab, was Sie versuchen zu tun.Könnten Sie erklären, was Sie versuchen zu tun? – zEro

+0

@zEro Ich baue ein System zum Speichern von experimentellen Daten. Das System sollte die Daten basierend auf ausgewählten Experimenten integrieren, d. H. Sie in einer großen Tabelle zusammenführen. Je nachdem, welche Art von Experimenten in den Versionen der App gespeichert sind, gibt es unterschiedliche "Datentypen", d. H. Unterschiedliche Modelle für die experimentellen Daten. Also muss ich sagen: "Zeige diese Spalte in der Ergebnistabelle." und "Dies ist nur ein unbedeutender Messwert, der nur der Vollständigkeit halber gespeichert wird." Hoffe, das macht es ein bisschen klarer. – Jarno

+0

Hmm .. Ich bin immer noch nicht in der Lage, vollständig zu verstehen, aber näher zu kommen (denke ich). Die von Ihnen gespeicherte 'self.custom_option' wird verwendet, um herauszufinden, wie oder was in einer Ansicht angezeigt werden soll, oder? – zEro

Antwort

0

Unabhängig davon, ob der Ansatz hier richtig ist, ist meine Lösung zum Anfügen von benutzerdefinierten Schlüsselwortargumenten an alle Django Field Klassen. Die benutzerdefinierten Optionen können in einem dict mit Variablennamen als keys Standardwerte wie values angegeben werden.

from django.db.models import fields 

# Get a dictionay of all field classes. 
plain_fields = dict([(name, cls) for name, cls 
        in fields.__dict__.items() 
        if type(cls) == type and 
        issubclass(cls, fields.Field) and 
        cls != fields.Field]) 

def options_factory(options): 
    """ 
    Produces a class that allows defining keyword arguments as 
    a mixin on another class. 

    Args: 
     options (dict): Name of the keyword arguments mapped to their 
      default value. 
    """ 
    class OptionsMixin(): 

     def __init__(self, *args, **kwargs): 

      for name, default in options.items(): 
       self.__dict__[name] = kwargs.pop(name, default) 
      super().__init__(*args, **kwargs) 

    return OptionsMixin 

# Specify custom options with default values. 
customoptions = {'supercooloption': 47, 
       'superfluous_option': None} 

CustomOptions = options_factory(customoptions) 

# Iterate over the field classes and mix the CustomOptions in. 
optionfields = {} 
for name, cls in plain_fields.items(): 
    optionfields[name] = type(name, (CustomOptions, cls), {}) 

# Update the modules __dict__ so the classes can be imported. 
globals().update(optionfields) 

I angegeben dies in einer separaten Datei wie optionmodels.py in models.py in kann dann wie import myapp.optionmodels as omodels importiert werden, die die benutzerdefinierten Felder mit nur geringer Syntax Änderung im Vergleich zu den Standard-Django Felder zu verwenden.

Beachten Sie, dass Beziehungsfelder wie ManyToManyField eine andere __init__ Signatur haben und daher ein anderes Mixin benötigen, das super().__init__(to, *args, **kwargs) aufruft.

Verwandte Themen