Creating SubCategories with Django Models - python

I am trying to expand the relationships within my Django Models. I have a system where elements are stored within Categories. How do I structure my models.py so that each category is related to a subcategory?
Here is what my category model looks like:
class Category(models.Model):
site = models.ForeignKey(Site)
template_prefix = models.CharField(max_length=200, blank=True)
name = models.CharField(max_length=200)
slug = models.SlugField()
description = models.TextField(default='')
sortby_fields = models.CharField(max_length=200,
help_text=_(u'A comma separated list of field names that should show up as sorting options.'),
blank=True)
sort_order = models.PositiveIntegerField(default=0)
def __unicode__(self):
return self.name + u' Category'
class Meta:
verbose_name_plural = u'categories'
Thanks for any suggestions.

You can create a foreign key to itself:
class Category(models.Model):
...
parent_category = models.ForeignKey('self', null=True, blank=True)
Then you can assigning any existing Category instance as the parent_category of that instance. Then, if you wanted to find all of the subcategories of a given Category instance you would do something like:
subcategories = Category.objects.filter(
parent_category__id=target_category.id)

You can also try django-mptt. It has some additional features.

Related

How to get specific objects based on ManyToMany field match

I'm doing a cookbook app, which help users find meal thay can do with their ingridients. I'm using Django RestFramework, and i need to return list of avaliable meals that user can do, but don't know how to do search by ingridients
My models.py:
#models.py
class Meal(models.Model):
name = models.CharField(max_length=250)
description = models.TextField(blank=True, null=True)
recipe = models.TextField()
is_published = models.BooleanField(default=False)
category = ForeignKey('Category', on_delete=models.CASCADE, null=True)
user = ForeignKey(User, verbose_name='User', on_delete= models.CASCADE)
difficulty = ForeignKey('Difficulty', on_delete=models.PROTECT, null=True)
ingridients = models.ManyToManyField('Ingridient')
class Ingridient(models.Model):
name = models.CharField(max_length=100, db_index=True)
ico = models.ImageField(upload_to="photos/%Y/%m/%d/", blank=True, null=True)
category = ForeignKey('CategoryIngridients', on_delete=models.CASCADE, null=True)
def __str__(self):
return self.name
class CookBookUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
ingridients = models.ManyToManyField('Ingridient')
serializer.py
class MealSerializer(serializers.ModelSerializer):
class Meta:
model = Meal
fields = "__all__"
views.py
class CraftWithUsersIngridientsListAPIView(generics.ListAPIView):
serializer_class = MealSerializer
def get_queryset(self):
return Meal.objects.filter(ingridients=CookBookUser.objects.filter(user_id = self.request.user.id).ingridients)
CraftWithUsersIngridientsListAPIView isn't working and I get AttributeError 'QuerySet' object has no attribute 'ingridients', can someone help fix this?
I tried building different serializer but it doesn't help
class CraftWithUsersIngridientsListAPIView(generics.ListAPIView):
serializer_class = MealSerializer
def get_queryset(self):
user_ingredients = CookBookUser.objects.get(user=self.request.user).ingredients.all()
return Meal.objects.filter(ingredients__in=user_ingredients)
This way, you first get the CookBookUser instance for the current user, then get all of their ingredients, and finally, filter the Meal objects that contain those ingredients. The __in query lookup is used to check if the meal ingredients are in the user's ingredients.

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/

Trouble accessing ForeignKey elements

I currently have two models set up in my Django app that have a ForeignKey relationship.
class Post(models.Model):
title = models.CharField(max_length=100)
body = RichTextField(config_name='awesome_ckeditor')
pub_date = models.DateTimeField('date', null=True)
description = models.CharField(max_length=100, blank=True, null=True)
photo = models.ImageField(upload_to='media/', blank=True, null=True)
def __unicode__(self):
return self.title
class Comment(models.Model):
post = models.ForeignKey(Post, related_name="comments", blank=True, null=True)
name = models.CharField(max_length=100, null=True)
comment = models.TextField(blank=True)
pub_date = models.DateField("date", blank=True, null=True)
def __unicode__(self):
return unicode(self.name)
What I am not getting is making queries between the two. I have tried making queries through the shell but to no success. If I set Post(title="Cat") and then make c = Comment(name="Dog"), I can query each models respective title or name through something like p = Post.object.get(pk=1) and p.title will output Cat. But if I do p.comment or p.comment_id, there is an error. Likewise with any Comment objects. However when I do print c.post, I get None. What am I missing in order to make p.<field_here>" =Dog`?
Since you have related name "comments", access to set foreign model from Post should be called this way:
p.comments
But since you can have many comments for a same Post, this won't return a unique value, but a related manager that you need to query. So you could get:
p.comments.filter(name="Dog")

Categories