I have two classes in order:
class A(models):
...
class B(models):
a = models.ManyToManyField(A)
Now I have to change my model to one below:
class A(models):
b = models.ManyToManyField(B)
class B(models):
...
I have to use south migrations. I wanted to create new many to many field in class A, migrate data and delete field from class B. The problem is that both are in same model. So when I put many to many into A class it cannot be seen. Because B declaration is below A. How to solve this problem?
At least SQLAlchemy allows you to use a string instead of a class. Try if django-orm allows that, too.
a = models.ManyToManyField('A')
# ...
b = models.ManyToManyField('B')
Update: According to Django/Python Circular model reference that's exactly the way to go.
Related
Hopefully my question won't have been asked before.
I've the following models in my Django app:
from django.db import models
class A(models.Model):
some_attribute = models.SomeField()
def some_method(self):
do_stuff()
# Note: not abstract
class B(A):
def some_other_method(self):
do_other_stuff()
Now, if I have one A and one B in the database,
when I issue a A.objects.filter() call, I get the A
and also the B instance (as expected).
But what if I in fact only want the instances of A specifically?
I don't see how to write is as an .exclude() instruction.
Could filtering with type == "A" be the intended way?
Follow-up: what if I have a class C inheriting from B, and so on, and want to exclude all instances of inheriting models?
You can filter with:
A.objects.filter(b=None)
to retrieve the A objects for which there is no B instance. This will make a LEFT OUTER JOIN on the B model, and thus only retain items where B is NULL.
Or you can omit all subclasses of A with:
data = {
f.name: None
for f in A._meta.get_fields()
if f.one_to_one and A in f.related_model.__mro__
}
A.objects.filter(**data)
Lets say i have 3 classes, A, B, C.
class A(models.Model):
comment = models.CharField(max_length=600, default="None")
rating = models.IntegerField(default=1, choices=CHOICES, name='rating')
date = models.CharField(max_length=50, default='nonee')
class B(models.Model):
Aname = models.ForeignKey('A', related_name='AB')
classC = models.ForeignKey('C', related_name='BC')
class C(models.Model)
#some info
def average_rating(self):
return self.?????.all().aggregate(Avg('rating')).values()[0]
How is it that I go from a view where my self is an object, all the way back to Class A so that I can aggregate the rating numbers. If i understand this correctly, the whole point of class B is just to be an object which shows relationships? I have been able to go between two classes, but when a third "relational" one is there i can't seem to get it to work.
When an operation needs to be performed on a recordset (queryset) basis rather than single record (model), then you should consider custom managers.
Adding extra Manager methods is the preferred way to add “table-level” functionality to your models. (For “row-level” functionality – i.e., functions that act on a single instance of a model object – use Model methods, not custom Manager methods.)
You don't need class B at all. What you need is a ManyToManyField between A and C; that will, behind the scenes, create a table similar to B, but unless you actually need to add fields on that table you're better off not defining it explicitly.
Once you've added the M2M on C, your average_rating method can use it directly:
class C(models.Model)
model_a_s = models.ManyToManyField('A')
def average_rating(self):
return self.model_a_s.all().aggregate(Avg('rating')).values()[0]
(Note, the title of your question is a bit confusing; there are no views involved here at all.)
I simplify my code structure, which contains two models:
# created by third part app, not Django one
# but we share same DB, so i have access to this one
class A(models.Model):
title = models.TextField()
# other fields ...
class Meta:
manage = False
class B(models.Model):
model_a = models.OneToOneField(A, related_name='+')
# other fields, to extend model A functionality
Is this a good way to extend third part app model A with my additional fields and methods? Now i have problem to sync this models true one-to-one field. Since I don't have access to trigger model A creation.
In ideal world i should have CarA and CarB. And CarB = CarA relation should be created if CarB exists.
I base this idea on Django 1.5 user extension. Is this clear enough? Or should i do something else?
You could use a property to create the B instance on access if it doesn't exist yet, ie,
class A(models.Model):
title = models.TextField()
# other fields ...
class Meta:
manage = False
#property
def b(self):
if not hasattr(self, "__bcache"):
self.__bcache, created = B.objects.get_or_create(model_a = self)
return self.__bcache
It seems like you're new to both Python and Django so let's explain quickly...
First, the "#property" part: it's a decorator that turns the following function into a computed attribute - IOW you use it as an attribute (myA.b.whatever), and under the hood it turns it into a method call (myA.b().whatever). It's not strictly required here, we would have used an explicit getter (the same method named get_a()) but it's cleaner that way.
Then our method implementation: obviously we don't want to hit the database each time someone looks up A.b, so
first we check if an attribute named __bcache ("b" "cache") is set on the current instance.
if not, we call B.objects.get_or_create(a_model=self) which will either retrieve the existing B instance for this A instance or create one if none exists yet and we store this B instance as self.__bcache so next call will retrieve it directly from __bcache instead of hitting the database.
and finally we return self.__bcache that is now garanteed to exists and point to the related B instance.
i' ve 2 model which needs to refer to each other in a way, but of course the second is not read when the first tries to reach it. How could i somehow preimport the models? I also tried from the init, but didn' t really work.
Thanks.
example:
class Follow(models.model):
auto_data = models.ForeignKey(Autodata)
class Autodata(models.model):
follow = models.ForeignKey(Follow)
You can pass strings into ForeignKey so they are not evaluated till runtime:
class A(models.Model):
b = models.ForeignKey('B')
class B(models.Model):
a = models.ForeignKey('A')
am not entirely sure if what am about to do is programmically possible. Although if this works, It will help me a lot organize my code.
class AuditColumns(models.Model):
created_at=models.DateField("Created at")
created_by=models.ForeignKey(User, db_column="created_by", related_name="%(app_label)s_%(class)s_y+")
updated_at=models.DateTimeField("Updated at")
updated_by=models.ForeignKey(User, db_column="updated_by", null=True, blank=True, related_name="%(app_label)s_%(class)s_y+")
class Meta:
abstract = True
def return_audit_columns(self):
return self.created_at, self.created_by, self.updated_at, self.updated_by
class Choice(models.Model):
choice=models.CharField(max_length=200)
def __init__(self):
self.created_at, self.created_by, self.updated_at, self.updated_by=AuditColumns.return_audit_columns(self)
the code above does not work, it was my attempt or what I wish to do. Basically, I have the class AuditColumns which contain this set of columns and I wish to use them in different models across my projects. I do not want the Choice model to inherit from AuditColumns because am going to use the same technique to include other columns from other sources into my Choice class.
off course what I wrote above is not practical either because I will have to repeat the column names every time I want to include the AuditColumns in one of the models across my project.
Is what I want to do achievable or not?
The usual way to do this is with content types. You create a model similar to AuditColumns, but you also include another field, a GenericForeignKey, which can point to any model within the project's database.
Python will let you do multiple inheritance so you can inherit the attributes of multiple base classes into your Choice class, that may be what you want.
class Choice(AuditColumns,Foo):
choice=models.CharField(max_length=200)
Would give your Choice class the attributes of the AuditColumns class, and the Foo class. You are also misusing self in your example. You are calling the return_audit_columns method of the AuditColumns class that is expecting an instance of that class but passing in an instance of the Choice class which is not what you want.