How to Nested Categories in django admin - django

I want to create muti category in my ecommerce website where sub category will be dependent on main category.
Please help me with this
class MainCategory(models.Model):
# name = models.CharField(max_length=50)
# date_created = models.DateTimeField(auto_now_add=True)
# def __str__(self):
# return self.name
# class SubCategory(models.Model):
# perentcategory = models.OneToOneField(MainCategory, on_delete=models.CASCADE, primary_key=True)
# name = models.CharField(max_length=50)
# date_created = models.DateTimeField(auto_now_add=True)
# def __str__(self):
# return self.name
# class Items(models.Model):
# main = models.ForeignKey(SubCategory, on_delete=models.CASCADE)
# name = models.CharField(max_length=255)
Posting this question 4th time

Change models.OneToOneField to models.ForeignKey so you can have multiple subcategories assigned to a main category:
class MainCategory(models.Model):
name = models.CharField(max_length=50)
date_created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class SubCategory(models.Model):
main_category = models.ForeignKey(MainCategory, on_delete=models.CASCADE, primary_key=True)
name = models.CharField(max_length=50)
date_created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class Items(models.Model):
main = models.ForeignKey(SubCategory, on_delete=models.CASCADE)
name = models.CharField(max_length=255)

You can use single model to accommodate both Category and Sub-categories. Something like this.
class Category(models.Model):
name = models.CharField(blank=False, max_length=200)
slug = models.SlugField(null=False)
parent = models.ForeignKey('self',blank=True, null=True ,related_name='children', on_delete=models.SET_NULL)
Then add following function to the above model
def get_categories(self):
if self.parent is None:
return self.name
else:
return self.parent.get_categories() + ' -> ' + self.name
def __str__(self):
return self.get_categories()
This will return structure similar to this image

Related

Django - How to group forms.CheckboxSelectMultiple items by unique parent field value?

My category models:
class Category(models.Model):
name = models.CharField(max_length=50, unique=True)
description = models.CharField(max_length=255, default='')
def __str__(self):
return "%s" % (self.name)
class SubCategory(models.Model):
name = models.CharField(max_length=50, unique=True)
description = models.CharField(max_length=255, default='')
category = models.ForeignKey(Category, on_delete=models.CASCADE)
def __str__(self):
return self.name
class Meta:
ordering = ['name']
Here's my Job class:
class Job(models.Model):
...
skill_set = models.ManyToManyField(SubCategory)
my forms.py:
class CustomSelectMultiple(ModelMultipleChoiceField):
def label_from_instance(self, obj):
return "%s - %s" %(obj.category, obj.name)
# return "%s" %(obj.name)
class NewJobForm(forms.ModelForm):
skill_set = CustomSelectMultiple(widget=forms.CheckboxSelectMultiple, queryset=SubCategory.objects.all())
class Meta:
model = Job
fields = ['skill_set']
In my template file I have a standard:
{{ form|crispy }}
In my context:
form = NewJobForm()
So as expected in my form I see:
But I would like my checkboxes to be display as such:
How can I achieve that?

NameError: name 'ProductTag' is not defined

