I have an abstract Product model, and I wanted it to be able to hold more than one image, so I decided to make another Image model and have a ForeignKey to Product, however I quickly realised that's not possible. The reason I decided to go for abstract base model is performance gains since every child model is in its own table. Having a different Image model for each subclass sounds bad to me, since there will be more than 20 subclasses.
class Product(models.Model):
title = models.CharField(max_length=50)
description = models.CharField(max_length=50)
category = models.ForeignKey('Category', on_delete=models.CASCADE, blank=False)
class Meta:
abstract = True
class Book(Product):
author = models.CharField(max_length=50)
publisher = models.CharField(max_length=50)
class Shoes(Product):
colour = models.CharField(max_length=50)
size = models.CharField(max_length=50)
class Image(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='images')
image = models.ImageField(upload_to=get_image_path, blank=True, null=True)
How can I overcome the issue?
You can use a ManyToManyField:
class Product(models.Model):
title = models.CharField(max_length=50)
description = models.CharField(max_length=50)
category = models.ForeignKey('Category', on_delete=models.CASCADE, blank=False)
images = models.ManyToManyField(Image)
class Meta:
abstract = True
inserting data:
b1 = Book.objects.create(...) #can't include M2M yet
i1 = Image.objects.create(...)
i2 = Image.objects.create(...)
b1.images.add(i1, i2)
You can query the images like this:
books = Book.objects.all().prefetch_related('images')
images_for_book_1 = books[0].images.all()
Related
I have to identical models:
class AnimalGroup(models.Model):
name = models.CharField(max_length=50, unique=True)
description = models.TextField(max_length=1000, blank=True)
images = models.ImageField(upload_to="photos/groups")
class AnimalSubGroup(models.Model):
name = models.CharField(max_length=50, unique=True)
description = models.TextField(max_length=1000, blank=True)
images = models.ImageField(upload_to="photos/groups")
and they have a on-to-many relationship. So AnimalGroup can have multiple AnimalSubGroups
But as you see they have identical fields.
Question: how to make one model of this?
So that in Admin I can create animalgroups, like:
mammals
fish
And then I can create the subgroups. Like
bigCat and then I select mammals.
Have them inherit an abstract base class and give the subgroup an additional foreign key:
class AbstractAnimalGroup(models.Model):
name = models.CharField(max_length=50, unique=True)
description = models.TextField(max_length=1000, blank=True)
images = models.ImageField(upload_to="photos/groups")
class Meta:
abstract = True
class AnimalGroup(AbstractAnimalGroup):
pass
class AnimalSubGroup(AbstractAnimalGroup):
parent = models.ForeignKey(AnimalGroup, on_delete=models.CASCADE)
If you want subgroups to be actual AnimalGroups, you can use multi-table inheritence:
class AnimalGroup(models.Model):
name = models.CharField(max_length=50, unique=True)
description = models.TextField(max_length=1000, blank=True)
images = models.ImageField(upload_to="photos/groups")
class AnimalSubGroup(AnimalGroup):
parent = models.ForeignKey(AnimalGroup, on_delete=models.CASCADE)
Now, all AnimalSubGroups will be also contained in AnimalGroup.objects.all().
You can use an abstract base model:
class NameDescImageModel(models.Model):
name = models.CharField(max_length=50, unique=True)
description = models.TextField(max_length=1000, blank=True)
images = models.ImageField(upload_to='photos/groups')
class Meta:
abstract = True
class AnimalGroup(NameDescImageModel):
pass
class AnimalSubGroup(NameDescImageModel):
group = models.ForeignKey(AnimalGroup, on_delete=models.CASCADE)
I have 2 models like this:
class Category(MPTTModel):
name = models.CharField(max_length=100)
slug = models.SlugField(unique=True)
class Product(models.Model):
name = models.CharField(max_length=70)
category = models.ForeignKey(Category, null=True, on_delete=models.SET_NULL)
slug = models.SlugField(unique=True)
description = models.TextField(max_length=300)
and in every Category i need my Product to have multiple additional fields for example processors(Category#1) and SSD drives(Category#2)
Category#1-Product#1(-/-, total_cores, total_threads, ..), Product#2(-/-, total_cores, total_threads, ..), ...
Category#2-Product#3(-/-, storage_capacity, connector, ..), Product#4(-/-, storage_capacity, connector, ..), ...
Is there any way to add fields to Product depending on the Category it belongs to or i need to create models for each Category?
One possible solution to this could be to use JsonField if you're using Postgresql as a database
from django.contrib.postgres.fields import JSONField
class Product(models.Model):
name = models.CharField(max_length=70)
category = models.ForeignKey(Category, null=True, on_delete=models.SET_NULL)
slug = models.SlugField(unique=True)
description = models.TextField(max_length=300)
product_features = JSONField()
I have two models in my Django-REST application.
a ProjectRequest and a ContactRequest
I want to make it so, each Projectrequest contains a list of the refered Contactrequests.
class ProjectRequest(models.Model):
project_name = models.CharField(max_length=50)
company_name = models.CharField(max_length=50)
#make array of technologiestechnologies = models.ArrayField(base_field=) (blank=True)
project_description = models.CharField(max_length=200)
project_type = models.CharField(max_length=30)
budget_estimation = models.IntegerField(
default=1000,
validators=[
MinValueValidator(1800),
MaxValueValidator(5000000)
])
#time_estimation = models.DateTimeField(default=None, blank=True, null=True)
class ContactRequest(models.Model):
topic = models.CharField(max_length=30)
description = models.CharField(max_length=200)
time = models.CharField(max_length=15)
project_request = models.ForeignKey(ProjectRequest,
on_delete=models.CASCADE)
so far I have established a relationship, with a foreign key, which works fine as of now. However I want to extends the functionality, so, that the ProjectRequest contains a list of all the projectrequest. I have tried with several different fields, without any luck, and the documentation I can only find fields for ManyToMany and OneToOne. How can this be achieved?
There are many ways to achive what you want. For that, lets add a reverse relation in model named contact_requests:
project_request = models.ForeignKey(ProjectRequest, on_delete=models.CASCADE, related_name="contact_requests")
Now you can use PrimaryKeyRelatedField to show Primary Keys of the ContactRequest attached to each ProjectRequest.
class ProjectRequestSerializer(serializers.ModelSerializer):
contact_requests = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
class Meta:
model = ProjectRequest
fields = ('contact_requests', 'company_name', ...) # other fields
Or if you want all the values of each contact_requests, then you can use nested relationship like this:
class ProjectRequestSerializer(serializers.ModelSerializer):
contact_requests = ContactRequestSerializer(many=True, read_only=True)
class Meta:
model = ProjectRequest
fields = ('contact_requests', 'company_name', ...) # and so on
You could add a property function to the ProjectRequest class that retruns all the ContactRequests that are related to that ProjectRequest like so...
class ProjectRequest(models.Model):
project_name = models.CharField(max_length=50)
company_name = models.CharField(max_length=50)
#make array of technologiestechnologies = models.ArrayField(base_field=) (blank=True)
project_description = models.CharField(max_length=200)
project_type = models.CharField(max_length=30)
budget_estimation = models.IntegerField(
default=1000,
validators=[
MinValueValidator(1800),
MaxValueValidator(5000000)
])
#time_estimation = models.DateTimeField(default=None, blank=True, null=True)
#property
def contact_requests(self):
return ContactRequest.objects.filter(project_request=self)
class ContactRequest(models.Model):
topic = models.CharField(max_length=30)
description = models.CharField(max_length=200)
time = models.CharField(max_length=15)
project_request = models.ForeignKey(ProjectRequest,
on_delete=models.CASCADE)
I had this problem too. This is how I solved it:
ContactRequest= models.ManyToManyField(ContactRequest,related_name="+")
I'm working on an inventory tracking application. Barebones, just for learning. One issue I'm running into is how products can be related. Categories works fine, but a Logitech G35 Mouse could be nested under Peripherals, but Peripherals will be populated with mice, keyboards, headphones, Waacom pads, etc. To help find what we need faster I wanted to incorporate tags of some sort, but I've noticed there's something called Tags native to Django which keeps hijacking my search.
Here's my Item model:
class Item(models.Model):
name = models.CharField(max_length=100)
description = models.CharField(max_length=100)
manufacturer = models.ForeignKey('Manufacturer', blank=True, null=True, on_delete=models.SET_NULL)
part_number = models.CharField(max_length=50, blank=True, null=True)
introduction = models.DateField(auto_now=True)
category = models.ForeignKey('Category', default='Uncategorized', on_delete=models.SET_DEFAULT)
quanity = models.IntegerField(default=0)
is_retired = models.BooleanField(default=False)
def __str__(self):
return self.name
def add(self):
pass
def remove(self):
pass
def retire(self): # Rex came up with this, roll credits.
pass
def count(self):
pass
So if I were to add a Logitech G35 Mouse as an item, I'd like the tag(s) to be mouse, mice, wireless and so forth. Where might I find the information needed to implement this?
You can create a model Tag and a many to many relationship with model Item:
class Tag(models.Model)
name = models.CharField(max_length=20)
class Item(models.Model):
name = models.CharField(max_length=100)
description = models.CharField(max_length=100)
manufacturer = models.ForeignKey('Manufacturer', blank=True, null=True, on_delete=models.SET_NULL)
part_number = models.CharField(max_length=50, blank=True, null=True)
introduction = models.DateField(auto_now=True)
category = models.ForeignKey('Category', default='Uncategorized', on_delete=models.SET_DEFAULT)
quanity = models.IntegerField(default=0)
is_retired = models.BooleanField(default=False)
tags = models.ManyToManyField(Tag)
You probably want a Many-to-Many relationship. You need a table of products, a table of categories, and a table that shows the relationship between those tables. Here is the sample code from the Django docs. A publication can contain many articles, and an article can be in many publications. To translate this to your models, a product(mouse) can be a part of many categories(mice/mouse/wireless), and a category(wireless) can contain many items(mouse, keyboard, speakers)
from django.db import models
class Publication(models.Model):
title = models.CharField(max_length=30)
def __str__(self):
return self.title
class Meta:
ordering = ('title',)
class Article(models.Model):
headline = models.CharField(max_length=100)
publications = models.ManyToManyField(Publication)
def __str__(self):
return self.headline
class Meta:
ordering = ('headline',)
Link: https://docs.djangoproject.com/en/2.1/topics/db/examples/many_to_many/
I want to connect a single ForeignKey to two different models.
For example:
I have two models named Casts and Articles, and a third model, Faves, for favoriting either of the other models. How can I make the ForeignKey dynamic?
class Articles(models.Model):
title = models.CharField(max_length=100)
body = models.TextField()
class Casts(models.Model):
title = models.CharField(max_length=100)
body = models.TextField()
class Faves(models.Model):
post = models.ForeignKey(**---CASTS-OR-ARTICLES---**)
user = models.ForeignKey(User,unique=True)
Is this possible?
Here is how I do it:
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import fields
class Photo(models.Model):
picture = models.ImageField(null=True, upload_to='./images/')
caption = models.CharField(_("Optional caption"),max_length=100,null=True, blank=True)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = fields.GenericForeignKey('content_type', 'object_id')
class Article(models.Model):
....
images = fields.GenericRelation(Photo)
You would add something like
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = fields.GenericForeignKey('content_type', 'object_id')
to Faves
and
fields.GenericRelation(Faves)
to Article and Cast
contenttypes docs
Here's an approach. (Note that the models are singular, Django automatically pluralizes for you.)
class Article(models.Model):
title = models.CharField(max_length=100)
body = models.TextField()
class Cast(models.Model):
title = models.CharField(max_length=100)
body = models.TextField()
FAVE_CHOICES = (
('A','Article'),
('C','Cast'),
)
class Fave(models.Model):
type_of_fave = models.CharField( max_length=1, choices=FAVE_CHOICES )
cast = models.ForeignKey(Casts,null=True)
article= models.ForeigKey(Articles,null=True)
user = models.ForeignKey(User,unique=True)
This rarely presents profound problems. It may require some clever class methods, depending on your use cases.