I am using in django the following models.py:
class Expense(models.Model):
name = models.CharField(max_length=50)
date = models.DateField(unique=False, blank=False)
slug = models.SlugField(unique=True, null=True, default='')
price = models.DecimalField(default=0.0, blank=True, max_digits = 20, decimal_places = 2)
category = models.ForeignKey(
'Category',
related_name="Expense",
on_delete=models.CASCADE
)
account = models.ForeignKey(Account, on_delete=models.CASCADE, verbose_name=u"Account", help_text=u"account")
def __str__(self):
return '{},{},{}'.format(self.name, self.date, self.price)
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Expense,self).save(*args, **kwargs)
def get_absolute_url(self):
return self.slug
class Category(MPTTModel):
name = models.CharField(max_length=200)
slug = models.SlugField(unique=True, null=True, default='')
parent = TreeForeignKey(
'self',
blank=True,
null=True,
related_name='child',
on_delete=models.CASCADE
)
class Meta:
unique_together = ('slug', 'parent',)
verbose_name_plural = "categories"
def __str__(self):
full_path = [self.name]
k = self.parent
while k is not None:
full_path.append(k.name)
k = k.parent
return ' -> '.join(full_path[::-1])
The TreeForeignKey allows me to define nested categories, such as Home -> Electricity and so on.
I am using the following Slick Report view.py:
class TotalExpenses(SlickReportView):
report_model = Expense
date_field = 'date'
group_by = 'category'
columns = ['name', SlickReportField.create(method=Sum, field='price', name='price__sum', verbose_name=('Total category $'))]
charts_settings = [
{
'type': 'bar',
'data_source': 'price__sum',
'title_source': 'name',
},
]
It works but I would like to sum only level 1 categories. Do you know how this might be possible?
Related
I am using a form that saves to one model to update the most current mileage which is stored in another model. I want to make sure the mileage entered is > or = the current mileage. I havent been able to figure out the right validation or where to write the validation.
I have tried an if statement in the form_valid() of the CreateView and a save() method in the model.
Models.py
class Vehicle(models.Model):
name = models.CharField(blank=True, max_length=100)
make = models.CharField(blank=True, max_length=100)
model = models.CharField(blank=True, max_length=100)
year = models.IntegerField(blank=True, null=True)
vin = models.CharField(blank=True, max_length=17)
gvw = models.IntegerField(blank=True, null=True)
license_plate = models.CharField(blank=True, max_length=100)
purchase_date = models.DateField()
current_mileage = models.IntegerField(blank=True, null=True)
class Meta:
ordering = ['name']
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('vehicles:vehicle_detail', kwargs={'pk':self.pk})
#property
def get_current_mileage(self):
return self.current_mileage
class FuelEntry(models.Model):
vehicle = models.ForeignKey(Vehicle, on_delete=models.CASCADE)
date = models.DateTimeField(auto_now_add=True)
fuel_choices = (
('EMPTY', 'Empty'),
('1/8', '1/8'),
('1/4', '1/4'),
('1/2', '1/2'),
('3/4', '3/4'),
('FULL', 'Full'),
)
current = models.CharField(max_length=5, choices=fuel_choices)
after = models.CharField(max_length=5, choices=fuel_choices, blank=True)
gallons = models.DecimalField(decimal_places=2, max_digits=5, blank=True, default='0')
cost = models.DecimalField(decimal_places=2, max_digits=5, blank=True, default='0')
mileage = models.IntegerField(blank=False)
user = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
ordering = ['-date', 'vehicle']
def __str__(self):
return self.vehicle.name
def get_absolute_url(self):
return reverse('fuellog:entry_detail', kwargs={'pk':self.pk})
Views.py
class CreateEntry(CreateView):
model = FuelEntry
fields = ('vehicle', 'current', 'after', 'gallons', 'cost', 'mileage')
def form_valid(self,form):
self.object = form.save(commit=False)
self.object.user = self.request.user
vehicle_id = self.object.vehicle.pk
mileage = self.object.mileage
self.object.save()
current_mileage = Vehicle.objects.filter(id=vehicle_id).get('current_mileage')
if current_mileage > mileage:
raise ValidationError('Incorrect mileage reading')
Vehicle.objects.filter(id=vehicle_id).update(current_mileage=mileage)
return super().form_valid(form)
ValueError at /fuel/new
too many values to unpack (expected 2)
I have a model CartItem that has a ForeignKey to a Product model.
Because from Product model I get the description, image, etc.
However, I want to have a method called sub_total that returns and integer. I use this to calculate total to be paid for this CartItem.
This sub_total method query a different model costo_de_los_productos using some of the properties of CartItem. like: self.product.category.name, self.product.name, self.size, self.quantity.
I need to return an Integer from sub_total method.
However, something is not right with me query, if I comment it and return 0 it works, but total is 0.
def sub_total(self):
product_price = costo_de_los_productos.objects.filter(category=self.product.category.name,
product = self.product.name,
size=self.size,
quantity=self.quantity).values_list("price", flat=True)
What could be wrong?
class CartItem(models.Model):
cart = models.ForeignKey(Cart, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
size = models.CharField(max_length=20, choices=TAMANIOS)
quantity = models.CharField(max_length=20, choices=CANTIDADES)
file = models.FileField(upload_to='files', blank=True, null=True)
comment = models.CharField(max_length=100, blank=True, null=True, default='')
uploaded_at = models.DateTimeField(auto_now_add=True)
step_two_complete = models.BooleanField(default=False)
# def __str__(self):
# return str(self.id) + " - " + str(self.size) + " por " + str(self.quantity)
def sub_total(self):
product_price = costo_de_los_productos.objects.filter(category = self.product.category.name,
product = self.product.name,
size=self.size,
quantity=self.quantity).values_list("price", flat=True)
# print(type(product_price))
return product_price
costo_de_los_productos model:
class costo_de_los_productos(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
price = models.IntegerField(default=30)
size = models.CharField(max_length=20, choices=TAMANIOS)
quantity = models.CharField(max_length=20, choices=CANTIDADES)
product model:
class Product(models.Model):
name = models.CharField(max_length=250, unique=False)
slug = models.SlugField(max_length=250, unique=False)
description = models.TextField(blank=True)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
image = models.ImageField(upload_to='product', blank=True, null=True)
available = models.BooleanField(default=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
ordering = ('name',)
verbose_name = 'product'
verbose_name_plural = 'products'
def get_url(self):
return reverse('shop:ProdDetail', args=[self.category.slug, self.slug])
def __str__(self):
return '{}'.format(self.name)
category model:
class Category(models.Model):
name = models.CharField(max_length=250, unique=True)
slug = models.SlugField(max_length=250, unique=True)
description = models.TextField(blank=True, null=True)
image = models.ImageField(upload_to='category', blank=True, null=True)
video = EmbedVideoField(null=True, blank=True)
class Meta:
ordering = ('name',)
verbose_name = 'category'
verbose_name_plural = 'categories'
def get_url(self):
return reverse('shop:allCat', args=[self.slug])
def __str__(self):
return '{}'.format(self.name)
Image of "costo_de_los_productos" from Admin Panel:
UPDATE 1
Cannot print anything after the product_price query.
def sub_total(self):
print("Enters Subtotal")
print(self.product.category.name)
print(self.product.name)
print(self.size)
print(self.quantity)
product_price = costo_de_los_productos.objects.filter(category=self.product.category.name,
product=self.product.name,
size=self.size,
quantity=self.quantity).values_list("price", flat=True)[0]
print("Line after product_price query")
print(type(product_price))
return product_price
Hard coding the values doesn't return expected integer:
def sub_total(self):
print("Enters Subtotal")
print(self.product.category.name)
print(self.product.name)
print(self.size)
print(self.quantity)
product_price = costo_de_los_productos.objects.filter(category="Stickers",
product="Stickers transparentes",
size="5cm x 5cm",
quantity=300).values_list("price", flat=True)[0]
print("Line after product_price query")
print(type(product_price))
return product_price
prints results:
Enters Subtotal
Stickers
Stickers transparentes
5cm x 5cm
300
forms.py
class MySelect(forms.Select):
def __init__(self, *args, **kwargs):
self.variations = kwargs.pop('variations')
super(MySelect, self).__init__(*args, **kwargs)
def render_option(self, selected_choices, option_value, option_label):
return '<option whatever>...</option>'
class CartItemForm(forms.ModelForm):
class Meta:
model = CartItem
fields = (
'variation',
'width',
'height',
'quantity',
)
widgets = {
'variation': MySelect(variations=self.variation_query)
}
def __init__(self, *args, **kwargs):
product = kwargs.pop('product')
try:
cart = kwargs.pop('cart')
self.cart = cart
except:
pass
super().__init__(*args, **kwargs)
variation_field = self.fields['variation']
variation_field.queryset = Variation.objects.filter(
product=product
)
self.variation_query = Variation.objects.filter(
product=product
)
def save(self):
cart_item = super().save(commit=False)
cart_item.cart = self.cart
cart_item.save()
return cart_item
Below is where you have to pay attention to.
(in Meta class)
widgets = {
'variation': MySelect(variations=self.variation_query)
}
self.variation_query is from __init__.
How can I do this?
models.py
class CartItem(models.Model):
cart = models.ForeignKey("Cart")
variation = models.ForeignKey(Variation)
# 벽화 너비
width = models.PositiveIntegerField(
default=1,
validators=[MinValueValidator(1)],
)
class Product(TimeStampedModel):
name = models.CharField(max_length=120, unique=True)
slug = models.SlugField(null=True, blank=True)
description = models.TextField(max_length=400, blank=True)
is_active = models.BooleanField(default=True)
place_category = models.ForeignKey(
"PlaceCategory",
related_name="products_by_place", # category.products_by_place.all()
)
subject_category_set = models.ManyToManyField(
"SubjectCategory",
related_name="products_by_subject", # category.products_by_subject.all()
)
# 벽화 높이
height = models.PositiveIntegerField(
default=1,
validators=[MinValueValidator(1)],
)
quantity = models.PositiveIntegerField(
default=1,
validators=[MinValueValidator(1)],
)
class Variation(TimeStampedModel):
COLOR_CHOICES = (
('black', '흑백'),
('single', '단색'),
('multi', '컬러'),
)
price = models.DecimalField(
decimal_places=0,
max_digits=15,
blank=True,
null=True,
)
product = models.ForeignKey(Product)
color = models.CharField(
max_length=10,
choices=COLOR_CHOICES,
)
is_active = models.BooleanField(default=True)
That's not a thing you would do in Meta. You need to do the whole thing in __init__.
You're already doing that in fact, so I don't know why you want to override Meta at all.
I think that showing code is much easier than explanation.
models.py
class Product(TimeStampedModel):
name = models.CharField(max_length=120, unique=True)
slug = models.SlugField(null=True, blank=True)
description = models.TextField(max_length=400, blank=True)
is_active = models.BooleanField(default=True)
place_category = models.ForeignKey(
"PlaceCategory",
related_name="products_by_place", # category.products_by_place.all()
)
subject_category_set = models.ManyToManyField(
"SubjectCategory",
related_name="products_by_subject", # category.products_by_subject.all()
)
objects = ProductManager()
class Meta:
ordering = ('-created',)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse(
"products:product_detail",
kwargs={
"slug": self.slug,
}
)
class Category(TimeStampedModel):
name = models.CharField(max_length=25, unique=True)
is_active = models.BooleanField(default=True)
class Meta:
abstract = True
def __str__(self):
return self.name
class PlaceCategory(Category):
class Meta:
verbose_name = "Place Category"
verbose_name_plural = "Place Categories"
class SubjectCategory(Category):
class Meta:
verbose_name = "Subject Category"
verbose_name_plural = "Subject Categories"
This is what I'm trying to do in shell.
# place category
self.place_category = PlaceCategory.objects.create(name="학교")
# subject category
self.subject_category1 = SubjectCategory.objects.create(name="사람")
self.subject_category2 = SubjectCategory.objects.create(name="꽃병")
# product
self.product = Product.objects.create(
name="product name1",
place_category=self.place_category,
subject_category_set=(
self.subject_category1,
self.subject_category2,
)
)
But it doesn't work. Any idea?
What I could think of is moving ManyToManyField from Product to SubjectCategory.
But I want know as in my code. Thanks.
You need to add subject category to your product.
So do it like this:
# place category
self.place_category = PlaceCategory.objects.create(name="학교")
# subject category
self.subject_category1 = SubjectCategory.objects.create(name="사람")
self.subject_category2 = SubjectCategory.objects.create(name="꽃병")
# product
self.product = Product.objects.create(
name="product name1",
place_category=self.place_category,
)
self.product.subject_category_set.add(self.subject_category1)
self.product.subject_category_set.add(self.subject_category2)
or you can make something like this
list_of_subject_categories = [self.subject_category1, self.subject_category2]
self.product.subject_category_set.add(*list_of_subject_categories)
How to sort by custom field in Django admin.
My database's tables are without any ForeignKey,
django framework design by related ship.
This model define:
class UserBaseInfo(BaseModel):
STATUS = [(0, 'not pass'), (1, 'pass')]
SEX = [(0, 'unset'), (1, 'male'), (2, 'female')]
parent_id = models.IntegerField(max_length=11, default=0)
level_id = models.IntegerField(max_length=11, default=1)
phone = models.BigIntegerField(max_length=15, null=True, blank=True, default=None)
nickname = models.CharField(max_length=100)
sex = models.IntegerField(null=False, blank=False, default=1, choices=SEX)
country = models.CharField(max_length=100, null=True, blank=True)
province = models.CharField(max_length=100, null=True, blank=True)
city = models.CharField(max_length=100, null=True, blank=True)
headimgurl = models.CharField(max_length=255, null=True, blank=True)
status = models.IntegerField(max_length=3, default=0)
updated_time = models.BigIntegerField(max_length=18, null=True, blank=True)
class Meta:
db_table = 'user_base_info'
ordering = ('-created_time', '-updated_time')
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
initial = False
if not self.id:
initial = True
super(UserBaseInfo, self).save(force_insert=force_insert, force_update=force_update, using=using,
update_fields=update_fields)
if initial:
Wallet(user_id=self.id, money=1000).save()
class Wallet(models.Model):
user_id = models.BigIntegerField(max_length=18, primary_key=True, null=False, blank=False, verbose_name=_('UserId'))
money = models.FloatField(null=False, blank=False)
class Meta:
db_table = 'wallet'
This admin
class UserBaseInfoAdmin(CSVAdmin):
list_display = ('nickname', 'avatar', 'level_id', 'parent', 'income', 'sex', 'country', 'province', 'city')
list_filter = ('nickname', 'level_id', 'sex', ('created_time', DateFieldListFilter), ('updated_time', DateFieldListFilter))
search_fields = ('nickname', 'level_id', 'sex', 'created_time', 'updated_time')
list_display_links = ('level_id',)
readonly_fields = ('nickname', 'level_id', 'sex', 'country', 'province', 'city', 'headimgurl',
'language', 'openid', 'privilege', 'created_time', 'updated_time')
list_per_page = 20
list_max_show_all = 20
def avatar(self, data):
return format_html('<img src="%s" height="50px" style="border-radius:50px"/>' % data.headimgurl)
def parent(self, data):
user = UserBaseInfo.objects.filter(pk=data.parent_id).first()
return user.nickname if user else ''
parent.allow_tags = True
parent.admin_order_field = 'parent_id'
def income(self, data):
wallet = Wallet.objects.filter(user_id=data.id).first()
if wallet:
return wallet.money / 100
income.admin_order_field = 'wallet__money'
I want to order by wallet's money, but I don't how to do next;