models.py
from django.db import models
from django.contrib.auth.models import User
class ActiveManager(models.Model):
def active(self):
return self.filter(active=True)
class Product(models.Model):
name = models.CharField(max_length=32)
description = models.TextField(blank=True)
price = models.DecimalField(max_digits = 5, decimal_places = 2)
slug = models.SlugField(max_length=48)
active = models.BooleanField(default=True)
in_stock = models.BooleanField(default=True)
date_updated = models.DateTimeField(auto_now=True)
objects = ActiveManager()
tags = models.ManyToManyField(ProductTag, blank=True)
def __str__(self):
return self.name
class ProductImage(models.Model):
product = models.ForeignKey(
Product, on_delete=models.CASCADE)
image = models.ImageField(upload_to="product-images")
thumbnail = models.ImageField(
upload_to="product-thumbnails", null=True)
class ProductTag(models.Model):
name = models.CharField(max_length=40)
slug = models.SlugField(max_length=48)
description = models.TextField(blank=True)
active = models.BooleanField(default=True)
def __str__(self):
return self.name
def natural_key(self):
return(self.slug,)
The name error says ProductTag is not defined, whereas ProductTag itself a Class. I don't understand where I missed... appreciate for the help
The solution must be like this, because I think reordering could solve your problem. However please put 2 lines of space between your classes and 1 line of space between your functions. It can make your code more readable and also more suitale for the Python guidelines.
from django.db import models
from django.contrib.auth.models import User
class ActiveManager(models.Model):
def active(self):
return self.filter(active=True)
class ProductTag(models.Model):
name = models.CharField(max_length=40)
slug = models.SlugField(max_length=48)
description = models.TextField(blank=True)
active = models.BooleanField(default=True)
def __str__(self):
return self.name
def natural_key(self):
return(self.slug,)
class Product(models.Model):
name = models.CharField(max_length=32)
description = models.TextField(blank=True)
price = models.DecimalField(max_digits = 5, decimal_places = 2)
slug = models.SlugField(max_length=48)
active = models.BooleanField(default=True)
in_stock = models.BooleanField(default=True)
date_updated = models.DateTimeField(auto_now=True)
objects = ActiveManager()
tags = models.ManyToManyField(ProductTag, blank=True)
def __str__(self):
return self.name
class ProductImage(models.Model):
product = models.ForeignKey(
Product, on_delete=models.CASCADE)
image = models.ImageField(upload_to="product-images")
thumbnail = models.ImageField(
upload_to="product-thumbnails", null=True)
Looking at your code, you’re trying to use ProductTag before you’ve defined it.
You could either reorder things, or I believe you can reference by string and django will link them up later.
Eg tags = models.ManyToManyField('ProductTag', blank=True)

Django Rlationships levels

I have 3 models : User, Attribute, Site.
class User(models.Model):
userid = models.CharField(max_length=200, primary_key=True)
name= models.BooleanField(null=True)
def get_absolute_url(self):
return reverse('myapp:index')
def __str__(self):
return self.userid
class Site(models.Model):
pK_site = models.CharField(max_length=200, primary_key=True)
name = models.CharField(max_length=200,null=True)
def __str__(self):
return self.pK_site
class Attribute(models.Model):
userid = models.ForeignKey(User, on_delete=models.CASCADE)
role= models.CharField(max_length=200)
site = models.ForeignKey(Site, on_delete=models.CASCADE)
def __str__(self):
return str(self.site)
def get_absolute_url(self):
return reverse('myapp:edit', kwargs={'pk' : self.userid.pk})
My problem is when i get for example the list of all the attribues (Class : Attribute) in a view, i can't get the Site of this attribute or its user in the template.
Someone has a suggestion to do that ? thank you

Django Cart - multiple configuration options for a product

