2023-11-09 18:47:11 +01:00

634 lines
22 KiB
Python

from django.db import models
from django.utils import timezone
from django.conf import settings
from django.db.models.signals import m2m_changed
from django.dispatch import receiver
from django.db.utils import IntegrityError
from .hierarchicalData import AncestorLevelsOf, SiblingLevelsOf
from treebeard.mp_tree import MP_Node
import os
# Create your models here.
class CharNullField(models.CharField):
"""
Subclass of the CharField that allows empty strings to be stored as NULL.
This class is used to set charfield be optional but unique when added.
Set blank=True, null=True when declaring the field
"""
description = "CharField that stores NULL but returns ''."
def get_prep_value(self, value):
"""
Catches value right before sending to db.
"""
if value == '': # If Django tries to save an empty string, send the db None (NULL).
return None
else: # Otherwise, just pass the value.
return value
def from_db_value(self, value, expression, connection):
"""
Gets value right out of the db and changes it if its ``None``.
"""
if value is None:
return ''
else:
return value
def to_python(self, value):
"""
Gets value right out of the db or an instance, and changes it if its ``None``.
"""
if isinstance(value, models.CharField): # If an instance, just return the instance.
return value
if value is None: # If db has NULL, convert it to ''.
return ''
return value # Otherwise, just return the value.
class ImageNullField(models.ImageField):
"""
Subclass of the CharField that allows empty strings to be stored as NULL.
This class is used to set charfield be optional but unique when added.
Set blank=True, null=True when declaring the field
"""
description = "ImageField that stores NULL but returns ''."
def get_prep_value(self, value):
"""
Catches value right before sending to db.
"""
if value == '': # If Django tries to save an empty string, send the db None (NULL).
return None
else: # Otherwise, just pass the value.
return value
def from_db_value(self, value, expression, connection):
"""
Gets value right out of the db and changes it if its ``None``.
"""
if value is None:
return ''
else:
return value
def to_python(self, value):
"""
Gets value right out of the db or an instance, and changes it if its ``None``.
"""
if isinstance(value, models.ImageField): # If an instance, just return the instance.
return value
if value is None: # If db has NULL, convert it to ''.
return ''
return value # Otherwise, just return the value.
class ReceipeImage(models.Model):
#RowId = models.IntegerField(primary_key=True)
checksum = models.CharField(
"checksum",
max_length=32,
editable=False,
unique=True,
help_text="The checksum of the original image."
)
thrashed_checksum = models.CharField(
"threshed checksum",
max_length=32,
editable=False,
unique=True,
help_text="The checksum of the thrashed image."
)
filename = models.FilePathField(
"filename",
max_length=1024,
editable=False,
default=None,
unique=True,
null=True,
help_text="Current filename in storage"
)
filename_trashed = models.FilePathField(
"filename trashed",
max_length=1024,
editable=False,
default=None,
unique=True,
null=True,
help_text="Current filename of the modified picture in storage"
)
created = models.DateTimeField(
"created",
default=timezone.now, db_index=True)
modified = models.DateTimeField(
"modified",
auto_now=True, editable=False, db_index=True)
added = models.DateTimeField(
"added",
default=timezone.now, editable=False, db_index=True)
@property
def source_path(self):
fname = str(self.filename)
return os.path.join(
settings.ORIGINALS_DIR,
fname
)
@property
def source_path_trashed(self):
fname = str(self.filename_trashed)
return os.path.join(
settings.ORIGINALS_DIR,
fname
)
@property
def source_file(self):
return open(self.source_path, "rb")
@property
def source_file_trashed(self):
return open(self.source_path_trashed, "rb")
class Allergenes(models.Model):
#RowId = models.IntegerField(primary_key=True)
name = models.CharField("allergene name", max_length=50, unique=True)
def __str__(self):
return 'PK: '+str(self.pk) + ' ' + self.name
class Brand(models.Model):
#RowId = models.IntegerField(primary_key=True)
name = models.CharField("brand name", max_length=50, unique=True)
def __str__(self):
return 'PK: '+str(self.pk) + ' ' + self.name
class Packaging(models.Model):
#RowId = models.IntegerField(primary_key=True)
name = models.CharField("packaging name", max_length=50, unique=True)
def __str__(self):
return 'PK: '+str(self.pk) + ' ' + self.name
class Ingredients(models.Model):
#RowId = models.IntegerField(primary_key=True)
name = models.CharField("ingredient name", max_length=100)
allergenes = models.ManyToManyField(Allergenes, blank=True)
vegan = models.BooleanField("vegan?",default=False)
vegetarian = models.BooleanField("vegetarian?",default=False)
palmoilfree = models.BooleanField("Palm oil free?",default=True)
additive = models.BooleanField("Additiv?",default=False)
eNumber = CharNullField("E number", max_length=7,null=True, blank=True)
subIngredients = models.ManyToManyField('self', blank=True, symmetrical=False)
#class Meta:
# unique_together = ('name', 'subIngredients',)
def __unicode__(self):
return "Ingredients: "+str(self.id)+" "+self.name
def __str__(self):
return 'PK: '+str(self.pk) + ' ' + self.name
@receiver(m2m_changed, sender=Ingredients.subIngredients.through)
def verify_uniqueness(sender, **kwargs):
ingredient = kwargs.get('instance', None)
action = kwargs.get('action', None)
subIngredients = kwargs.get('pk_set', None)
if action == 'pre_add':
for subIngredient in subIngredients:
if Ingredients.objects.filter(name=ingredient.name).filter(subIngredients=subIngredient):
raise IntegrityError('Ingredient with name %s already exists for subIngredient %s' % (ingredient.name, Ingredients.objects.get(pk=subIngredient)))
class Traces(models.Model):
#RowId = models.IntegerField(primary_key=True)
name = models.CharField("trace name", max_length=50, unique=True)
class Labels(models.Model):
#RowId = models.IntegerField(primary_key=True)
name = models.CharField("label name", max_length=50, unique=True)
class EMBs(models.Model):
#RowId = models.IntegerField(primary_key=True)
name = models.CharField("emb name", max_length=50, unique=True)
class ManufacturingPlaces(models.Model):
#RowId = models.IntegerField(primary_key=True)
name = models.CharField("manufacturing places name", max_length=50, unique=True)
class OriginIngredients(models.Model):
#RowId = models.IntegerField(primary_key=True)
name = models.CharField("origin of igredients", max_length=50, unique=True)
class Category(MP_Node):
name = models.CharField("category name",max_length=30,unique=True)
node_order_by = ['name']
def __str__(self):
return 'Category: {}'.format(self.name)
class Nutrient(models.Model):
name = models.CharField("nutrient name", max_length=50, unique=True)
isMacroNutrient = models.BooleanField("Is macronutrient?", default=False)
def __str__(self):
return 'PK: '+str(self.pk) + ' ' + self.name
class NutrientAlias(models.Model):
nutrient = models.ForeignKey(
Nutrient,
on_delete=models.CASCADE,
verbose_name="Nutrient"
)
name = models.CharField("nutrient alias name", max_length=50, unique=True)
def __str__(self):
return 'PK: '+str(self.pk) + ' ' + self.name
#-------------------------------------------------------------------------------
class Article(models.Model):
#RowId = models.IntegerField(primary_key=True)
name = models.CharField("article name", max_length=100)
brand = models.ForeignKey(
Brand,
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name="brand id"
)
EAN = CharNullField(
"EAN", max_length=50,
unique=True,
blank=True,
null=True
)
offlink = models.URLField("Open Food Fact link", blank=True, null=True)
category = models.ForeignKey(
Category,
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name="category id"
)
quantityPerPackage = models.PositiveIntegerField("quantity per packages", blank=True, null=True)
unit = CharNullField("unit",max_length=4, blank=True, null=True)
novaGroup = models.PositiveIntegerField("NOVA group", blank=True, null=True)
nutritionGrade = models.CharField("nutri grade",max_length=1, blank=True, null=True)
ecoGrade = models.CharField("eco grade",max_length=1, blank=True, null=True)
MwSt = models.PositiveIntegerField("taxes", blank=True, null=True)
allergenes = models.ManyToManyField(Allergenes, blank=True)
ingredients = models.ManyToManyField(Ingredients, through='IngredientsArticle', blank=True)
traces = models.ManyToManyField(Traces, blank=True)
embs = models.ManyToManyField(EMBs, blank=True)
manufacturingPlaces = models.ManyToManyField(ManufacturingPlaces, blank=True)
originIngredients = models.ManyToManyField(OriginIngredients, blank=True)
packagings = models.ManyToManyField(Packaging, through='PackagingArticle', blank=True)
nutrients = models.ManyToManyField(Nutrient, through='NutrientArticle', blank=True)
labels = models.ManyToManyField(Labels, blank=True)
models.ForeignKey(
Category,
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name="category id"
)
created = models.DateTimeField(
"created",
default=timezone.now,
db_index=True)
modified = models.DateTimeField(
"modified",
auto_now=True,
editable=False,
db_index=True)
nutritionImage = models.ImageField(
"nutriton image filepath",
default=None,
#unique=True,
blank=True,
null=True,
help_text="Nutrition image",
upload_to='nutritionImages'
)
ingredientsImage = models.ImageField(
"ingredients image filepath",
default=None,
#unique=True,
blank=True,
null=True,
help_text="Ingredients image",
upload_to='ingredientsImages'
)
frontImage = models.ImageField(
"front image",
default=None,
#unique=True,
null=True,
blank=True,
help_text="Front image",
upload_to='frontImages'
)
def __str__(self):
return 'PK: '+str(self.pk) + ' ' + self.name
#-------------------------------------------------------------------------------
class IngredientsArticle(models.Model):
ingredient = models.ForeignKey(
Ingredients,
blank=True,
null=True,
on_delete=models.CASCADE,
verbose_name="Ingredient"
)
article = models.ForeignKey(
Article,
blank=True,
null=True,
on_delete=models.CASCADE,
verbose_name="article"
)
position = models.PositiveIntegerField("Position")
percent = models.FloatField(
"Percentage on total weight",
blank=True,
null=True,
default=None
)
#-------------------------------------------------------------------------------
class PackagingArticle(models.Model):
packaging_id = models.ForeignKey(
Packaging,
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name="packaging id"
)
article_id = models.ForeignKey(
Article,
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name="article id"
)
weight = models.PositiveIntegerField("weight")
#-------------------------------------------------------------------------------
class NutrientArticle(models.Model):
nutrient = models.ForeignKey(
Nutrient,
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name="nutrient"
)
article = models.ForeignKey(
Article,
blank=True,
null=True,
on_delete=models.CASCADE,
verbose_name="article"
)
value = models.DecimalField("value", max_digits=7, decimal_places=2, blank=True, null=True)
unit = models.CharField(max_length=4, blank=True, null=True)
isEstimated = models.BooleanField("Is nutrient exstimated?", default=False)
class Meta:
unique_together = ('article', 'nutrient',)
# Deprectated, will be deleted later
class NutritionalValues(models.Model):
article = models.OneToOneField(
Article,
on_delete=models.CASCADE,
primary_key=True,
)
energy = models.DecimalField("energy",max_digits=7,decimal_places=2,blank=True, null=True)
energyUnit = models.CharField(max_length=4,blank=True, null=True,default='kJ')
fat = models.DecimalField("fat",max_digits=7,decimal_places=2,blank=True, null=True)
fatUnit = models.CharField(max_length=2,blank=True, null=True,default='g')
saturatedFat = models.DecimalField("saturatedFat",max_digits=7,decimal_places=2,blank=True, null=True)
saturatedFatUnit = models.CharField(max_length=2,blank=True, null=True,default='g')
carbohydrate = models.DecimalField("carbohydrate",max_digits=7,decimal_places=2,blank=True, null=True)
carbohydrateUnit = models.CharField(max_length=2,blank=True, null=True,default='g')
sugars = models.DecimalField("sugars",max_digits=7,decimal_places=2,blank=True, null=True)
sugarsUnit = models.CharField(max_length=2,blank=True, null=True,default='g')
dietaryFiber = models.DecimalField("dietaryFiber",max_digits=7,decimal_places=2,blank=True, null=True)
dietaryFiberUnit = models.CharField(max_length=2,blank=True, null=True,default='g')
proteins = models.DecimalField("proteins",max_digits=7,decimal_places=2,blank=True, null=True)
proteinsUnit = models.CharField(max_length=2,blank=True, null=True,default='g')
salt = models.DecimalField("salt",max_digits=7,decimal_places=2,blank=True, null=True)
saltUnit = models.CharField(max_length=2,blank=True, null=True,default='g')
sodium = models.DecimalField("sodium",max_digits=7,decimal_places=2,blank=True, null=True)
sodiumUnit = models.CharField(max_length=2,blank=True, null=True)
vitamin_a = models.DecimalField("vitamin_a",max_digits=7,decimal_places=2,blank=True, null=True)
vitamin_aUnit = models.CharField(max_length=2,blank=True, null=True)
vitamin_b1 = models.DecimalField("vitamin_b1",max_digits=7,decimal_places=2,blank=True, null=True)
vitamin_b1Unit = models.CharField(max_length=2,blank=True, null=True)
vitamin_b2 = models.DecimalField("vitamin_b2",max_digits=7,decimal_places=2,blank=True, null=True)
vitamin_b2Unit = models.CharField(max_length=2,blank=True, null=True)
vitamin_b3 = models.DecimalField("vitamin_b3",max_digits=7,decimal_places=2,blank=True, null=True)
vitamin_b3Unit = models.CharField(max_length=2,blank=True, null=True)
vitamin_b5 = models.DecimalField("vitamin_b5",max_digits=7,decimal_places=2,blank=True, null=True)
vitamin_b5Unit = models.CharField(max_length=2,blank=True, null=True)
vitamin_b7 = models.DecimalField("vitamin_b7",max_digits=7,decimal_places=2,blank=True, null=True)
vitamin_b7Unit = models.CharField(max_length=2,blank=True, null=True)
vitamin_b9 = models.DecimalField("vitamin_b9",max_digits=7,decimal_places=2,blank=True, null=True)
vitamin_b9Unit = models.CharField(max_length=2,blank=True, null=True)
vitamin_b12 = models.DecimalField("vitamin_b12",max_digits=7,decimal_places=2,blank=True, null=True)
vitamin_b12Unit = models.CharField(max_length=2,blank=True, null=True)
vitamin_c = models.DecimalField("vitamin_c",max_digits=7,decimal_places=2,blank=True, null=True)
vitamin_cUnit = models.CharField(max_length=2,blank=True, null=True)
vitamin_d = models.DecimalField("vitamin_d",max_digits=7,decimal_places=2,blank=True, null=True)
vitamin_dUnit = models.CharField(max_length=2,blank=True, null=True)
vitamin_e = models.DecimalField("vitamin_e",max_digits=7,decimal_places=2,blank=True, null=True)
vitamin_eUnit = models.CharField(max_length=2,blank=True, null=True)
vitamin_k = models.DecimalField("vitamin_k",max_digits=7,decimal_places=2,blank=True, null=True)
vitamin_kUnit = models.CharField(max_length=2,blank=True, null=True)
potassium = models.DecimalField("potassium",max_digits=7,decimal_places=2,blank=True, null=True)
potassiumUnit = models.CharField(max_length=2,blank=True, null=True)
calcium = models.DecimalField("calcium",max_digits=7,decimal_places=2,blank=True, null=True)
calciumUnit = models.CharField(max_length=2,blank=True, null=True)
magnesium = models.DecimalField("magnesium",max_digits=7,decimal_places=2,blank=True, null=True)
magnesiumUnit = models.CharField(max_length=2,blank=True, null=True)
iron = models.DecimalField("iron",max_digits=7,decimal_places=2,blank=True, null=True)
ironUnit = models.CharField(max_length=2,blank=True, null=True)
zinc = models.DecimalField("zinc",max_digits=7,decimal_places=2,blank=True, null=True)
zincUnit = models.CharField(max_length=2,blank=True, null=True)
sulfat = models.DecimalField("sulfat",max_digits=7,decimal_places=2,blank=True, null=True)
sulfatUnit = models.CharField(max_length=2,blank=True, null=True)
chlorid = models.DecimalField("chlorid",max_digits=7,decimal_places=2,blank=True, null=True)
chloridUnit = models.CharField(max_length=2,blank=True, null=True)
hydrogencarbonat = models.DecimalField("hydrogencarbonat",max_digits=7,decimal_places=2,blank=True, null=True)
hydrogencarbonatUnit = models.CharField(max_length=2,blank=True, null=True)
class ReceipeString(models.Model):
name = models.CharField("receipe string", max_length=50, unique=True)
def __str__(self):
return 'PK: '+str(self.pk) + ' ' + self.receipeString
class ArticleMaps(models.Model):
article = models.ForeignKey(
Article,
blank=True,
null=True,
on_delete=models.CASCADE,
verbose_name="article id"
)
#receipeString = models.CharField("receipe string", max_length=50)
receipeString = models.ForeignKey(
ReceipeString,
on_delete=models.CASCADE,
null=True,
verbose_name="receipe string"
)
location_x = models.PositiveIntegerField("x coordiante in image", null=True)
location_y = models.PositiveIntegerField("y coordiante in image", null=True)
location_h = models.PositiveIntegerField("height in image", null=True)
location_w = models.PositiveIntegerField("width in image", null=True)
receipeImage = models.ForeignKey(ReceipeImage, on_delete=models.CASCADE)
class Meta:
unique_together = ('article', 'receipeImage',)
def __str__(self):
return 'PK: '+str(self.pk) + ' ' + ' ' + self.receipeString.name
class Market(models.Model):
#RowId = models.AutoField(primary_key=True)
name = models.CharField("market name", max_length=50)
street = models.CharField("street name", max_length=50)
street_number = models.PositiveIntegerField("street number")
zip_code = models.CharField("zip code", max_length=5)
city = models.CharField("city", max_length=50)
phone = CharNullField("phone number",max_length=50, blank=True, null=True)
articles = models.ManyToManyField(Article,blank=True)
created = models.DateTimeField(
"created",
default=timezone.now,
db_index=True)
modified = models.DateTimeField(
"modified",
auto_now=True,
editable=False,
db_index=True)
def __str__(self):
return 'PK: '+str(self.pk) + ' ' + self.name + ' ' + self.street + ' ' + str(self.street_number) + ' ' + self.city
class Purchase(models.Model):
purchase_date = models.DateField("purchase date")
payment_type = models.CharField("payment type",max_length=10,default='EC')
total_price = models.DecimalField("total price",max_digits=7,decimal_places=2,default=0)
articles = models.ManyToManyField(Article, through='PurchaseArticle')
market = models.ForeignKey(
Market,
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name="market id"
)
created = models.DateTimeField(
"created",
default=timezone.now,
db_index=True)
modified = models.DateTimeField(
"modified",
auto_now=True,
editable=False,
db_index=True)
receipeImage = models.OneToOneField(
ReceipeImage,
on_delete=models.CASCADE,
primary_key=True,
blank = True,
)
edit_finished = models.BooleanField("edit finished", default=False)
def __str__(self):
return 'PK: '+str(self.pk) + ' Datum: ' + self.purchase_date.strftime("%m/%d/%Y") + ' Preis: ' +str(self.total_price)
#-------------------------------------------------------------------------------
class PurchaseArticle(models.Model):
#shoud be renamed to article, but migrations will delete the current database
article_id = models.ForeignKey(
Article,
blank=True,
null=True,
on_delete=models.CASCADE,
verbose_name="article id"
)
purchase_id = models.ForeignKey(
Purchase,
blank=True,
null=True,
on_delete=models.CASCADE,
verbose_name="purchase id"
)
quantity = models.PositiveIntegerField("quantity")
net_weight = models.DecimalField("net weight",max_digits=7,decimal_places=3, blank=True, null=True)
price = models.DecimalField("price",max_digits=7,decimal_places=2,default=0)
inSale = models.BooleanField("in sale",default=False)