Django: How do I get the model a model inherits from? [duplicate] - python

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
get python class parent(s)
I have a:
class Animal(models.Model):
pass
class Cat(Aminal):
pass
class StreetCat(Cat):
pass
How can I find out the model a model inherits from?

You can get the direct superclass in python through __base__
>>> StreetCat.__base__ is Cat
>>> True
__bases__ will get you a tuple of all parent classes if you have multiple base classes class Foo(A, B)
Update thanks to OP: the following django method does not retrieve abstract base classes, as technically these are internal use methods for storing the foreign keys that tie each inherited model to their parents. Be warned!
Django also indirectly provides some helpers for inherited models which are shortcuts for the pure python methods of traversing the superclasses.
>>> StreetCat._meta.get_parent_list()
[Out] : Set([Class Animal, Class Cat])
InheritedClass.parents is an ordered dictionary of all parents, so the following would work to get the upper most parent if you wanted:
>>> StreetCat._meta.parents.keys()[-1]
You could also use a non django related method, something like
>>> StreetCat.__mro__[-3]
# once you know that BaseModel is an Object, and since all defined models subclass
# the BaseModel, [-3] is the first class that subclasses models.Model

Related

How to access args of generic class [duplicate]

This question already has an answer here:
Access type argument in any specific subclass of user-defined Generic[T] class
(1 answer)
Closed 4 months ago.
If I have a class A:
T = TypeVar("T")
class A(Generic[T]):
a: T
How do I access the Generic[T] with the type-object A
typing.get_origin(A[...]).__bases__ just returns a <class 'typing.Generic'> instead of typing.Generic[~T]
You are looking for __orig_bases__. That is set by the type metaclass when a new class is created. It is mentioned here in PEP 560, but is otherwise hardly documented.
This attribute contains (as the name suggests) the original bases as they were passed to the metaclass constructor in the form of a tuple. This distinguishes it from __bases__, which contains the already resolved bases as returned by types.resolve_bases.
Here is a working example:
from typing import Generic, TypeVar
T = TypeVar("T")
class A(Generic[T]):
a: T
class B(A[int]):
pass
print(A.__orig_bases__) # (typing.Generic[~T],)
print(B.__orig_bases__) # (__main__.A[int],)
Since it is poorly documented, I would be careful, where you use it. If you add more context to your question, maybe we'll find a better way to accomplish what you are after.
Possibly related or of interest:
Access type argument in any specific subclass of user-defined Generic[T] class

Class inheritance python

In the case creating a model, for example
class Student(models.Model)
name=models.charfield(),roll=models.integerfield()
similarly,
In the case creating a form, class newform(forms.Form)
name=forms.charfield(),roll=forms.integerfield()
similarly,
In the case creating a serializer, class serial(serializers.Serializer)
name=serializers.charfield(),roll=serializers.integerfield()
I understood that in each classes,a base class is inherited but i am confused that if different objects of different classes are created inside a class in each scenario then what is the meaning of inheriting models.model, forms.Form,serializers.Serializer what these inherited classes do?
Django uses inheritance as well as object composition which are techniques of OOP for reusability.
Let us take your first class as example (I have only kept one field for simplicity):
Student(models.Model):
name = models.CharField(max_length=100)
Inheritance:
The first line Student(model.Model): does inheritance by inheriting from Model class using which you are getting methods like save(), delete(), clean_fields e.t.c. Now your Student class can reuse those methods.
Composition
The second line name = models.CharField(max_length=100) does object composition by creating object namely name of class CharField using which you get methods like check, get_internal_type e.t.c.
All of those Inbuilt classes (Model, CharField e.t.c) are defined in file namely models.py so when you do models.Model you are getting Model class from file models.py and models.CharField gives you CharField class from same file.
By inheriting from other classes, you have access to their methods;
Class A(object):
def _print(self):
print('Class A')
Class B(A):
def other_print(self):
print('Class B')
if __name__ == "__main__":
a, b = A(), B()
a._print()
b._print()
b.other_print()
When inheriting from model, forms, etc... You inherit from an object that is already integrated in the framework and thus has specific methods to work with the framework. For example the model will be registered to the database, the form 'knows' how to render properly, etc...
When you inherit from these classes, you already have an pre-built object with all these methods.

Can python class variable be used as both class and instance variable? [duplicate]

