Django - Append a related field to a queryset - django

I have two models:
class A(models.Model):
# fields
class B(models.Model):
a = models.ForeignKey(A)
name = models.CharField(max_length=64)
What I want to do is to get a filtered queryset from A in addition to the related objects from B and append them to the queryset from A, so I would be able to access name field this way: A.B.name
Any idea how to do this?

The problem is that, since the relationship is one-to-many, A doesn't have just one B, but rather a b_set
You could so something like:
for b in a.b_set.all():
b.name
But you can't reference just B because that concept doesn't exist. It would however, if you had used a OneToOneField. Then you could easily do:
a.b.name
Because there's only one B for each A. But, you have to model your object after the actual relationships going on, not how you would prefer the api to work.

Related

Django Using ManyToMany from the other side instead of ForeignKey

In a specific Django app, I have a DB Model class A that is considered as the main class and many other models are connected to it weather through one to one relationship (like B) or one to many relationship (like C). So, the direct approach to implement such is:
class A(Model):
b = OneToOneField('B', on_delete=CASCADE)
# other fields
class B(Model):
# some fields
class C(Model):
a = ForeignKey(A, on_delete=CASCADE)
# other fields
Now, when I want to create a new object of A, the sequence will be:
create B object
create A object and link the created B object to it
create C object and link the created A object to it.
This happens on a larger scale with a lot of models linked with model A. But I want to have all the relations seen in the A class so that when I want to create an object of A, I go to create all the related objects first after validating them regardless the relationship, then create new A object and link all those related objects to it. So, I did so:
class A(Model):
b = OneToOneField('B', on_delete=CASCADE)
c = ManyToManyField('C') # as there is no OneToManyField
class B(Model):
# some fields
class C(Model):
# some fields
But this solution seems not good as C should have only one A object.
Is it acceptable to do this or is there another good practice approach to do?
OneToMany is equal to ForeignKey constructor.
class A(Model):
b = OneToOneField('B', on_delete=CASCADE)
c = Foreignkey('C', on_delete=CASCADE)
class B(Model):
# some fields
class C(Model):
# some fields
seems totally fine approach to me.

Django: Get objects for which ForeignKey does not exist

Given:
class A(models.Model):
...
class B(models.Model):
...
class C(models.Model):
a = models.ForeignKey(A)
b = models.ForeignKey(B)
For a fixed b of class B, I would like to retrieve all those Objects a from A, for which there is no entry (a,b) in C.
I am failing to come up with a correct filter to achieve this.
Start with class A, since that's the type of object you ultimately want. You'll either want to filter those or exclude them. We could try to filter for the objects that don't have a matching entry, but you know what? It'll be easier to exclude the ones that do have a match.
Assuming class A has a related field of c for the C.a foreign key...
A.objects.exclude(c__b=b)

Restricted ManyToMany relationships in Django

I'm hoping someone can point me to the most Djangoic way to represent the following general relationship with models, so that Django's existing logic naturally enforces the relationship.
Thing A and Thing B both have one of a number of Types. Thing A can be related to many, one, or no Things Bs and vice-versa (in a symmetric fashion), however Thing A and Thing B can be related if and only if they share the same Type.
My current implementation is to have three models, A, B, and Type, where As and Bs have a foreign key to Type, and A has a m2m with B.
class A(models.Model):
b = models.ForeignKey(B)
typ = models.ManyToManyField(Type)
class B(models.Model):
a = models.ForeignKey(A)
class Type(models.Model):
name = models.CharField()
This lets me do what I want, but doesn't enforce the fact that A can't have a B of another Type. I can use filtering logic in views I control, but where I have less control, like in the Admin, Django lets me map As to Bs of different Types. Is there another way to represent the relationship between As, Bs, and Types in Django?
This would be my approach off the top of my head:
class A(models.Model):
typ = models.ManyToManyField(Type)
#property
def related2B(self)
return list of relationships
def save
check that relationship is still valid if typ field changes
class B(models.Model):
typ = models.ManyToManyField(Type)
#property
def related2A(self)
return list of relationships
def save
check that relationship is still valid if typ field changes
class Type(models.Model):
name = models.CharField()
class Relationship(models.Model):
classA = models.ForeignKey(A)
classB = models.ForeignKey(B)
def save
do check that they share a type before saving
Have you looked at limit_choices_to as a way to control the scope of the M2M?
It can take Q objects for complex queries, but am guessing not F ones (for complex queries including the parent object's current state), but you still might be able to make it deny the save if inappropriate

Django Models - Foreign Key of different objects types that share a common base class

I have the following conceptual design in mind for one of my models.
class A(models.Model):
...
class B(A): #Inherits A
fieldA = ...
fieldB = ...
class C(A): #Inherits A
fieldC = ...
fieldD = ...
class D(models.Model):
field = models.ForeignKey(A) #Here lies the problem, should store B or C
Given the models above, I'd like to store a foreign key to either B or C in D but not both.
I tried setting the Meta class property of A to abstract but that doesn't allow a ForeignKey relationship to A. I do not want to ever have an instance of A that isn't B or C, but if necessary, I can restrict this behavior with the save signal.
Is there an easier design that would allow me to store a foreign key from a list of types where all classes inherit from a common base?
I can think of two options:
Use a generic relation in your D class instead of a foreign key.
If you don't need to filter D using specific fields from B or C you could continue with the approach you have now, but add a method to D that would retrieve the child class of field:
class D(models.Model):
field = models.ForeignKey(A)
def get_field(self):
try:
return self.field.b
except B.DoesNotExist:
pass
try:
return self.field.c
except C.DoesNotExist:
pass
This definitely has some performance implications and as you said in your post, you would have to manually ensure that every instance of A has a B or C subclass. Obviously this approach doesn't scale well if you are going to have n number of subclasses.

how to handle many to many relationships in modelForms

I have a model similar to this one:
class A(models.Model):
name = models.CharField(primary_key=True)
class B(models.Model):
(morefields)
target = models.ManyToManyField(A,through='C')
class C(models.Model):
a_key = models.ForeignKey(A)
b_key = models.ForeignKey(B)
(extra fields)
I am creating a form to edit an item of B using a modelForm. However, I get "Cannot set values on a ManyToManyField which specifies an intermediary model" error. If I exclude the target field it works fine.
Could you suggest any way to workaround this?
You can use inlines. The problem is that Django can't create the relation for you because there's additional fields that must be set on the join table (your "through" model). Try the following:
class CInlineAdmin(admin.TabularInline):
model = C
extra = 1
class BAdmin(admin.ModelAdmin):
inlines = [CInlineAdmin,]
By your own mentioning above, you have (extra fields) in Class C. How is django supposed to populate those extra fields, if by using given A, you want to create more B's.
You should probably create an admin for C, where in you can add each A and B to a given C