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)
Related
suppose that i have a module like below
class B:
def ...
def ...
class A:
b: B
def ...
def ...
I use class B only as member variable of class A
when i try to abstract this module for my buisness logic, what should i do?
one big interface, which has abstract method for class A and class B
two interface, which has abstract method for class A and class B individually
all above are wrong. another way
Both, 1 & 2 are correct approach, but it completely depends on your application.
I think, two interfaces, which would have abstract method for class A and class B individually is the right approach when both of your classes have separate workings and are completely different from each other.
But, as you have mentioned in your code that you have inherited class B in class A. If you create a single interface for class A, it will also allow you to access the methods from class B. So, this approach is good. Also, this approach will shorten the length of your code, resulting in fast processing.
I hope this would help you to take your decision. Let me know if any other clarification required.
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.)
Suppose I have my models set up like this:
class B(Model):
...
def __str__(self):
return "B"
class C(B):
...
def __str__(self):
return "C"
class A(Model):
b = ForeignKey(B)
def __str__(self):
print "A: %s"%(self.b)
a = A(b=C(...))
a.save()
print str(a) # Prints "A: B"
Maybe I'm a bit confused how django inheritance works. My intention is to have the program print "A: C" at runtime (since A.b is an instance of model C)
I think I might be asking about multi-table inheritance. But that's only if you know what instance of a subclass you want.
As another example of how I'm confused, I'd like to borrow the example from the docs:
# Assume Restaurant, Park, and Museum inherit Place
bills = Restaurant.objects.create(name="Bill's Pub", burger="Bill's Burger")
city_prk = Park.objects.create(name='City Park', num_trails=5)
nose = Museum.objects.create(name='Nose Museum', est=1940)
places = Places.objects.all()
I'll definitely get a list of 3 objects (of type Place) but I have no way of differentiating the types of places. For example, if I want to print out the str value of each place...
for place in places:
print str(place)
...python will just execute Place.__str__() and not Restaurant.__str__() (for the restaurant) or Park.__str__() (for the park). This doesn't seem to happen with "normal" python. Python should normally automatically find the lowest-inherited class and execute the overridden function from that (if B overrides a method from A, B's method will be executed).
Are my assumptions correct? Sorry for the long question (and sorry if it's not clear). I'm not exactly sure how to ask what I'm wondering.
You are correct that most python objects work that way, but django models do not. You are doing a multi-table inheritance. Which will create a parent table - B, and a child table - C. C would have a primary key named b_ptr_id which is also a foreign key to B.id. Since A contains a foreign key to B, that is what you get. You can reference the child object like this:
b_object = B.objects.get(…)
c_object = b_object.c
But of course if multiple tables inherited from B, you would not no which child object to extract. This utility might help you: https://django-model-utils.readthedocs.org/en/latest/managers.html#inheritancemanager it will do just what you need. Calling .select_subclasses() on a query set will automatically "cast" each object to whatever child object it "really" is.
Actually, after doing more research, I've found what I was looking for was the "polymorphic" app, found here: https://github.com/bconstantin/django_polymorphic
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.
Suppose I have the following models:
class User(models.Model):
pass
class A(models.Model):
user = models.ForeignKey(User)
class B(models.Model):
a = models.ForeignKey(A)
That is, each user owns some objects of type A, and also some of type B. Now, I'm writing a generic interface that will allow the user to view any objects that it owns. In a view, of course I can't say something like "objects = model.objects.filter(user=user)", since B has no attribute 'user'. What's the best approach to take here?
The way I would do it is to simply go through the object 'a' on class B. So in the view, I would do:
objects = B.objects.get(user=a.user)
objects += A.objects.get(user=user)
The reason I would do it this way is because these are essentially two database queries, one to retrieve a bunch of object A's and one to retrieve a bunch of object B's. I'm not certain it's possible in Django to retrieve a list of both, simply because of the way database inheritance works.
You could use model inheritance as well. This would be making a base class for both objects A and B that contains the common fields and then retrieving a list of the base classes, then convert to their proper types.
Edit: In response to your comment, I suggest then making a base class that contains this line:
user = models.ForeignKey(User)
Class A and B can then inherit from that base class, and you can thus now just get all of the objects from that class. Say your base class was called 'C':
objects = C.objects.get(user=user)
That will obtain all of the C's, and you can then figure out their specific types by going through each object in objects and determining their type:
for object in objects:
if object.A:
#code
if object.B:
#code