I'm simultaneously learning Python while picking up Django. I'm familiar with many other languages.
In the following code snippet, x is a class variable of class Foo.
class Foo(object):
x = 9000
Given the previous declaration, the following works fine.
print Foo.x
The Django framework lets you create your model by defining Python classes. It makes fields out of the different class variables in your Python classes.
class Question(models.Model):
question_text = models.CharField(max_length=200)
Why does the following code snippet:
#!/usr/bin/env
import os, django
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
django.setup()
from polls.models import Question, Choice
print Question.question_text
throw the following error:
AttributeError: type object 'Question' has no attribute 'question_text'
As far as I'm understanding everything my Question class has a single static member defined: Question.question_text.
Django models use a metaclass to alter what is normal class behaviour.
Use dir(Question) and you'll see there are different attributes on that class now. This is custom behaviour just for Django models however.
If you are curious you can study the metaclass __new__ method, but it does a lot of work specific to Object Relational Mapping tasks.
Magic.
No, really.
Python classes aren't set-in-stone structure, like they are in C++. They are, themselves, just objects — instances of another type:
class Foo(object):
pass
print(type(Foo)) # <class 'type'>
You can even make a class like you'd make any other object, by calling type. This:
class Bar(object):
a = 1
b = 2
Is really (more or less) syntactic sugar for this:
Bar = type('Bar', (object,), {'a': 1, 'b': 2})
type takes the name of your new class, a list of its superclasses, and a dict of all the attributes of the class, and spits out a new class.
But, because type is just a class like any other, it's possible to subclass it and give it different behavior. And this is what Django has done: it's created a subclass of type that does something different with the dict of attributes you pass to it.
You don't see this happening directly in your own code, but if you check type(models.Model), you'll find out its type is not type, but something specific to Django. It probably has "meta" in the name, because it's called a metaclass: the class of a class.
This is a fairly common pattern for making "declarative" libraries in Python, where the attributes of a class actually define some kind of structure. You can see the same thing in form validation (wtforms), schema validation (colander), other ORMs (sqlalchemy), and even the stdlib enum module.
Question is an object of type type. You want an instance of Question:
>>> q= Question(text = "Does a dog have the buddha nature?")
Then you should get
q.text
"Does a dog have the buddha nature?"
Note that this object will not persist unless you save() it:
>>> q.save()

How to add new method to Django class from other modules? [duplicate]

This question already has answers here:
Adding a method to an existing object instance in Python
(19 answers)
Closed 6 years ago.
I have a Django model say:
class MyOperation(models.Model):
name = models.CharField(max_length=100)
def my_method(self):
pass
I want to be able to add, from a different Django app, a new method to this class.
I tried to do this from a different app module called custom.py:
from operations.models import MyOperation
def op_custom(test):
print "testing custom methods"
MyOperation.op_custom = op_custom
However this does not seems to work, in runtime the method does not exists.
Is this the way to modify the definition of a class from a different django application? Is there a better way to do it?
Thanks
The Right Way™ to do this is via a mixin:
class MyMixIn(object):
def op_custom(self):
print("foo")
class MyOperation(models.Model, MyMixIn):
def op_normal(self):
print("bar")
This has several advantages over monkey-patching in another method:
The mixin is in the class' method resolution order, so introspection works perfectly.
It is guaranteed to be defined on every instance of the class regardless of where it is instantiated since the class itself inherits from the mixin. Otherwise, you may end up with instances from before the monkey patch is applied where this method isn't there.
It provides an obvious place to add such methods in the future.

Django, Python, and Class Variables

I'm simultaneously learning Python while picking up Django. I'm familiar with many other languages.
In the following code snippet, x is a class variable of class Foo.
class Foo(object):
x = 9000
Given the previous declaration, the following works fine.
print Foo.x
The Django framework lets you create your model by defining Python classes. It makes fields out of the different class variables in your Python classes.
class Question(models.Model):
question_text = models.CharField(max_length=200)
Why does the following code snippet:
#!/usr/bin/env
import os, django
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
django.setup()
from polls.models import Question, Choice
print Question.question_text
throw the following error:
AttributeError: type object 'Question' has no attribute 'question_text'
As far as I'm understanding everything my Question class has a single static member defined: Question.question_text.
Django models use a metaclass to alter what is normal class behaviour.
Use dir(Question) and you'll see there are different attributes on that class now. This is custom behaviour just for Django models however.
If you are curious you can study the metaclass __new__ method, but it does a lot of work specific to Object Relational Mapping tasks.
Magic.
No, really.
Python classes aren't set-in-stone structure, like they are in C++. They are, themselves, just objects — instances of another type:
class Foo(object):
pass
print(type(Foo)) # <class 'type'>
You can even make a class like you'd make any other object, by calling type. This:
class Bar(object):
a = 1
b = 2
Is really (more or less) syntactic sugar for this:
Bar = type('Bar', (object,), {'a': 1, 'b': 2})
type takes the name of your new class, a list of its superclasses, and a dict of all the attributes of the class, and spits out a new class.
But, because type is just a class like any other, it's possible to subclass it and give it different behavior. And this is what Django has done: it's created a subclass of type that does something different with the dict of attributes you pass to it.
You don't see this happening directly in your own code, but if you check type(models.Model), you'll find out its type is not type, but something specific to Django. It probably has "meta" in the name, because it's called a metaclass: the class of a class.
This is a fairly common pattern for making "declarative" libraries in Python, where the attributes of a class actually define some kind of structure. You can see the same thing in form validation (wtforms), schema validation (colander), other ORMs (sqlalchemy), and even the stdlib enum module.
Question is an object of type type. You want an instance of Question:
>>> q= Question(text = "Does a dog have the buddha nature?")
Then you should get
q.text
"Does a dog have the buddha nature?"
Note that this object will not persist unless you save() it:
>>> q.save()

Categories