property - modify model django




Django: ottieni un elenco di campi modello? (6)

Ho definito una classe User che (in definitiva) eredita dai models.Model . Voglio ottenere un elenco di tutti i campi definiti per questo modello. Ad esempio, phone_number = CharField(max_length=20) . Fondamentalmente, voglio recuperare tutto ciò che eredita dalla classe Field .

Pensavo di poterli recuperare sfruttando inspect.getmembers(model) , ma l'elenco restituito non contiene nessuno di questi campi. Sembra che Django abbia già conquistato la classe e abbia aggiunto tutti i suoi attributi magici e spogliato di ciò che è stato effettivamente definito. Quindi ... come posso ottenere questi campi? Probabilmente hanno una funzione per recuperarli per i loro scopi interni?


Almeno con Django 1.9.9 - la versione che sto usando attualmente -, nota che .get_fields() effettivamente "considera" qualsiasi modello straniero come un campo, il che può essere problematico. Di 'che hai:

class Parent(models.Model):
    id = UUIDField(primary_key=True)

class Child(models.Model):
    parent = models.ForeignKey(Parent)

Ne consegue che

>>> map(lambda field:field.name, Parent._model._meta.get_fields())
['id', 'child']

mentre, come mostrato da @Rockallite

>>> map(lambda field:field.name, Parent._model._meta.local_fields)
['id']

Il metodo get_all_related_fields() qui menzionato è stato deprecato in 1.8 . D'ora in poi get_fields() .

>> from django.contrib.auth.models import User
>> User._meta.get_fields()

Per le versioni Django 1.8 e successive:

Il metodo get_all_field_names() è deprecato a partire da Django 1.8 e verrà rimosso in 1.10 .

La pagina di documentazione collegata sopra fornisce un'implementazione completamente compatibile con i precedenti di get_all_field_names() , ma per la maggior parte degli scopi [f.name for f in MyModel._meta.get_fields()] dovrebbe funzionare [f.name for f in MyModel._meta.get_fields()] .

Per le versioni di Django precedenti alla 1.8:

model._meta.get_all_field_names()

Questo dovrebbe fare il trucco.

Ciò richiede un'istanza di modello reale. Se tutto ciò che hai è una sottoclasse di django.db.models.Model , allora dovresti chiamare myproject.myapp.models.MyModel._meta.get_all_field_names()


Questo fa il trucco. L'ho provato solo su Django 1.7.

your_fields = YourModel._meta.local_fields
your_field_names = [f.name for f in your_fields]

Model._meta.local_fields non contiene campi molti-a-molti. Dovresti prenderli usando Model._meta.local_many_to_many .


Trovo abbastanza utile l'aggiunta di questo ai modelli di django:

def __iter__(self):
    for field_name in self._meta.get_all_field_names():
        value = getattr(self, field_name, None)
        yield (field_name, value)

Questo ti permette di fare:

for field, val in object:
    print field, val

MyModel._meta.get_all_field_names() stato MyModel._meta.get_all_field_names() e rimosso diverse versioni in Django 1.10.

Ecco il suggerimento compatibile con le versioni precedenti dei documenti :

from itertools import chain

list(set(chain.from_iterable(
    (field.name, field.attname) if hasattr(field, 'attname') else (field.name,)
    for field in MyModel._meta.get_fields()
    # For complete backwards compatibility, you may want to exclude
    # GenericForeignKey from the results.
    if not (field.many_to_one and field.related_model is None)
)))






django-models