英文:
Return a list of options only if they exist in two Django Models
问题
我在models.py文件中有两个模型:
口味模型(Flavour model):
class Flavour(models.Model):
flavour_choice = models.CharField(null=True, blank=True, max_length=254)
def __str__(self):
return self.flavour_choice
和产品模型(Product model):
class Product(models.Model):
category = models.ForeignKey(
'Category', null=True, blank=True, on_delete=models.SET_NULL
)
slug = models.SlugField()
sku = models.CharField(max_length=254, null=True, blank=True)
name = models.CharField(max_length=254)
brand = models.TextField()
has_flavours = models.BooleanField(default=False, null=True, blank=True)
flavours = models.ForeignKey(
'Flavour', null=True, blank=True, on_delete=models.SET_NULL
)
has_strength = models.BooleanField(default=False, null=True, blank=True)
strength = models.ForeignKey(
'Strength', null=True, blank=True, on_delete=models.SET_NULL
)
description = models.TextField()
price = models.DecimalField(max_digits=6, decimal_places=2)
rating = models.DecimalField(max_digits=6, decimal_places=2, null=True, blank=True)
image_url = models.URLField(max_length=1024, null=True, blank=True)
image = models.ImageField(null=True, blank=True)
display_home = models.BooleanField(blank=True)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('-created_at',)
def __str__(self):
return self.name
我想要能够将口味添加到口味表,并选择它们是否出现在特定的产品中。我应该如何做到这一点?我知道我可以将口味直接添加到产品中,但我希望许多产品具有相同的口味。
我需要能够在数据库层面完成这个操作,而不仅仅是在程序中进行操作,这样管理员用户可以通过前端产品管理页面添加口味和产品。
英文:
I have two models in my models.py file:
Flavour model:
class Flavour(models.Model):
flavour_choice = models.CharField(null=True, blank=True, max_length=254)
def __str__(self):
return self.flavour_choice
and Product model:
class Product(models.Model):
category = models.ForeignKey(
'Category', null=True, blank=True, on_delete=models.SET_NULL
)
slug = models.SlugField()
sku = models.CharField(max_length=254, null=True, blank=True)
name = models.CharField(max_length=254)
brand = models.TextField()
has_flavours = models.BooleanField(default=False, null=True, blank=True)
flavours = models.ForeignKey(
'Flavour', null=True, blank=True, on_delete=models.SET_NULL
)
has_strength = models.BooleanField(default=False, null=True, blank=True)
strength = models.ForeignKey(
'Strength', null=True, blank=True, on_delete=models.SET_NULL
)
description = models.TextField()
price = models.DecimalField(max_digits=6, decimal_places=2)
rating = models.DecimalField(max_digits=6, decimal_places=2, null=True, blank=True)
image_url = models.URLField(max_length=1024, null=True, blank=True)
image = models.ImageField(null=True, blank=True)
display_home = models.BooleanField(blank=True)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('-created_at',)
def __str__(self):
return self.name
I want to able to add flavours to the flavours table and then choose if they appear for particular products. How would I go about this? I know I could just add the flavours to the product but so many of the products I want to have, have the same flavours.
I need to be able to do this database side and not just programmatically so admin users can add flavours and products via a front-end product management page.
答案1
得分: 0
你可以使用ManyToMany关系,其中许多口味可以用于许多不同的产品。
更多解释请参考这里:https://docs.djangoproject.com/en/4.1/topics/db/examples/many_to_many/
英文:
You can use a ManyToMany relationship, where many flavours can be used for many different products.
More explanation here : https://docs.djangoproject.com/en/4.1/topics/db/examples/many_to_many/
答案2
得分: 0
关于您的模型和字段,您可以在Flavour
模型中使用model choices,但这不一定是必需的。您可以去掉has_flavours
和has_strength
字段,使用model property以及flavours
和strengths
关系来获取所需的输出。
此外,如其他回答中提到的,将Flavour
和Product
之间的关系替换为多对多关系,以避免数据库中的重复记录。最后,image_url
也是不必要的,因为您正在使用models.ImageField
,可以通过属性例如instance.image.url
来访问图像URL。
models.py
class Product(models.Model):
category = models.ForeignKey(
'Category', null=True, blank=True, on_delete=models.SET_NULL
)
slug = models.SlugField()
sku = models.CharField(max_length=254, null=True, blank=True)
name = models.CharField(max_length=254)
brand = models.TextField()
flavours = models.ManyToManyField('Flavour')
strength = models.ForeignKey(
'Strength', null true, blank=true, on delete=models.SET NULL
)
description = models.TextField()
price = models.DecimalField(max_digits=6, decimal_places=2)
rating = models.DecimalField(max_digits=6, decimal_places=2, null=true, blank=true)
image = models.ImageField(null=true, blank=true)
display_home = models.BooleanField(blank=true)
created_at = models.DateTimeField(auto_now_add=true)
class Meta:
ordering = ('-created_at',)
def __str__(self):
return self.name
@property
def has_flavours(self):
return True if self.flavours.count() > 0 else False
@property
def has_strength(self):
return True if self.strength.count() > 0 else False
一个简单的示例,演示如何将风味与特定产品关联起来:
tests.py
class ProductTestCase(TestCase):
def setUp(self):
self.flv1 = Flavour.objects.create(flavour_choice='Flavour One')
self.flv2 = Flavour.objects.create(flavour_choice='Flavour Three')
self.product = Product.objects.create(
slug='product-one', name='Product One',
brand='Brand', description='Product Description',
price=decimal.Decimal(100), display_home=True
)
self.another_product = Product.objects create(
slug='another-product', name='Another Product',
brand='Brand', description='Another Product Description',
price=decimal.Decimal(100), display_home=True
)
def test_product_with_specific_flavour(self):
self.product.flavours.add(self.flv1)
self.product.flavours.add(self.flv2)
self.another_product.flavours.add(self.flv2)
queryset = Product.objects.filter(flavours=self.flv2)
# queryset contains both products
self.assertEqual(queryset.count(), 2)
queryset = Product.objects.filter(flavours=self.flv1)
# queryset contains only 'Product One'
self.assertEqual(queryset.count(), 1)
self.assertEqual(queryset[0], self.product)
def test_product_flavour_property(self):
# Associate flavour with poduct one
self.product.flavours.add(self.flv1)
# Product One has flavour and another_product does not.
self.assertEqual(self.product.has_flavours, True)
self.assertNotEqual(self.another_product.has_flavours, True)
我还建议考虑创建一个brand = models.TextField()
模型,具有一对多关系。
英文:
First about your models and fields. You can use model choices at Flavour
model, but it is not necessarily required. You can get rid of has_flavours
and has_strength
fields, use a model property and flavours
and strengths
relations to obtain the desired output.
Also, as mentioned on the other answer, substitute the relation between Flavour
and Product
with a many-to-many relation in order to avoid duplicates in your database. Lastly, image_url
is also not necessary, since you are using models.ImageField
it is possible to access the image url via attribute e.g. instance.image.url
.
models.py
class Product(models.Model):
category = models.ForeignKey(
'Category', null=True, blank=True, on_delete=models.SET_NULL
)
slug = models.SlugField()
sku = models.CharField(max_length=254, null=True, blank=True)
name = models.CharField(max_length=254)
brand = models.TextField()
flavours = models.ManyToManyField('Flavour')
strength = models.ForeignKey(
'Strength', null=True, blank=True, on_delete=models.SET_NULL
)
description = models.TextField()
price = models.DecimalField(max_digits=6, decimal_places=2)
rating = models.DecimalField(max_digits=6, decimal_places=2, null=True, blank=True)
image = models.ImageField(null=True, blank=True)
display_home = models.BooleanField(blank=True)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('-created_at',)
def __str__(self):
return self.name
@property
def has_flavours(self):
return True if self.flavours.count() > 0 else False
@property
def has_strength(self):
return True if self.strength.count() > 0 else False
A simple example, on how you would associate a flavour with a specific product:
tests.py
class ProductTestCase(TestCase):
def setUp(self):
self.flv1 = Flavour.objects.create(flavour_choice='Flavour One')
self.flv2 = Flavour.objects.create(flavour_choice='Flavour Three')
self.product = Product.objects.create(
slug='product-one', name='Product One',
brand='Brand', description='Product Description',
price=decimal.Decimal(100), display_home=True
)
self.another_product = Product.objects.create(
slug='another-product', name='Another Product',
brand='Brand', description='Another Product Description',
price=decimal.Decimal(100), display_home=True
)
def test_product_with_specific_flavour(self):
self.product.flavours.add(self.flv1)
self.product.flavours.add(self.flv2)
self.another_product.flavours.add(self.flv2)
queryset = Product.objects.filter(flavours=self.flv2)
# queryset contains both products
self.assertEqual(queryset.count(), 2)
queryset = Product.objects.filter(flavours=self.flv1)
# queryset contains only 'Product One'
self.assertEqual(queryset.count(), 1)
self.assertEqual(queryset[0], self.product)
def test_product_flavour_property(self):
# Associate flavour with poduct one
self.product.flavours.add(self.flv1)
# Product One has flavour and another_product does not.
self.assertEqual(self.product.has_flavours, True)
self.assertNotEqual(self.another_product.has_flavours, True)
I would also consider the possibility of creating a model for brand = models.TextField()
with a one-to-many
relation.
答案3
得分: 0
I went a different route in the end as I was overcomplicating the issue.
I added a Variation model:
class Variation(models.Model):
product = models.ForeignKey('Product', null=True, blank=True, on_delete=models.SET_NULL)
flavour = models.CharField(max_length=254, null, blank=True)
strength = models.CharField(max_length=254, null, blank=True)
And now I can just use an if statement to call the flavours into the template in a for loop that iterates over all the flavours associated with the product in the product variation model.
{% if product.has_flavours %}
<div class="col-12">
<p><strong>Flavour:</strong></p>
<select class="form-control rounded-0 w-50" name="product_flavour" id="id_product_flavour">
{% for variation in variations %}
<option value="{{ variation.flavour }}">{{ variation.flavour }}</option>
{% endfor %}
</select>
</div>
{% endif %}
英文:
I went a different route in the end as I was overcomplicating the issue.
I added a Variation model:
class Variation(models.Model): product = models.ForeignKey( 'Product', null=True, blank=True, on_delete=models.SET_NULL ) flavour = models.CharField(max_length=254, null=True, blank=True) strength = models.CharField(max_length=254, null=True, blank=True)
And now I can just use an if statement to call the flavours into the template in a for loop that iterates over all the flavours associated with the product in the product variation model.
{% if product.has_flavours %}
<div class="col-12">
<p><strong>Flavour:</strong></p>
<select class="form-control rounded-0 w-50" name="product_flavour" id='id_product_flavour'>
{% for variation in variations %}
<option value="{{ variation.flavour }}">{{ variation.flavour }}</option>
{% endfor %}
</select>
</div>
{% endif %}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论