let I have a model with ForeignKey to another:
class Photo(models.Model):
name = models.CharField(max_length=64)
album = models.ForeignKey('Album')
And that 'Album' model must to connect this photo's objects to its ManyToManyField automatically:
class Album(models.Model):
name = models.CharField(max_length=64)
photoItems = models.ManyToManyField(Photo)
And the question is how can I do this?
You could do it the following way, and Django should automatically add a reverse relation. Hence, no need to add album as foreign key to your Photo model. Doing this you get access to "albums" from your Photo model.
class Photo(models.Model):
name = models.CharField(max_length=64)
class Album(models.Model):
name = models.CharField(max_length=64)
photoItems = models.ManyToManyField(Photo, related_name='albums')
Shell:
>>> photo1=Photo(name="photo number 1")
>>> photo2=Photo(name="photo number 2")
>>> photo1.save()
>>> photo2.save()
>>> album=Album(name="album1")
>>> album.save()
>>> album.photoItems.add(photo1,photo2)
>>> photo1.albums.get().name
'album1'
Related
e.g. I've a person with an address
class Persons(models.Model):
adress = models.ForeignKey(Adress, on_delete=models.DO_NOTHING, blank=True,
null=True)
class Adress(models.Model):
some_data = models.IntegerField()
and i have another related data in antoher model like this
class Places(models.Model):
adress = models.ForeignKey(Adress, on_delete=models.DO_NOTHING)
how can i get a queryset now of both persons and places if adress is set in persons?
You can obtain the Places of a Persons object with:
Places.object.filter(adress__persons=myperson)
If you want to do this in bulk, you can work with:
qs = Persons.objects.select_related('adress').prefetch_related('adress__places_set')
this will load the related Places in bulk, so you can fetch these with:
for person in qs:
print(person.adress.places_set.all())
You can do somethings like this but first you need to add related_name in your Persons and Places Foreign key
class Persons(models.Model):
adress = models.ForeignKey(Adress,related_name = "persons_adress",on_delete=models.DO_NOTHING, blank=True,null=True)
class Adress(models.Model):
some_data = models.IntegerField()
class Places(models.Model):
adress = models.ForeignKey(Adress, related_name = "places_addres",on_delete=models.DO_NOTHING)
After this alteration you can now query
Adress.objects.filter(persons_adress__some_data = some_data,places_addres__some_data = some_data)
I'm trying to write up a Factory for a model with a GFK for testing but I can't seem to get it working. I've referred to the common recipes in the docs, but my models don't match up exactly, and I'm also running into an error. Here are my models
class Artwork(models.Model):
...
region = models.ForeignKey("Region", on_delete=models.SET_NULL, null=True, blank=True)
class Region(models.Model):
# Could be either BeaconRegion or SpaceRegion
region_content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
region_object_id = models.PositiveIntegerField()
region = GenericForeignKey("region_content_type", "region_object_id")
class SpaceRegion(models.Model):
label = models.CharField(max_length=255)
regions = GenericRelation(
Region,
content_type_field="region_content_type",
object_id_field="region_object_id",
related_query_name="space_region",
)
class BeaconRegion(models.Model):
label = models.CharField(max_length=255)
regions = GenericRelation(
Region,
content_type_field="region_content_type",
object_id_field="region_object_id",
related_query_name="beacon_region",
)
Essentially, an Artwork can be placed in one of two Regions; a SpaceRegion or BeaconRegion.
I've created the following Factorys for the corresponding models
class RegionFactory(factory.django.DjangoModelFactory):
region_object_id = factory.SelfAttribute("region.id")
region_content_type = factory.LazyAttribute(
lambda o: ContentType.objects.get_for_model(o.region)
)
class Meta:
exclude = ["region"]
abstract = True
class BeaconRegionFactory(RegionFactory):
label = factory.Faker("sentence", nb_words=2)
region = factory.SubFactory(RegionFactory)
class Meta:
model = Region
class SpaceRegionFactory(RegionFactory):
label = factory.Faker("sentence", nb_words=2)
region = factory.SubFactory(RegionFactory)
class Meta:
model = Region
class ArtworkFactory(factory.django.DjangoModelFactory):
...
region = factory.SubFactory(SpaceRegionFactory)
In my test, I try to create an Artwork using ArtworkFactory(), but it errors with
AttributeError: The parameter 'region' is unknown. Evaluated attributes are {}, definitions are <DeclarationSet: {'region_object_id': <SelfAttribute('region.id', default=<class 'factory.declarations._UNSPECIFIED'>)>, 'region_content_type': <factory.declarations.LazyAttribute object at 0x1068cf430>, 'label': <factory.faker.Faker object at 0x1068cf880>}>
What am I doing wrong here?
The issue comes when resolving ArtworkFactory.region.region, i.e SpaceRegionFactory.region.
From your models, it seems that:
Region is a table which points to either SpaceRegion or BeaconRegion
SpaceRegion and BeaconRegion are simple tables, with a helper to retrieve the related Region object.
The first step in those complex relation chains is to write the code without factories:
>>> shire = SpaceRegion(label="Shire")
>>> shire_generic = Region(region=shire)
>>> the_ring = Artwork(region=shire_generic)
This tells us that the Region is always created after the SpaceRegion or BeaconRegion, giving the following factories:
class SpaceRegionFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.SpaceRegion
label = factory.Faker("sentence", n_words=2)
class RegionFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.Region
region = factory.SubFactory(SpaceRegionFactory)
class ArtworkFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.Artwork
region = factory.SubFactory(RegionFactory)
With this, you should be able to get your code working.
Note how we're simply setting the region field on Region: Django's internals will extract the object content type / content ID automatically.
Additional options
You could tune the RegionFactory to let callers decide whether they want a SpaceRegion or a BeaconRegion:
class RegionFactory(factory.django.DjangoModelFactory):
class Meta:
models = Region
class Params:
space = True # Request a SpaceRegion
region = factory.Maybe(
factory.SelfAttribute("space"),
factory.SubFactory(SpaceRegion),
factory.SubFactory(BeaconRegion),
)
I am struggling to understand django models relationship.
I have this arborescence:
A train have cars, and those cars are divided into parts. Then those parts all contains different references.
Like, for exemple, all the trains have the 6 cars, and the cars 6 parts. Each part have x reference to be associated.
I would like to use all of them in a template later on, where the user can select the train, the car and the part he worked on, then generate a table from his selections with only the references associated to the parts he selected.
It should update the train and the car (I'm trying to update a stock of elements for a company)
I dont really understand which model field give to each of them. After checking the doc, Ive done something like this but i am not convinced:
class Train(Car):
train = models.CharField(max_length=200)
id = models.CharField(primary_key='True', max_length=100)
selected = models.BooleanField()
class Meta:
abstract = True
class Car(Part):
car = models.CharField(max_length=200)
id = models.CharField(primary_key='True', max_length=100)
selected = models.BooleanField()
class Meta:
abstract = True
class Part(Reference):
part = models.CharField(max_length=200)
id = models.CharField(primary_key='True', max_length=100)
selected = models.BooleanField()
class Meta:
abstract = True
class Reference(models.Model):
reference = models.CharField(max_length=200)
id = models.CharField(primary_key='True', max_length=100)
selected = models.BooleanField()
def __str__(self):
return self.reference
Can someone please help me understand this so I can do well ? Thanks!!
1-)if you add abstract = True in your Model Meta class, your class doesn't created on database as a table. If you store data for any class, you mustn't define abstract = True.
2-)For relations, you can use models.ForeignKey . If you add a class into brackets of another class, it names: inheritance.(You can think like parent-child relation). In database management, we can use foreignkey for one-to-many relationship.
3-)In Django ORM, id field automatically generated. So you don't need to define id field.
If I understand correctly, also you want to store parts of user's selected.
So, your model can be like that:
class Train(models.Model):
name = models.CharField(max_length=200) # I think you want to save name of train
class Car(models.Model):
train = models.ForeignKey(Train,on_delete=models.Cascade)
name = models.CharField(max_length=200)
class Part(models.Model):
car = models.ForeignKey(Car,on_delete=models.Cascade)
name = models.CharField(max_length=200)
class Reference(models.Model):
part = models.ForeignKey(Part,on_delete=models.Cascade)
name = models.CharField(max_length=200)
def __str__(self):
return self.reference
#addtional table for storing user's references
class UserReference(models.Model):
user = models.ForeignKey(User,on_delete=models.Cascade)
reference = models.ForeignKey(Reference,on_delete=models.Cascade)
name = models.CharField(max_length=200)
With this definitions, you can store user's definition on UserReference table. And with Django Orm, you can access train object from UserReferenceObject.
#user_reference: UserReference object like that result of UserReference.objects.first()
user_reference.reference.part.car.train.name
How do you get a field related by OneToOneField and ManyToManyField in Django?
For example,
class A(models.Model):
myfield = models.CharField()
as = models.ManyToManyField('self')
class B(models.Model):
a = models.OneToOneField(A)
If I want to get a 'myfield' and all associated 'as' using class B, given a 'myfield' equal to a string like 'example', how is it done?
Models.py
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
def __str__(self): # __unicode__ on Python 2
return "%s the place" % self.name
class Restaurant(models.Model):
place = models.OneToOneField(
Place,
on_delete=models.CASCADE,
primary_key=True,
)
serves_hot_dogs = models.BooleanField(default=False)
serves_pizza = models.BooleanField(default=False)
def __str__(self): # __unicode__ on Python 2
return "%s the restaurant" % self.place.name
Let create a place instance.
p1 = Place.objects.create(name='Demon Dogs', address='944 W. Fullerton')
Then create a restaurant object.
r = Restaurant.objects.create(place=p1, serves_hot_dogs=True, serves_pizza=False)
Now, to access place from Restaurant:
>>> r.place
<Place: Demon Dogs the place>
vice-versa to access Restaurant from place
>>> p1.restaurant
<Restaurant: Demon Dogs the restaurant>
I did not understand the many-to-many field part can you please elaborate?
First you get an instance of B say b and you can easily access myfield and as through the a attribute of b
b.a.myfield
b.a.as.all()
Furthermore, CharField requires a max_length attribute as follows:
class A(models.Model):
myfield = models.CharField(max_length=128)
as = models.ManyToManyField('self')
class B(models.Model):
a = models.OneToOneField(A)
A general point, give more descriptive names to your models and their attributes, or at the very least, add comments explaining what these models represent
I'm trying to follow the code from the django docs:
class Person(models.Model):
name = models.CharField(max_length=128)
def __unicode__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __unicode__(self):
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person)
group = models.ForeignKey(Group)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
>>> ringo = Person.objects.create(name="Ringo Starr")
>>> paul = Person.objects.create(name="Paul McCartney")
>>> beatles = Group.objects.create(name="The Beatles")
>>> m1 = Membership(person=ringo, group=beatles,
... date_joined=date(1962, 8, 16),
... invite_reason= "Needed a new drummer.")
>>> m1.save()
>>> beatles.members.all()
[<Person: Ringo Starr>]
>>> ringo.group_set.all()
My model looks like this:
class Trip(models.Model):
members = models.ManyToManyField(User,blank=True,null=True,through='TripReservation')
But when I call user.group_set.all() for a given user instance, I get an error that there is no attribute group_set
First, are you using a through Model? You have through in there, but you don't have it listed. If you aren't you don't need it.
I would add a related_name, like so:
class Trip(models.Model):
members = models.ManyToManyField(User,blank=True,null=True, related_name='user_trips')
Then you should be able to call:
user.user_trips.all()
I called it 'user_trips' rather than 'trips' becuase if it isn't a unique name it can cause conflicts.
If you are using a through Model, it would look more like this:
#User is defined in django.auth
class Trip(models.Model):
members = models.ManyToManyField(User,blank=True,null=True, related_name='user_trips', through='TripReservation')
class TripReservation(models.Model):
user = models.ForeignKey(User)
trip = models.ForeignKey(Trip)
registered = models.DateField()
Understand that with this way, the TripReservation refers to a particular Users reservation to the Trip, not the whole trip, and information about the trip should be properties on the Trip model itself. So, TripReservation.registered, is when that particular user registered for the trip.
The user trips lookup would be the same:
user.user_trips.all()