class Parent(models.Model):
pass
class RebelliousChild(Parent):
parent_fields = [__x.name for __x in Parent._meta._fields()]
Django 1.3 responds:
django.core.exceptions.FieldError: Local field '_RebelliousChild__x'
in class 'RebelliousChild'clashes with field of similar name from base class 'Parent'
Django 1.5 responds:
FieldError: Local field u'id' in class 'RebelliousChild' clashes with field
of similar name from base class 'Parent'
My second reaction (after trying to make the variable private) was to delete the variable (which worked.)
parent_fields = [__x.name for __x in Parent._meta._fields()]
del __x
List comprehensions leak their control variables in Python 2.
Django prohibits overriding parent field attributes, which seems to be involved somehow, since Django 1.5 has the same issue. But in both cases the leaked attribute name _RebelliousChild__x isn't defined on Parent.
What is going on here?
PS
Using "list(x.name for x in Parent._meta._fields())" is prettier than "del x". See the aforementioned https://stackoverflow.com/a/4199355 about generators not leaking their control variables.
Have a look here: https://docs.djangoproject.com/en/1.5/topics/db/models/#multi-table-inheritance
In short, you don't need to apply the parent fields to the child(they already exist, but in a different table), you can access them directly on a RebelliousChild instance.
Related
I want to be able to have a foreign key to a parent class, thereby allowing queries of the children classes as well. All other solutions are nightmarish.
I have tried to make this (Destination is also a parent class that has a # of children classes I want to relate to):
class Destination(PolymorphicModel)
class Account(Destination)
class Organization(Destination)
class Person(Destination)
class Transaction(models.Model)
destination = models.ForeignKey(Destination, verbose_name="Destination", null=True, blank=True,
related_name="CompletedTransaction_Destination_FK")
I am referencing destination in other places as well.
This is the error message I get when I try to migrate:
psycopg2.IntegrityError: could not create unique index "baseapp_organization_organization_destination_ptr_id_key"
DETAIL: Key (organization_destination_ptr_id)=(1) is duplicated.
I would love it if I could make the destination class
abstract = True
but then I can't have a foreign key. I need to be able to choose all of those destinations, and they need to remain distinct, real models in the database.
I have also tried GenericRelations, but that proved to be a nightmare as I said earlier.
It feels like I could just get around this error somehow though, any help?
The solution, and I'm guessing it would apply to other errors where the index could not be created, was to wipe the database an delete all the migrations. It was a pain to be sure, but now I can do:
destinations = Destination.objects.all()
and it will give me all the objects, as according to django polymorphic
i have three classes. Place is foreignkey of Activity(where the activity takeplace), Park and Restarant are inherited from Place.
class Activity(Model):
place=ForeignKeyField('Place')
....
class Place(Model):
address=CharField(max_length=200)
....
class Park(Place):
ticket_price=Decimal()
....
class Restarant(Place):
manager_name=CharField(max_length=100)
how can i get the real type of 'Place' in a query on Activity,so i can get the additional attributes of child type.
activity_list= Activity.objects.all()
all the activity_list[n].place are 'Place' ,neither Park or Restarant, so i can't get 'ticket_price' or 'manager_name' directly.
i have checked the model-utils, and can't find a easy way to do this.
any help will be appreciated.
inspect.getmro(cls)
Return a tuple of class cls’s base classes, including cls, in method resolution order. No class appears more than once in this tuple. Note that the method resolution order depends on cls’s type. Unless a very peculiar user-defined metatype is in use, cls will be the first element of the tuple.
try:
import inspect
for activity in activity_list:
print inspect.getmro(activity.place)
or try :
for activity in activity_list:
print activity.place._type()
try:
activity_list= Activity.objects.all()
for act in activity_list:
for b in act.place.__class__.__bases__:
print b.__name__
I use Django Inheritance Managers for this, from django-model-utils. It allows you to do exactly what you want...you said you checked model-utils to do this, but it didn't work. It should work -- what did you try with django-model-utils? You need to add this line to the parent model of Place:
objects = InheritanceManager()
I haven't tried this with your exact model design, but have you tried something like:
places = Activity.objects.all().values_list('place_id', flat=True)
places_of_right_type = Place.objects.filter(pk__in=places).select_subclasses()
?
------ UPDATE --------
Not sure this will work, but throwing it out there as an idea...would only work for a get(), not all():
places = Activity.objects.get(pk=#).place.objects.select_subclasses()
The docs say that you can call select_subclasses() on the InheritanceManager itself, which is stored in .objects.
'MODEL' has a relation with model MODEL.IN.APP, which has either not been installed or is abstract.
This error arises when I move from an explicit reference to another model in another app:
foo = models.ForeignKey(project.app.models.OtherModel)
to a quoted version of the same (to remove circular references)
foo = models.ForeignKey("project.app.models.OtherModel")
This has stung me three times now, and I've googled the same question asked elsewhere (without the correct answer).
Django's ForeignKey takes either the Model object itself or a Django-specific string representation of the model. The string is the app-name and the model name, so the correct form is:
foo = models.ForeignKey("app.OtherModels")
not
foo = models.ForeignKey("project.app.models.OtherModels")
Using the fully qualified name in quotes gives the rather odd error message in the original question.
This is a fun one :-)
Working on an EAV, we inject a generic relationship handler at runtime in a model.
model_cls is any class, and a EavValue class have a generic relation pointing to it. It works fine from EavValues to a model_cls, but on the other way we need to inject an accessor to ease things:
generic_relation = generic.GenericRelation(EavValue,
object_id_field='entity_id',
content_type_field='entity_ct',
related_name=model_cls.__name__)
generic_relation.contribute_to_class(model_cls, 'eav_values')
Again, we do that at runtime because we want to make it work with untouchable 3rd party libs.
While unittesting with a Patient class as model_cls, we get the following error:
eav_ng.patient: Accessor for m2m field 'eav_values' clashes with related m2m field 'EavValue.Patient'. Add a related_name argument to the definition for 'eav_values'.
Now, we thought the easy fix was to change either the second parameter of contribute_to_class or related_name in GenericRelation, but it doesn't! We get exactly the same error, only with different name.
Second strange thing, running the same unittests with Sqlite instead of MySql: all pass.
What's more, no matters the order or the tests, we always get this error at the second tests. Since this process happen in a register method and that we call register and unregister at setup and tear down, I'm guessing our unregister method is imperfect.
Last strange fact: we get the error while running unittest, but we are unable to reproduce it manually. Worst, on my colleague computer, it doesn't get the error while we are using the same version of Python, Django, Ubuntu and MySQL.
We solved a lot of hard ones but we are kind of stuck on this one so any clue appreciated.
UPDATE:
New clues for this great game:
Errors are raised from this snippet in django.core.management.validation, on line 245 (django 1.2.1):
for r in rel_opts.get_all_related_many_to_many_objects():
if r.field is not f:
if r.get_accessor_name() == rel_name:
e.add(opts, "Accessor for m2m field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
if r.get_accessor_name() == rel_query_name:
e.add(opts, "Reverse query name for m2m field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
For us r.get_accessor_name() == rel_name is True, as both are "Patient".
UPDATE 2:
When we add an app that register a model. Any model, the problem doesn't appear anymore. So much for the unregister theory...
We at two symmetrical errors (both sides of the relation). Removing related_name suppress one of the errors 0_o
Found the solution
Adding a generic relation on put a reference in the model class _meta.local_many_to_many attribute which is a list. Django check against that but provides no way to get rid of it. Fix is:
# remove remaining reference to the generic relation
for field in model_cls._meta.local_many_to_many:
if field.name == 'eav_value': # your related name
model_cls._meta.local_many_to_many.remove(field)
break
I have a Django model with some fields that have default values specified. I am looking to grab the default value for one of these fields for us later on in my code. Is there an easy way to grab a particular field's default value from a model?
TheModel._meta.get_field('the_field').get_default()
As of Django 1.9.x you may use:
field = TheModel._meta.get_field('field_name')
default_value = field.get_default()
You can get the field like this:
myfield = MyModel._meta.get_field_by_name('field_name')
and the default is just an attribute of the field:
myfield.default
if you don't want to write the field name explicitly, you can also do this:
MyModel._meta.get_field(MyModel.field.field_name).default
If you need the default values for more than one field (e.g. in some kind of reinitialization step) it may be worth to just instantiate a new temporary object of your model and use the field values from that object.
temp_obj = MyModel()
obj.field_1 = temp_obj.field_1 if cond_1 else 'foo'
...
obj.field_n = temp_obj.field_n if cond_n else 'bar'
Of course this is only worth it, if the temporary object can be constructed without further performance / dependency issues.