Django'da model alanlarını alın


121

Bir Django modeli verildiğinde, tüm alanlarını listelemeye çalışıyorum. _Meta model özniteliğini kullanarak bunu yapmanın bazı örneklerini gördüm, ancak metanın önündeki alt çizgi _meta özniteliğinin özel bir öznitelik olduğunu ve doğrudan erişilmemesi gerektiğini göstermiyor mu? ... Çünkü, örneğin, _meta'nın düzeni gelecekte değişebilir ve kararlı bir API olmayabilir?

_Meta bu kuralın bir istisnası mıdır? Kararlı ve kullanıma hazır mı yoksa ona erişmek kötü bir uygulama olarak mı görülüyor? Ya da bir modelin alanlarını _meta özniteliğini kullanmadan iç gözlem yapmanın bir işlevi veya başka bir yolu var mı? _Meta özelliği kullanılarak bunun nasıl yapılacağını gösteren bazı bağlantıların listesi aşağıdadır

Herhangi bir tavsiye çok takdir edilmektedir.

django nesnesi alma / ayarlama alanı

http://www.djangofoo.com/80/get-list-model-fields

Django model alanlarına nasıl iç gözlem yapılır?


Yanıtlar:


144

_metaözeldir, ancak nispeten kararlıdır. 1.3 veya 1.4'ten önce gerçekleşebilecek resmileştirme, belgeleme ve alt çizgiyi kaldırma çabaları vardır. Her şeyin geriye dönük olarak uyumlu olmasını sağlamak için çaba gösterileceğini düşünüyorum, çünkü zaten birçok insan kullanıyor.

Uyumluluk konusunda özellikle endişeleriniz varsa, bir model alan ve alanları döndüren bir işlev yazın. Bu, gelecekte bir şey değişirse, yalnızca bir işlevi değiştirmeniz gerektiği anlamına gelir.

def get_model_fields(model):
    return model._meta.fields

Bunun bir Fieldnesne listesi getireceğine inanıyorum . Örnekten her alanın değerini almak için kullanın getattr(instance, field.name).

Güncelleme: Django'ya katkıda bulunanlar, Google Summer of Code'un parçası olarak _Meta nesnesini değiştirmek için bir API üzerinde çalışıyor. Bakınız:
- https://groups.google.com/forum/#!topic/django-developers/hD4roZq0wyk
- https://code.djangoproject.com/wiki/new_meta_api


45
Ayrıca çoktan çoğa alanlara da ihtiyacınız varsa erişmeniz gerektiğinin farkında olmalısınız model._meta.many_to_many!
Bernhard Vallant

1
Teşekkür ederim Will. Başkalarının da _meta kullandığını bilmek güzel. Bir sarmalayıcı işlevine sahip olma fikrini seviyorum. Lazerscience, ayrıca teşekkür ederim. Many_to_many alanlarını elde etmenin güzel bir yöntemi olduğunu bilmek güzel. Joe
Joe J

3
django/core/management/commands/loaddata.pyuygulamalar, modeller ve alanlar ağacında gezinmek için _meta kullanır. İzlenecek güzel kalıp ... ve bunun "resmi yol" olduğuna bahse girebilirsiniz.
Ocak

2
Genel yabancı anahtar kullanıyorsanız, ayrıca kontrol etmelisiniz_meta.virtual_fields
andrei1089


97

Bu gönderinin oldukça eski olduğunu biliyorum, ancak aynı şeyi arayan herkese bunu yapmak için herkese açık ve resmi bir API olduğunu söylemeyi önemsedim: get_fields()veget_field()

Kullanımı:

fields = model._meta.get_fields()
my_field = model._meta.get_field('my_field')

https://docs.djangoproject.com/en/1.8/ref/models/meta/


6
Bu aslında django'nun yeni sürümü için doğru cevaptır.
chhantyal


3
Bir soru: bunlar "kamuya açık ve resmi" ise, neden hala altındalar _meta?
krubo

9

Şimdi özel bir yöntem var - get_fields ()

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

Hangi alanların döndürüleceğini kontrol etmek için kullanılabilecek iki parametreyi kabul eder:

  • include_parents

    Varsayılan olarak doğrudur. Özyinelemeli olarak üst sınıflarda tanımlanan alanları içerir. False olarak ayarlanırsa, get_fields () yalnızca doğrudan mevcut modelde bildirilen alanları arayacaktır. Doğrudan soyut modellerden veya proxy sınıflarından miras alan model alanlarının üst öğe üzerinde değil yerel olduğu kabul edilir.

  • include_hidden

    Varsayılan olarak yanlış. True olarak ayarlanırsa, get_fields () diğer alanın işlevselliğini desteklemek için kullanılan alanları içerecektir. Bu, "+" ile başlayan related_name (ManyToManyField veya ForeignKey gibi) olan tüm alanları da içerecektir.


