ForeignKey to abstract model - python

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

How to merge two models into one model with django for admin?

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)

How to implement different model fields for different categories?

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()

Adding one to many relationship in Django models

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="+")

Tags for relationship in Django

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/

How to use dynamic foreignkey in Django?

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.

Categories