Django: access the model meta class value - python

I have some model classes defined:
class ModelA(models.Model):
class Meta:
abstract = True
class ModelB(ModelA):
class Meta:
abstract = False
So, now I have a class object, I want to check if it is abstract, is there any way to do this?
For example, I want something like:
>>> ModelA.abstract
True
>>> ModelB.abstract
False

Oh, I found that it is easy to get the Meta class by _meta field of the class:
>>> ModelA._meta.abstract
True

technically, strictly speaking, no external method should access a method or property that begins with an underscore (_) as it is private and protected from outsider access. To solve this, in your model file, add a property:
class Foo(models.Model):
class Meta:
verbose_name = "Foolish"
#property
def verbose_name(self):
return self._meta.verbose_name
Then your view can "properly" access the Meta.verbose_name via Foo().verbose_name as opposed to Foo._meta.verbose_name

Related

What is the use of class Meta in django?

I have been using django and used class Meta: a lot of times, actually what is the use of it?
for example , In django models
class Accounts(models.Model):
---some code here---
class Meta:
ordering = [-1]
In django forms
class AccountForm(forms.ModelForm):
---some code here---
class Meta:
fields = '__all__'
class Meta is basically the inner class. In Django, the use of the Meta class is simply to provide metadata to the ModelForm or the Model class. It is different from the metaclass of a Class in Python.
class Meta is used to change the behavior of the models such ordering, verbose_name etc. Though it is optional to be included in your models.

How to set initialisation value on abstract Django mixin from concrete class

I have an abstract mixin class that adds a Django model field to any concrete class that inherits from it.
At class initialisation - when makemigrations is run - I'd like the inheriting class to define whether an inherited field is required or optional via the blank= True or False property.
I've tried various Meta and __new__ approaches, but can't figure out how the abstract mixin class can get the information from the inheriting class.
Here's a naive attempt:
from django.db import models
class DescriptionMixin(models.Model):
class Meta:
abstract = True
description = models.TetxField(
# how to get value here?
blank=inheriting_class.description_required
)
class OptionalDescription(DescriptionMixin, SomeOtherClass):
class Meta:
verbose_name = 'Optional description'
description_required = False
class RequiredDescription(DescriptionMixin, SomeOtherClass):
class Meta:
verbose_name = 'Required description'
description_required = True
Thanks in advance for any help offered.
You can't do this at the database level. makemigrations doesn't actually initialise your models to create the migration files.
But since you're trying to enforce this on a TextField, which cannot be enforced at the database level anyway (blank is only used when validating a model through the full_clean() method), you could just override the clean() method on the DescriptionMixin, checking the value of self.blank and raising a ValidationError appropriately.
Solved using this (it's actually Wagtail on top of Django):
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs)
self._meta.get_field('description').blank = not getattr(self, 'description_required', False)

Django Model Subclass - no fields declared in subclass creating indentation error

class Value_List:
name = models.charfield(max_length=50)
description = models.TextField(max_length=140)
class Meta:
abstract = True
class Meter(Value_List):
class ContributionRole(Value_List):
class AttributionCertainty(Value_List):
The subclasses don't need their own fields declared (Value_List is for Option lists of various sorts).
This is causing an indentation error at class Meter(Value_List), because there is no indented block beneath it.
Like shmee said, you need "pass" to avoid the indentation error
class Meter(Value_List):
pass

How to create mixin to use #property in classes

I've got the following class
class UserProfile(models.Model):
# ...
#property
def get_fields(self):
return [(field.name, field.value_to_string(self)) for field in UserProfile._meta.fields]
I want to use that property on all my classes. So I want to make a mixin.
class HelperMixin(object):
#property
def get_fields(self):
return [(field.name, field.value_to_string(self)) for field in UserProfile._meta.fields]
Trouble is, the property has class specific code in it. How do I generalize the code to work in other classes?
And what is the difference when I use it like this:
class UserProfile(models.Model, HelperMixin)
vs. like this
class UserProfile(HelperMixin, models.Model)
Use self._meta.fields, class members are available on instances as well:
class HelperMixin(object):
#property
def get_fields(self):
return [(field.name, field.value_to_string(self)) for field in self._meta.fields]
The differense between class UserProfile(models.Model, HelperMixin) and class UserProfile(HelperMixin, models.Model) lies in the MRO (method resolution order). It would seem natural to have the mixin before the base class, but as long as the base and the mixin does not have members with the same name it makes no difference.

How to call only a subset of validation methods when editting

In my Django app, I am using a model (let's call it Mymodel), and a form :
class Mymodel(models.Model):
firstField(...)
secondField(...)
class MymodelAddform(ModelForm):
def clean_firstField(self):
#stuff
def clean_secondField(self):
#stuff again
def clean(self):
#performs stuff with all the fields
class Meta:
model = Mymodel
Now I want to add another form, MymodelEditform, based on Mymodel again, using only secondField, and only secondField validation
Two options I've considered (both do not work as I wrote them) :
class MymodelEditform(ModelForm):
class Meta:
model = Mymodel
fields = ['secondField']
Here the problem is that clean_secondField is not called unless I re-define it, and I would like to avoid having clean_secondField call another method defined elsewhere (though, if it is the only option, so be it)
class MymodelEditform(MymodelAddform):
class Meta:
model = Mymodel
fields = ['secondField']
Here the problem is that the clean() validation is called, and since I'm only using a subset of the fields, it fails.
The question is pretty obvious : how can I make it work as intended?
I haven't done this, but you can try this.
Create a simple class with clean methods.
As below
class MymodelformCleaner(ModelForm):
def clean_firstField(self):
#stuff
def clean_secondField(self):
#stuff again
Inherit your model forms from this class
Your model forms will just define the fields, while clean methods come from another class
class MymodelAddform(ModelForm, MymodelformCleaner):
class Meta:
model = Mymodel
class MymodelEditform(ModelForm, MymodelformCleaner):
class Meta:
model = Mymodel
fields = ['secondField']
An obvious solution would be to define clean_secondField in MymodelEditform and make MyModelAddForm inherit from MymodelEditForm, but it might not work as expected. Another solution would be to make both forms inherit from a common base form defining clean_secondField.
Or you could just explicitely exclude the field in the form's Meta (cf https://code.djangoproject.com/ticket/12901)

Categories