I am using the package django-polymorphic-tree inside of a Django application.
The PolymorphicMPTTModel abstract model from said package has the following Meta:
class PolymorphicMPTTModel(MPTTModel, PolymorphicModel, metaclass=PolymorphicMPTTModelBase):
"""
The base class for all nodes; a mapping of an URL to content (e.g. a HTML page, text file, blog, etc..)
"""
# ... fields
class Meta:
abstract = True
ordering = (
"tree_id",
"lft",
)
base_manager_name = "objects"
Here's a model I wrote that inherits from it:
class MyNodeModel(PolymorphicMPTTModel):
parent = PolymorphicTreeForeignKey(
"self",
blank=True,
null=True,
related_name="children",
on_delete=models.CASCADE,
)
# ... fields
class Meta:
ordering = (
"tree_id",
"-lft",
)
As you can see, I'm trying to overwrite the parent's Meta.ordering attribute.
However, if I do this inside of an instance of MyNodeModel:
print(self.Meta.ordering)
it prints:
('tree_id', 'lft')
which is the parent's value for that field. It appears as though the child class is failing to override that property. Why does this happen?
Related
I am trying to access child model value from parent model serializer.
Parent Models
class Course(models.Model):
name = models.CharField(max_length=100)
Child Models
class CourseStaff(models.Model):
course = models.ForeignKey(Course, on_delete=models.CASCADE,
related_name='course_staff_course')
staff = models.ForeignKey(User, on_delete=models.CASCADE,
related_name='course_staff_user')
enable = models.BooleanField()
Serializer Class
class TeacherCourseSerializer(serializers.ModelSerializer):
class Meta:
model = Course
fields = '__all__'
Expected Result
[
{
id: 1,
name: "",
staff_id: 5, #<---- It will come from the child model.
is_enabled: true #<---- It will come from the child model.
}
]
I tried with this
Serializer
class TeacherCourseSerializer(serializers.ModelSerializer):
enable = serializers.CharField(source='course_staff_course.enable')
class Meta:
model = Course
fields = '__all__'
But getting error
Got AttributeError when attempting to get a value for field `enable` on serializer `TeacherCourseSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `Course` instance.
Original exception text was: 'RelatedManager' object has no attribute 'enable'.
How can I achieve this?
Thanks
Course to course staff is one to many relationship. The related manager will not return a single object instead multiple objects. Instead you can try different approach if course is going to have only one staff use OneToOneField and continue in same way.
Other way is to create a nested serializer for staff and the use in the course serializer.
class CourseStaffSerializer(serializers.ModelSerializer):
class Meta:
model = CourseStaff
fields = '__all__'
class TeacherCourseSerializer(serializers.ModelSerializer):
teachers = CourseStaffSerializer(many=True, read_only=True)
class Meta:
model = Course
fields = '__all__'
I have a base model and 2 child models inheriting from base model
class Module(models.Model):
name = models.CharField(max_length=200, null=False)
def __str__(self):
return self.name
class A(Module):
title = models.CharField(max_length=300, null=False, verbose_name='Title')
image = models.FileField(upload_to='uploads/', null=True)
class B(Module):
title = models.CharField(max_length=300, null=False, verbose_name='Title')
sub_title = models.CharField(max_length=300, null=False, verbose_name='Title')
image = models.FileField(upload_to='uploads/', null=True)
This is working fine, Django creates table inside child model table that references to parent.
Now, where I struggle is that there is an additional app with its own model that needs to query related parent model with its all child models. Lets assume this is my app referencing to module class
class Page(models.Model):
title = models.CharField(max_length=300, null=False)
slug = models.SlugField(max_length=300, null=False, db_index = True)
modules = models.ManyToManyField('modules.module')
By this current setup, Django stores parent model id in child model table, I'm not using django on client side hence in my sql query I'd like to get the child module attached to parent, by having a reference to what child model is referencing to. Please have in mind, Parent is linked to only one model.
I've looked at abstract, proxy models as well as model_utils.managers InheritenceManager but none stored child model information in parent.
How do I achieve that?
Thanks
The relationship is already defined by the ManyToManyField. Being able to display it is perhaps the question you're getting at.
You can reference the "through" model and register it in Admin like so:
from django.contrib import admin
# https://docs.djangoproject.com/en/3.0/ref/contrib/admin/#inlinemodeladmin-objects
#
# You can use TabularInline, or StackedInline --- whichever meets your style preferences
#
class PageModuleInline(admin.TabularInline):
model = Page.modules.through # the implicit "join table" model
class PageAdmin(admin.ModelAdmin):
inlines = [
PageModuleInline,
]
class ModuleAdmin(admin.ModelAdmin):
inlines = [
PageModuleInline,
]
see: https://docs.djangoproject.com/en/3.0/ref/contrib/admin/#working-with-many-to-many-models
I am running into an issue with prefetch_related on a property of an inherited model.
In models.py I have:
class Security(models.Model):
name = models.TextField()
...other fields
class Fund(Security):
...other fields
#property
def underlying_security(self):
return self.maps_when_mapped.get().original_security
class SecurityToSecurityMap(models.Model):
original_security = models.ForeignKey(Security, related_name="maps_when_original")
mapped_security = models.ForeignKey(Security, related_name="maps_when_mapped")
and in serializers.py
class UnderlyingSecuritySerializer(serializers.Serializer):
id = serializers.IntegerField()
name = serializers.CharField()
class FundSerializer(serializers.ModelSerializer):
underlying_security = UnderlyingSecuritySerializer(read_only=True, allow_null=True)
class Meta:
model = Fund
fields = ("id", "name", "underlying_security")
Now, I when I am querying fund objects:
queryset = Fund.objects.prefetch_related("maps_when_mapped__original_security")
Django ignores prefetching. Experimented with `Prefetch, tried moving property to the parent - no luck, still getting hundreds on queries. Any way this can be optimised?
I am using Django 2.2 with Postgres 11
UPDATE 1
After looking at the question, I suspect that problem is when I use .get() in property, it is immediately evaluated but then not sure how to fetch it without evaluation
Suppose I have a set of Django models that are all subclasses of an abstract Base model:
from django.db import models
class Base(models.Model):
created = models.DateTimeField(auto_now_add=True)
class Meta:
abstract = True
class Derived1(Base):
name = models.CharField(max_length=32, null=False, unique=True)
whatever = models.CharField(max_length=255, null=True, blank=True)
Now I can get the Field objects for Derived1 like this:
fields=models.Derived1._meta.get_fields()
This gives me all the fields, including the inherited "created" field.
Once I have this list of fields, is there any way to see that the field "created" was inherited from Base? Does the field object have any function or property that tells me the name of the model on which "created" was defined? Specifically I'm looking for some function field.get_model_name_where_defined() so that for fields defined on Derived1, that function returns "Derived1" but for the "created" field it returns "Base". Does anything like this exist?
Just to be clear, I am not looking for a way to assert that Derived1 is derived from Base. What I am looking for is a way to check any Django model and get the unknown name of the model class that is its abstract superclass, if there is such a class.
I want to define two model fields: created_by, modified_by in a parent model, they will be acting as common fields for the child models.
class ExtendedModel(models.Model):
created_by = models.ForeignKey(User,related_name='r_created_by')
modified_by = models.ForeignKey(User,related_name='r_modified_by')
class Meta:
abstract = True
class ChildModel1(ExtendedModel):
pass
class ChildModel2(ExtendedModel):
pass
this gives errors as ChildModel1 and ChildModel2 has related_name clashed with each other on their created_by and modified_by fields.
The Django docs explain how to work around this: http://docs.djangoproject.com/en/dev/topics/db/models/#abstract-related-name
class ExtendedModel(models.Model):
created_by = models.ForeignKey(User,related_name='"%(app_label)s_%(class)s_created_by')
modified_by = models.ForeignKey(User,related_name='"%(app_label)s_%(class)s_modified_by')
class Meta:
abstract = True
class ChildModel1(ExtendedModel):
pass
class ChildModel2(ExtendedModel):
pass