9

get_fields()a döndürür tupleve her öğe, Model fielddoğrudan bir dize olarak kullanılamayan bir türdür. Böylece field.namealan adını döndürecek

my_model_fields = [field.name for field in MyModel._meta.get_fields()]
Yukarıdaki kod, tüm alanların adını içeren bir liste döndürecektir

Örnek

In [11]: from django.contrib.auth.models import User

In [12]: User._meta.get_fields()
Out[12]: 
(<ManyToOneRel: admin.logentry>,
 <django.db.models.fields.AutoField: id>,
 <django.db.models.fields.CharField: password>,
 <django.db.models.fields.DateTimeField: last_login>,
 <django.db.models.fields.BooleanField: is_superuser>,
 <django.db.models.fields.CharField: username>,
 <django.db.models.fields.CharField: first_name>,
 <django.db.models.fields.CharField: last_name>,
 <django.db.models.fields.EmailField: email>,
 <django.db.models.fields.BooleanField: is_staff>,
 <django.db.models.fields.BooleanField: is_active>,
 <django.db.models.fields.DateTimeField: date_joined>,
 <django.db.models.fields.related.ManyToManyField: groups>,
 <django.db.models.fields.related.ManyToManyField: user_permissions>)

In [13]: [field.name for field in User._meta.get_fields()]
Out[13]: 
['logentry',
 'id',
 'password',
 'last_login',
 'is_superuser',
 'username',
 'first_name',
 'last_name',
 'email',
 'is_staff',
 'is_active',
 'date_joined',
 'groups',
 'user_permissions']

Mükemmel cevap! Teşekkürler!
Tms91

8

Bu, bir modelden bir form oluştururken Django tarafından yapılan bir şeydir. _Meta özelliğini kullanıyor, ancak Bernhard'ın belirttiği gibi, hem _meta.fields hem de _meta.many_to_many kullanıyor. Django.forms.models.fields_for_model'e baktığınızda, bunu şu şekilde yapabilirsiniz:

opts = model._meta
for f in sorted(opts.fields + opts.many_to_many):
    print '%s: %s' % (f.name, f)

4

_Meta'nın içerdiği model alanları, ilgili alan nesnelerinin listeleri olarak birden çok konumda listelenir. Anahtarların alan adları olduğu bir sözlük olarak onlarla çalışmak daha kolay olabilir.

Bence bu, model alan nesnelerini toplamanın ve düzenlemenin en gereksiz ve etkileyici yolu:

def get_model_fields(model):
  fields = {}
  options = model._meta
  for field in sorted(options.concrete_fields + options.many_to_many + options.virtual_fields):
    fields[field.name] = field
  return fields

( Django.forms.models.fields_for_model içindeki bu örnek kullanımına bakın .)


2
Kodunuza, yaptığı şeyin kısa bir açıklamasıyla eşlik etmek isteyebilirsiniz.
Bas van Dijk

2

Buna ne dersin.

fields = Model._meta.fields

1
Bir alanın özelliklerine erişmek isteyebileceğini hayal ediyorum. Ayrıca, önceki cevaplarda belirtildiği gibi, many_to_manyve vardır virtual_fields.
Jocke

@Jocke haklısın. Başka bir niteliğe erişme ihtiyacı doğabilir. Cevap düzenlendi.
JDE876

2

Django dokümantasyonu 2.2'ye göre şunları kullanabilirsiniz:

Tüm alanları almak için: Model._meta.get_fields()

Tek bir alan almak için: Model._meta.get_field('field name')

ex. Session._meta.get_field('expire_date')


1

Yönetici siteniz için buna ihtiyacınız varsa , bir alan adı döndüren ModelAdmin.get_fieldsyöntem ( dokümanlar ) da vardır .liststrings

Örneğin:

class MyModelAdmin(admin.ModelAdmin):
    # extending change_view, just as an example
    def change_view(self, request, object_id=None, form_url='', extra_context=None):
        # get the model field names
        field_names = self.get_fields(request)
        # use the field names
        ...

0

Diğer bir yol, modele işlevler eklemektir ve tarihi geçersiz kılmak istediğinizde işlevi çağırabilirsiniz.

class MyModel(models.Model):
    name = models.CharField(max_length=256)
    created = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now=True)

    def set_created_date(self, created_date):
        field = self._meta.get_field('created')
        field.auto_now_add = False
        self.created = created_date

    def set_modified_date(self, modified_date):
        field = self._meta.get_field('modified')
        field.auto_now = False
        self.modified = modified_date

my_model = MyModel(name='test')
my_model.set_modified_date(new_date)
my_model.set_created_date(new_date)
my_model.save()
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.