What is a good model for Product attributes - django

I'm making a cart for a online store. I have a model Product like
#Product
from django.db import models
class Product(models.Model):
title = models.CharField()
attribute = models.ManyToManyField('Attribute')
How can I make attributes models like size, colors with their keys like numbers or choices ('Red', 'Green',...) ?

Have you read up on ManyToManyField?
https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ManyToManyField
You'd need to define an Attribute model class to point to, then add the relationships via the field managers 'add' method.
class Attribute(models.Model):
value = models.CharField(max_length=64)
class Product(models.Model):
title = models.CharField()
attribute = models.ManyToManyField('Attribute')
product = Product.objects.create(title='foobar')
red_attribute = Attribute.objects.create(value='Red')
product.attribute.add(red_attribute)

Related

Django admin: reverse select foreign keys

I want to add pre-existing foreignkey items from the parent's admin. I have a "Bundle" model to hold "Product" items; many-to-one/foreignkey:
models.py
class Bundle(models.Model):
title = models.CharField(max_length=300)
class Product(models.Model):
title = models.CharField(max_length=300)
bundle = models.ForeignKey(
'Bundle',
on_delete=models.CASCADE,
null=True,
blank=True,
)
Below, I used StackedInline but this is for creating new products with a form:
admin.py
class ProductInline(admin.StackedInline):
model = Product
#admin.register(Bundle)
class BundleAdmin(admin.ModelAdmin):
inlines = [
ProductInline,
]
Instead, I want to repeatedly add existing products from a dropdown/search in the Bundle section of admin. So, I make a Bundle and then add a series of Products from a dropdown / with a search.
Thanks in advance.
For you requirement, you can use ManyToManyField in Bundle model instead of ForeignKey in Product model.
Check below code.
class Bundle(models.Model):
title = models.CharField(max_length=255)
product = models.ManyToManyField('Product')
class Product(models.Model):
title = models.CharField(max_length=255)
Then you can register admin interfaces:
admin.site.register(Bundle)
admin.site.register(Product)
Then you can add series of Product from a dropdown/search.

DRY fields in Django models

I know about using inheritance and abstract models in reusing common fields in different models.
I'd like to know if the following approach is possible instead of inheritance and mixins.
from django.db import models
common_modified_by = models.CharField()
class Author(models.Model):
name = models.CharField()
modified_by = common_modified_by
class Book(models.Model):
title = models.CharField()
modified_by = common_modified_by
Will the above code work? Why or why not?
The issue with reusing the same field in multiple models is that the model attribute of the field will be set to the last model where the field is defined
from django.db import models
common_modified_by = models.CharField(max_length=20)
class Author(models.Model):
name = models.CharField(max_length=20)
modified_by = common_modified_by
class Book(models.Model):
title = models.CharField(max_length=20)
modified_by = common_modified_by
The field now has Book as it's model even when you get the field from the Author model. This can be problematic
>>> Book._meta.get_field('modified_by').model
<class 'foo.models.Book'>
>>> Author._meta.get_field('modified_by').model
<class 'foo.models.Book'>
One issue could be using the field as the target of a foreign key django.db.models.fields.related seems to use this model attribute quite a lot
It's also used when generating subqueries

Diango model property to return list of objects of other model

I have 2 models like this:
class Company(models.Model):
name = models.CharField(max_length=200)
address = models.CharField(max_length=200)
class Meta:
verbose_name = 'Company'
And another model:
class Product(models.Model):
name = models.CharField(max_length=200)
company = models.ForeignKey(to=Company, on_delete=models.PROTECT)
class Meta:
verbose_name = 'Product'
Now, I need to make a property in Company model which could return a list of all Product Objects, like
#property
def products (self):
products = []
for i in Product.objects().filter(company=self.id):
products.append(i)
return products
When I mention products (property) in CompanySerializer fields, it give me an error that it cannot return a list of objects.
Can anyone solve my problem and tell me what is wrong with the code?
I think if you want the list of results in your API, you should use model_to_dict function. Like,
#property
def products(self):
from django.forms.models import model_to_dict
res = []
for i in Product.objects.filter(company=self.id):
res.append(model_to_dict(i))
return res
And, then you can include this 'products' property in your Company serializer class fields. Hope, this helps!
Django adds properties to your models dynamically that return a queryset with all related objects. By default the property is named <model name lowercase>_set
company.product_set.all()
The name of this property can be changed by passing related_name to the ForeignKey
class Product(models.Model):
company = models.ForeignKey(to=Company, on_delete=models.PROTECT, related_name='products')
company.products.all()

How to get all objects linked to a given foreign ket field using rest_framework serializers?

I have two models and I want to call the field values associated with the foreign key present in both the models.
For example:
Say we have two models:
from django.db import models
from django.contrib.auth.models import User
class Bike(models.Model):
bike_model = models.CharField(max_length=200)
owner = models.ForeignKey(User,on_delete=models.CASCADE)
class Car(models.Model):
car_model = models.CharField(max_length=200)
owner = models.ForeignKey(User,on_delete=models.CASCADE)
And the relating serializer class is:
from rest_framework import serializers
from .models import Bike,Car
class BikeSerializer(serializers.ModelSerializer):
class Meta:
model = Bike
fields = ('bike_model','owner')
class CarSerializer(serializers.ModelSerializer):
class Meta:
model = Car
fields = ('car_model','owner')
Now, I want to add a field in BikeSerializer to get all the cars associated with the given owner. That is I want to make the following change:
class BikeSerializer(serializers.ModelSerializer):
cars_owned = ???
class Meta:
model = Bike
fields = ('bike_model','owner','cars_owned')
I am unable to get how the cars owned by the owner can be returned. Thus, for the data from serializer, I want the bike model, the owner id and the list of all the car ids that the owner has.
You should look this SerializerMethodField.
Basically, you need to create a method inside BikeSerializer that return cars owned.
class BikeSerializer(serializers.ModelSerializer):
cars_owned = serializers.SerializerMethodField()
class Meta:
model = Bike
fields = ('bike_model','owner','cars_owned')
def get_cars_owned(self, object):
# This is your query to get all cars associated
return object.cars_owned.all()
You may add seializer as field:
class BikeSerializer(serializers.ModelSerializer):
cars_owned = CarSerializer(source='owner.car_set', many=True, read_only=True)
class Meta:
model = Bike
fields = ('bike_model','owner','cars_owned')

How to create custom relation table for ForeignKey or OnetoOne field?

What I want to do is create a model than can be used to store data about a relation between two elements. With ManytoMany fields, I can use the parameter "through" and specify a model which stores two elements foreign keys as below.
def MyModel(models.Model):
relation = models.ManyToManyField('AnotherModel', through='RelationModel')
def RelationModel(models.Model):
model1 = models.ForeignKey('MyModel')
model2 = models.ForeignKey('AnotherModel')
slug = models.CharField()
What would be the equivalent for a OnetoOne relation or a ForeignKey relation ? I've read the docs about custom managers and some posts on SO so in the end I'm quite confused and I dont know what is the solution. Thanks in advance for any help.
you can do like this
from products.models import VendorDetails
class UserProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, related_name='profile', on_delete=models.CASCADE)
user_location = models.CharField(max_length=50, null=True)
vendor_category = models.ManyToManyField(VendorDetails, through="UserProfileVendorCategory")
class UserProfileVendorCategory(models.Model):
user_profile = models.ForeignKey(UserProfile)
vendor_category = models.ForeignKey(VendorDetails)
location = models.CharField(max_length=256)