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
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.
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 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")