I want to create a Django web-application where users can add items to a cart.
Without the models Colour and Size this works so far.
My Problem is, that i can not figure out how to implement the configuration-options (for example) Colour and Size the right way.
I added both "Options" with a Many-to-One relationship. I now can add multiple colours and sizes for a Product, but do not know how to save the choosen "Option" in an CartEntry
This is what i got so far:
from django.db import models
from django.contrib.auth.models import User
class Product(models.Model):
name = models.CharField(max_length=256)
price = models.DecimalField(max_digits=6, decimal_places=2)
def __str__(self):
return str(self.name)
class Colour(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name="rel_colour")
option = models.CharField(max_length=24)
price = models.DecimalField(max_digits=6, decimal_places=2)
def __str__(self):
return str(self.colour)
class Size(models.Model):
product =models.ForeignKey(Product, on_delete=models.CASCADE, related_name="rel_size")
option = models.CharField(max_length=24)
price = models.DecimalField(max_digits=6, decimal_places=2)
def __str__(self):
return str(self.size)
class Cart(models.Model):
user = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE)
products = models.ManyToManyField(Product, blank=True)
updated = models.DateTimeField(auto_now=True)
timestamp = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.id) + ' - ' + str(self.user)
class CartEntry(models.Model):
product = models.ForeignKey(Product, null=True, on_delete=models.CASCADE)
cart = models.ForeignKey(Cart, null=True, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField()
def __str__(self):
return str(self.quantity) + ', ' + str(self.product.name)
Maybe i can not user relations for CartEntry here?
why not do like this:
from django.db import models
from django.contrib.auth.models import User
class Product(models.Model):
name = models.CharField(max_length=256)
colour = models.ForeignKey(Colour, on_delete=models.CASCADE)
size = models.ForeignKey(Size, on_delete=models.CASCADE)
price = models.DecimalField(max_digits=6, decimal_places=2)
def __str__(self):
return str(self.name)
class Colour(models.Model):
name = models.CharField(max_length=24)
def __str__(self):
return str(self.name)
class Size(models.Model):
name = models.CharField(max_length=24)
def __str__(self):
return str(self.name)
so every product has different colour and size. or if you want make a Product as a "parent" you can add 1 more model like let say VariantProduct
class Product(models.Model):
name = models.CharField(max_length=256)
def __str__(self):
return str(self.name)
class VariantProduct(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
name = models.CharField(max_length=256)
colour = models.ForeignKey(Colour, on_delete=models.CASCADE)
size = models.ForeignKey(Size, on_delete=models.CASCADE)
price = models.DecimalField(max_digits=6, decimal_places=2)
def __str__(self):
return str(self.name)

Django ManyToManyField Foreign Key Design

As part of an Address Book application, I have the following in my models.py
from django.db import models
class Contact(models.Model):
contact_id= models.AutoField(auto_created=True, primary_key=True, default=1, verbose_name='ID')
name = models.CharField(max_length=100, unique=True)
contact_no = models.ManyToManyField(ContactNumberTypeField,
through='ContactContactNumber', through_fields=('contact_name','contact_type'))
def __str__(self):
return self.name
class ContactNumberTypeField(models.Model):
contact_number_type=models.AutoField(auto_created=True, primary_key=True, default=1, verbose_name='ID')
name = models.CharField(max_length=20)
contact_no = models.ManyToManyField(Contact,
through='ContactContactNumber', through_fields=('contact_name','contact_type'))
def __str__(self):
return self.name
class ContactContactNumber(models.Model):
contact_name=models.ForeignKey(Contact)
contact_type=models.ForeignKey(ContactNumberTypeField)
contact_number = models.CharField(max_length=50)
def __str__(self):
return contact_number
My question is that why is it when I run makemigrations, it throws a ContactNumberTypeField is not defined error?
Update
Correct code is as follows
from django.db import models
class Contact(models.Model):
contact_id= models.ManyToManyField('ContactNumberTypeField',
through='ContactContactNumber', through_fields=('contact_name','contact_type'))
name = models.CharField(max_length=100, unique=True)
def __str__(self):
return self.name
class ContactNumberTypeField(models.Model):
contact_number_type=models.ManyToManyField('Contact',
through='ContactContactNumber', through_fields=('contact_type','contact_name'))
name = models.CharField(max_length=20)
contact_no = models.IntegerField(max_length=20)
def __str__(self):
return self.name
class ContactContactNumber(models.Model):
contact_name=models.ForeignKey(Contact)
contact_type=models.ForeignKey(ContactNumberTypeField)
contact_number = models.CharField(max_length=50)
def __str__(self):
return contact_number
ContactNumberTypeField is not defined at the time of defining of Contact class. Change contact_no field to this:
class Contact(models.Model):
...
contact_no = models.ManyToManyField('ContactNumberTypeField',
through='ContactContactNumber',
through_fields=('contact_name','contact_type'))
Note the quotes around 'ContactNumberTypeField'.
The other error here is the wrong order of field names in through_fields attribute of the ContactNumberTypeField.contact_no field. It should be:
class ContactNumberTypeField(models.Model):
...
contact_no = models.ManyToManyField(Contact,
through='ContactContactNumber',
through_fields=('contact_type','contact_name'))
Read the documentation about field1 and field2.