I am trying to add object to m2m with add method but neither its showing error nor adding item, I can't understand why
Here is my view :
class UpdateCartView(generic.UpdateView):
model = Cart
fields = ['products']
template_name = 'update_cart.html'
success_url = reverse_lazy('carts:home')
def form_valid(self,form):
product = ProductCreateModel.objects.get(pk = self.request.POST.get('product'))
size = Size.objects.get(pk = self.request.POST.get('size'))
colour = Colour.objects.get(pk = self.request.POST.get('colour'))
products = Products.objects.create(product = product,
size = size,
quantity = int(self.request.POST.get('quantity')),
colour = colour)
product.save()
cart = self.get_object()
print(products)
cart.products.add(products)
cart.save()
return super(UpdateCartView,self).form_valid(form)
def get_object(self):
cart_obj, cart_created = Cart.objects.new_or_get(self.request)
return cart_obj
Here is my models :
class Products(models.Model):
product = models.ForeignKey(ProductCreateModel,on_delete=models.CASCADE,related_name='cart_product')
quantity = models.PositiveIntegerField(default=1,validators=[MinValueValidator(1)])
size = models.ForeignKey(Size,related_name='cart_product_size',on_delete=models.CASCADE,null=True,blank=False)
colour = models.ForeignKey(Colour,related_name='cart_product_colour',on_delete=models.CASCADE,null=True,blank=False)
def __str__(self):
return '{product}({quantity})'.format(product=self.product,quantity=self.quantity)
class Cart(models.Model):
MESSAGE_CHOICES = (
('A' , 'Items are added to you cart'),
('R' , 'Items are removed from cart'),
('PC' , 'Price of some items has changed'),
)
messages = models.CharField(max_length=1, choices=MESSAGE_CHOICES,null=True,blank=True)
user = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE)
products = models.ManyToManyField(Products, blank=True)
subtotal = models.DecimalField(default=0.00, max_digits=100, decimal_places=2)
total = models.DecimalField(default=0.00, max_digits=100, decimal_places=2)
updated = models.DateTimeField(auto_now=True)
timestamp = models.DateTimeField(auto_now_add=True)
objects = CartManager()
def __str__(self):
return str(self.id)
def m2m_changed_cart_receiver(sender, instance, action, *args, **kwargs):
if action == 'post_add' or action == 'post_remove' or action == 'post_clear':
products = instance.products.all()
total = 0
for x in products:
total += (x.product.final_price * x.quantity)
if instance.subtotal != total:
instance.subtotal = total
instance.save()
def pre_save_cart_receiver(sender, instance, *args, **kwargs):
if instance.subtotal > 0:
instance.total = Decimal(instance.subtotal) * Decimal(1.08) # 8% tax
else:
instance.total = 0.00
Everything is working fine, no errors, also print the products but in my admin panel its showing empty cart means cart.products.add(products) not added products why ?
My template.html:
{% for x in post.tags.all %}
<a href="{% url 'blog:post_list_by_tag' x.slug %}">
{{ x.name }}
</a>
{% if not forloop.last %}, {% endif %}
{% endfor %}
I haven't space at the end of the lines and I haven't space in the name (in database) but the output is:
tag1 , tag2 , tag3
with a space between name and comma and a space at the end. Even with one tag there's a space at the end. I use taggit, maybe the problem is there.
Also the links underline even the white spaces when after there's the comma (so not at the end). If I write {{ x.name }}</a> the spaces are there but the links underline only the tags, not the spaces.
In myview
print(post.tags) => AttributeError: '_TaggableManager' object has no attribute 'name'
print(post.tags.all) =>
<bound method BaseManager.all of <taggit.managers._TaggableManager object at 0x03EFEA70>>
Mymodel.py:
class Post(models.Model):
author = models.ForeignKey('auth.User', blank=True,
on_delete=models.PROTECT, verbose_name=_('autore'))
title = models.CharField(_('titolo'), max_length=32)
text = models.TextField(_('testo'))
created_date = models.DateTimeField(_('creato il'),
default=timezone.now)
published_date = models.DateTimeField(_('pubblicato il'),
blank=True, null=True)
likes = models.ManyToManyField(settings.AUTH_USER_MODEL,
related_name='posts_liked', blank=True, verbose_name=_('piace a'))
dislikes = models.ManyToManyField(settings.AUTH_USER_MODEL,
related_name='posts_disliked', blank=True, verbose_name=_('non piace a'))
tags = TaggableManager()
views = models.IntegerField(_('visite'), default=0)
block_comment = models.BooleanField(default=False)
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.title
class Meta:
verbose_name = pgettext('singolare', 'post')
verbose_name_plural = pgettext('plurale', 'post')
...
taggit.managers.py:
...
class _TaggableManager(models.Manager):
def __init__(self, through, model, instance, prefetch_cache_name):
self.through = through
self.model = model
self.instance = instance
self.prefetch_cache_name = prefetch_cache_name
self._db = None
def is_cached(self, instance):
return self.prefetch_cache_name in instance._prefetched_objects_cache
def get_queryset(self, extra_filters=None):
try:
return self.instance._prefetched_objects_cache[self.prefetch_cache_name]
except (AttributeError, KeyError):
kwargs = extra_filters if extra_filters else {}
return self.through.tags_for(self.model, self.instance, **kwargs)
def get_prefetch_queryset(self, instances, queryset=None):
if queryset is not None:
raise ValueError("Custom queryset can't be used for this lookup.")
instance = instances[0]
from django.db import connections
db = self._db or router.db_for_read(instance.__class__, instance=instance)
fieldname = ('object_id' if issubclass(self.through, CommonGenericTaggedItemBase)
else 'content_object')
fk = self.through._meta.get_field(fieldname)
query = {
'%s__%s__in' % (self.through.tag_relname(), fk.name):
set(obj._get_pk_val() for obj in instances)
}
join_table = self.through._meta.db_table
source_col = fk.column
connection = connections[db]
qn = connection.ops.quote_name
qs = self.get_queryset(query).using(db).extra(
select={
'_prefetch_related_val': '%s.%s' % (qn(join_table), qn(source_col))
}
)
return (qs,
attrgetter('_prefetch_related_val'),
lambda obj: obj._get_pk_val(),
False,
self.prefetch_cache_name)
# Django < 1.6 uses the previous name of query_set
get_query_set = get_queryset
get_prefetch_query_set = get_prefetch_queryset
def _lookup_kwargs(self):
return self.through.lookup_kwargs(self.instance)
#require_instance_manager
def add(self, *tags):
db = router.db_for_write(self.through, instance=self.instance)
tag_objs = self._to_tag_model_instances(tags)
new_ids = set(t.pk for t in tag_objs)
# NOTE: can we hardcode 'tag_id' here or should the column name be got
# dynamically from somewhere?
vals = (self.through._default_manager.using(db)
.values_list('tag_id', flat=True)
.filter(**self._lookup_kwargs()))
new_ids = new_ids - set(vals)
signals.m2m_changed.send(
sender=self.through, action="pre_add",
instance=self.instance, reverse=False,
model=self.through.tag_model(), pk_set=new_ids, using=db,
)
for tag in tag_objs:
self.through._default_manager.using(db).get_or_create(
tag=tag, **self._lookup_kwargs())
signals.m2m_changed.send(
sender=self.through, action="post_add",
instance=self.instance, reverse=False,
model=self.through.tag_model(), pk_set=new_ids, using=db,
)
def _to_tag_model_instances(self, tags):
"""
Takes an iterable containing either strings, tag objects, or a mixture
of both and returns set of tag objects.
"""
db = router.db_for_write(self.through, instance=self.instance)
str_tags = set()
tag_objs = set()
for t in tags:
if isinstance(t, self.through.tag_model()):
tag_objs.add(t)
elif isinstance(t, six.string_types):
str_tags.add(t)
else:
raise ValueError(
"Cannot add {0} ({1}). Expected {2} or str.".format(
t, type(t), type(self.through.tag_model())))
if getattr(settings, 'TAGGIT_CASE_INSENSITIVE', False):
# Some databases can do case-insensitive comparison with IN, which
# would be faster, but we can't rely on it or easily detect it.
existing = []
tags_to_create = []
for name in str_tags:
try:
tag = (self.through.tag_model()._default_manager
.using(db)
.get(name__iexact=name))
existing.append(tag)
except self.through.tag_model().DoesNotExist:
tags_to_create.append(name)
else:
# If str_tags has 0 elements Django actually optimizes that to not
# do a query. Malcolm is very smart.
existing = (self.through.tag_model()._default_manager
.using(db)
.filter(name__in=str_tags))
tags_to_create = str_tags - set(t.name for t in existing)
tag_objs.update(existing)
for new_tag in tags_to_create:
tag_objs.add(
self.through.tag_model()._default_manager
.using(db)
.create(name=new_tag))
return tag_objs
#require_instance_manager
def names(self):
return self.get_queryset().values_list('name', flat=True)
#require_instance_manager
def slugs(self):
return self.get_queryset().values_list('slug', flat=True)
#require_instance_manager
def set(self, *tags, **kwargs):
"""
Set the object's tags to the given n tags. If the clear kwarg is True
then all existing tags are removed (using `.clear()`) and the new tags
added. Otherwise, only those tags that are not present in the args are
removed and any new tags added.
"""
db = router.db_for_write(self.through, instance=self.instance)
clear = kwargs.pop('clear', False)
if clear:
self.clear()
self.add(*tags)
else:
# make sure we're working with a collection of a uniform type
objs = self._to_tag_model_instances(tags)
# get the existing tag strings
old_tag_strs = set(self.through._default_manager
.using(db)
.filter(**self._lookup_kwargs())
.values_list('tag__name', flat=True))
new_objs = []
for obj in objs:
if obj.name in old_tag_strs:
old_tag_strs.remove(obj.name)
else:
new_objs.append(obj)
self.remove(*old_tag_strs)
self.add(*new_objs)
#require_instance_manager
def remove(self, *tags):
if not tags:
return
db = router.db_for_write(self.through, instance=self.instance)
qs = (self.through._default_manager.using(db)
.filter(**self._lookup_kwargs())
.filter(tag__name__in=tags))
old_ids = set(qs.values_list('tag_id', flat=True))
signals.m2m_changed.send(
sender=self.through, action="pre_remove",
instance=self.instance, reverse=False,
model=self.through.tag_model(), pk_set=old_ids, using=db,
)
qs.delete()
signals.m2m_changed.send(
sender=self.through, action="post_remove",
instance=self.instance, reverse=False,
model=self.through.tag_model(), pk_set=old_ids, using=db,
)
#require_instance_manager
def clear(self):
db = router.db_for_write(self.through, instance=self.instance)
signals.m2m_changed.send(
sender=self.through, action="pre_clear",
instance=self.instance, reverse=False,
model=self.through.tag_model(), pk_set=None, using=db,
)
self.through._default_manager.using(db).filter(
**self._lookup_kwargs()).delete()
signals.m2m_changed.send(
sender=self.through, action="post_clear",
instance=self.instance, reverse=False,
model=self.through.tag_model(), pk_set=None, using=db,
)
def most_common(self, min_count=None, extra_filters=None):
queryset = self.get_queryset(extra_filters).annotate(
num_times=models.Count(self.through.tag_relname())
).order_by('-num_times')
if min_count:
queryset = queryset.filter(num_times__gte=min_count)
return queryset
#require_instance_manager
def similar_objects(self):
lookup_kwargs = self._lookup_kwargs()
lookup_keys = sorted(lookup_kwargs)
qs = self.through.objects.values(*six.iterkeys(lookup_kwargs))
qs = qs.annotate(n=models.Count('pk'))
qs = qs.exclude(**lookup_kwargs)
qs = qs.filter(tag__in=self.all())
qs = qs.order_by('-n')
# TODO: This all feels like a bit of a hack.
items = {}
if len(lookup_keys) == 1:
# Can we do this without a second query by using a select_related()
# somehow?
f = _get_field(self.through, lookup_keys[0])
remote_field = _remote_field(f)
rel_model = _related_model(_remote_field(f))
objs = rel_model._default_manager.filter(**{
"%s__in" % remote_field.field_name: [r["content_object"] for r in qs]
})
for obj in objs:
items[(getattr(obj, remote_field.field_name),)] = obj
else:
preload = {}
for result in qs:
preload.setdefault(result['content_type'], set())
preload[result["content_type"]].add(result["object_id"])
for ct, obj_ids in preload.items():
ct = ContentType.objects.get_for_id(ct)
for obj in ct.model_class()._default_manager.filter(pk__in=obj_ids):
items[(ct.pk, obj.pk)] = obj
results = []
for result in qs:
obj = items[
tuple(result[k] for k in lookup_keys)
]
obj.similar_tags = result["n"]
results.append(obj)
return results
# _TaggableManager needs to be hashable but BaseManagers in Django 1.8+ overrides
# the __eq__ method which makes the default __hash__ method disappear.
# This checks if the __hash__ attribute is None, and if so, it reinstates the original method.
if models.Manager.__hash__ is None:
__hash__ = object.__hash__
class TaggableManager(RelatedField, Field):
# Field flags
many_to_many = True
many_to_one = False
one_to_many = False
one_to_one = False
_related_name_counter = 0
def __init__(self, verbose_name=_("Tags"),
help_text=_("A comma-separated list of tags."),
through=None, blank=False, related_name=None, to=None,
manager=_TaggableManager):
self.through = through or TaggedItem
self.swappable = False
self.manager = manager
rel = TaggableRel(self, related_name, self.through, to=to)
Field.__init__(
self,
verbose_name=verbose_name,
help_text=help_text,
blank=blank,
null=True,
serialize=False,
rel=rel,
)
# NOTE: `to` is ignored, only used via `deconstruct`.
def __get__(self, instance, model):
if instance is not None and instance.pk is None:
raise ValueError("%s objects need to have a primary key value "
"before you can access their tags." % model.__name__)
manager = self.manager(
through=self.through,
model=model,
instance=instance,
prefetch_cache_name=self.name
)
return manager
def deconstruct(self):
"""
Deconstruct the object, used with migrations.
"""
name, path, args, kwargs = super(TaggableManager, self).deconstruct()
# Remove forced kwargs.
for kwarg in ('serialize', 'null'):
del kwargs[kwarg]
# Add arguments related to relations.
# Ref: https://github.com/alex/django-taggit/issues/206#issuecomment-37578676
rel = _remote_field(self)
if isinstance(rel.through, six.string_types):
kwargs['through'] = rel.through
elif not rel.through._meta.auto_created:
kwargs['through'] = "%s.%s" % (rel.through._meta.app_label, rel.through._meta.object_name)
related_model = _related_model(rel)
if isinstance(related_model, six.string_types):
kwargs['to'] = related_model
else:
kwargs['to'] = '%s.%s' % (related_model._meta.app_label, related_model._meta.object_name)
return name, path, args, kwargs
def contribute_to_class(self, cls, name):
if VERSION < (1, 7):
self.name = self.column = self.attname = name
else:
self.set_attributes_from_name(name)
self.model = cls
self.opts = cls._meta
cls._meta.add_field(self)
setattr(cls, name, self)
if not cls._meta.abstract:
# rel.to renamed to remote_field.model in Django 1.9
if VERSION >= (1, 9):
if isinstance(self.remote_field.model, six.string_types):
def resolve_related_class(cls, model, field):
field.remote_field.model = model
lazy_related_operation(
resolve_related_class, cls, self.remote_field.model, field=self
)
else:
if isinstance(self.rel.to, six.string_types):
def resolve_related_class(field, model, cls):
field.rel.to = model
add_lazy_relation(cls, self, self.rel.to, resolve_related_class)
if isinstance(self.through, six.string_types):
if VERSION >= (1, 9):
def resolve_related_class(cls, model, field):
self.through = model
self.remote_field.through = model
self.post_through_setup(cls)
lazy_related_operation(
resolve_related_class, cls, self.through, field=self
)
else:
def resolve_related_class(field, model, cls):
self.through = model
_remote_field(self).through = model
self.post_through_setup(cls)
add_lazy_relation(
cls, self, self.through, resolve_related_class
)
else:
self.post_through_setup(cls)
def get_internal_type(self):
return 'ManyToManyField'
def __lt__(self, other):
"""
Required contribute_to_class as Django uses bisect
for ordered class contribution and bisect requires
a orderable type in py3.
"""
return False
def post_through_setup(self, cls):
if RelatedObject is not None: # Django < 1.8
self.related = RelatedObject(cls, self.model, self)
self.use_gfk = (
self.through is None or issubclass(self.through, CommonGenericTaggedItemBase)
)
# rel.to renamed to remote_field.model in Django 1.9
if VERSION >= (1, 9):
if not self.remote_field.model:
self.remote_field.model = self.through._meta.get_field("tag").remote_field.model
else:
if not self.rel.to:
self.rel.to = self.through._meta.get_field("tag").rel.to
if RelatedObject is not None: # Django < 1.8
self.related = RelatedObject(self.through, cls, self)
if self.use_gfk:
tagged_items = GenericRelation(self.through)
tagged_items.contribute_to_class(cls, 'tagged_items')
for rel in cls._meta.local_many_to_many:
if rel == self or not isinstance(rel, TaggableManager):
continue
if rel.through == self.through:
raise ValueError('You can\'t have two TaggableManagers with the'
' same through model.')
def save_form_data(self, instance, value):
getattr(instance, self.name).set(*value)
def formfield(self, form_class=TagField, **kwargs):
defaults = {
"label": capfirst(self.verbose_name),
"help_text": self.help_text,
"required": not self.blank
}
defaults.update(kwargs)
return form_class(**defaults)
def value_from_object(self, instance):
if instance.pk:
return self.through.objects.filter(**self.through.lookup_kwargs(instance))
return self.through.objects.none()
def related_query_name(self):
return _model_name(self.model)
def m2m_reverse_name(self):
return _get_field(self.through, 'tag').column
def m2m_reverse_field_name(self):
return _get_field(self.through, 'tag').name
def m2m_target_field_name(self):
return self.model._meta.pk.name
def m2m_reverse_target_field_name(self):
# rel.to renamed to remote_field.model in Django 1.9
if VERSION >= (1, 9):
return self.remote_field.model._meta.pk.name
else:
return self.rel.to._meta.pk.name
def m2m_column_name(self):
if self.use_gfk:
return self.through._meta.virtual_fields[0].fk_field
return self.through._meta.get_field('content_object').column
def db_type(self, connection=None):
return None
def m2m_db_table(self):
return self.through._meta.db_table
def bulk_related_objects(self, new_objs, using):
return []
def extra_filters(self, pieces, pos, negate):
if negate or not self.use_gfk:
return []
prefix = "__".join(["tagged_items"] + pieces[:pos - 2])
get = ContentType.objects.get_for_model
cts = [get(obj) for obj in _get_subclasses(self.model)]
if len(cts) == 1:
return [("%s__content_type" % prefix, cts[0])]
return [("%s__content_type__in" % prefix, cts)]
def get_extra_join_sql(self, connection, qn, lhs_alias, rhs_alias):
model_name = _model_name(self.through)
if rhs_alias == '%s_%s' % (self.through._meta.app_label, model_name):
alias_to_join = rhs_alias
else:
alias_to_join = lhs_alias
extra_col = _get_field(self.through, 'content_type').column
content_type_ids = [ContentType.objects.get_for_model(subclass).pk for
subclass in _get_subclasses(self.model)]
if len(content_type_ids) == 1:
content_type_id = content_type_ids[0]
extra_where = " AND %s.%s = %%s" % (qn(alias_to_join),
qn(extra_col))
params = [content_type_id]
else:
extra_where = " AND %s.%s IN (%s)" % (qn(alias_to_join),
qn(extra_col),
','.join(['%s'] *
len(content_type_ids)))
params = content_type_ids
return extra_where, params
# This and all the methods till the end of class are only used in django >= 1.6
def _get_mm_case_path_info(self, direct=False):
pathinfos = []
linkfield1 = _get_field(self.through, 'content_object')
linkfield2 = _get_field(self.through, self.m2m_reverse_field_name())
if direct:
join1infos = linkfield1.get_reverse_path_info()
join2infos = linkfield2.get_path_info()
else:
join1infos = linkfield2.get_reverse_path_info()
join2infos = linkfield1.get_path_info()
pathinfos.extend(join1infos)
pathinfos.extend(join2infos)
return pathinfos
def _get_gfk_case_path_info(self, direct=False):
pathinfos = []
from_field = self.model._meta.pk
opts = self.through._meta
linkfield = _get_field(self.through, self.m2m_reverse_field_name())
if direct:
join1infos = [PathInfo(self.model._meta, opts, [from_field], _remote_field(self), True, False)]
join2infos = linkfield.get_path_info()
else:
join1infos = linkfield.get_reverse_path_info()
join2infos = [PathInfo(opts, self.model._meta, [from_field], self, True, False)]
pathinfos.extend(join1infos)
pathinfos.extend(join2infos)
return pathinfos
def get_path_info(self):
if self.use_gfk:
return self._get_gfk_case_path_info(direct=True)
else:
return self._get_mm_case_path_info(direct=True)
def get_reverse_path_info(self):
if self.use_gfk:
return self._get_gfk_case_path_info(direct=False)
else:
return self._get_mm_case_path_info(direct=False)
def get_joining_columns(self, reverse_join=False):
if reverse_join:
return ((self.model._meta.pk.column, "object_id"),)
else:
return (("object_id", self.model._meta.pk.column),)
def get_extra_restriction(self, where_class, alias, related_alias):
extra_col = _get_field(self.through, 'content_type').column
content_type_ids = [ContentType.objects.get_for_model(subclass).pk
for subclass in _get_subclasses(self.model)]
return ExtraJoinRestriction(related_alias, extra_col, content_type_ids)
def get_reverse_joining_columns(self):
return self.get_joining_columns(reverse_join=True)
#property
def related_fields(self):
return [(_get_field(self.through, 'object_id'), self.model._meta.pk)]
#property
def foreign_related_fields(self):
return [self.related_fields[0][1]]
...
taggit.models.py:
...
#python_2_unicode_compatible
class TagBase(models.Model):
name = models.CharField(verbose_name=_('Name'), unique=True, max_length=100)
slug = models.SlugField(verbose_name=_('Slug'), unique=True, max_length=100)
def __str__(self):
return self.name
class Meta:
abstract = True
def save(self, *args, **kwargs):
if not self.pk and not self.slug:
self.slug = self.slugify(self.name)
from django.db import router
using = kwargs.get("using") or router.db_for_write(
type(self), instance=self)
# Make sure we write to the same db for all attempted writes,
# with a multi-master setup, theoretically we could try to
# write and rollback on different DBs
kwargs["using"] = using
# Be oportunistic and try to save the tag, this should work for
# most cases ;)
try:
with atomic(using=using):
res = super(TagBase, self).save(*args, **kwargs)
return res
except IntegrityError:
pass
# Now try to find existing slugs with similar names
slugs = set(
self.__class__._default_manager
.filter(slug__startswith=self.slug)
.values_list('slug', flat=True)
)
i = 1
while True:
slug = self.slugify(self.name, i)
if slug not in slugs:
self.slug = slug
# We purposely ignore concurrecny issues here for now.
# (That is, till we found a nice solution...)
return super(TagBase, self).save(*args, **kwargs)
i += 1
else:
return super(TagBase, self).save(*args, **kwargs)
def slugify(self, tag, i=None):
slug = default_slugify(unidecode(tag))
if i is not None:
slug += "_%d" % i
return slug
class Tag(TagBase):
class Meta:
verbose_name = _("Tag")
verbose_name_plural = _("Tags")
app_label = 'taggit'
...
That's just the way HTML works; it converts any whitespace - including newlines - to spaces. If you don't want any spaces you will need to put everything on the same line.
{{ x.name }}{% if not forloop.last %}, {% endif %}
Maybe you could try:
{{ x.name.strip }}
I have a list comprehension in my view I use since I have to filter based on model calculated fields.
leaseterms = LeaseTerm.objects.filter( is_active = True )
tobe_payed_terms = [obj for obj in leaseterms if obj.current_balance < 0]
I use it to display all the fields in my report.
Currently I have to add a dashboard where I just want to display count of total units of this list comprehension.
What is most performance wise optimal way of doing so?
(I might have few cases like this in my dashboard)
MODEL - I use SQLlite on DEV and POSTGRES on PROD and TEST
class LeaseTerm(CommonInfo):
version = IntegerVersionField( )
start_period = models.ForeignKey(Period, related_name='start_period',on_delete=models.PROTECT)
end_period = models.ForeignKey(Period, related_name='end_period',on_delete=models.PROTECT)
lease = models.ForeignKey(Lease,on_delete=models.PROTECT)
increase = models.DecimalField(max_digits=7, decimal_places=2)
amount = models.DecimalField(max_digits=7, decimal_places=2)
is_renewed = models.BooleanField(default=False)
is_renewal_letter = models.BooleanField(default=False)
renewal_letter_date = models.DateField(null=True, blank=True)
_current_period = None
_total_current = None
_total_payment = None
_total_current_payment = None
_total_discount = None
_total_current_discount = None
_current_tobe_payed = None
_current_balance = None
_is_current_term = None
_tenant = None
def _get_total(self):
from payment.models import LeasePayment
from conditions.models import LeaseDiscount
total_payment_dict = LeasePayment.objects.filter(leaseterm_id=self.id, is_active = True ).aggregate(Sum('amount'))
if total_payment_dict ['amount__sum']:
total_payment = total_payment_dict['amount__sum']
else:
total_payment = 0
total_discount_dict = LeaseDiscount.objects.filter(leaseterm_id=self.id, is_active = True ).aggregate(Sum('amount'))
if total_discount_dict ['amount__sum']:
total_discount = total_discount_dict['amount__sum']
else:
total_discount = 0
current_date=datetime.datetime.now().date()
current_period_dict = Period.objects.filter(start_date__lte=current_date,end_date__gte=current_date, is_active = True ).aggregate(Max('order_value'))
if current_period_dict['order_value__max']:
current_period = current_period_dict['order_value__max']
else:
current_period = 0
tenant = LeaseTenant.objects.filter(lease=self.lease, is_financially_accountable=True ).last()
if (self.start_period.order_value <= current_period <= self.end_period.order_value) and (self.is_active == True):
is_current_term_dict = True
else:
is_current_term_dict = False
current_period = self.end_period.order_value
current_discount_dict = LeaseDiscount.objects.filter(leaseterm_id=self.id,
is_active = True, period_date__gte=self.start_period,
period_date__lte=current_period).aggregate(Sum('amount'))
if current_discount_dict ['amount__sum']:
current_discount = current_discount_dict['amount__sum']
else:
current_discount = 0
current_periods_number = current_period - self.start_period.order_value + 1
current_tobe_payed = current_periods_number * self.amount - current_discount
current_balance = total_payment - current_tobe_payed
self._current_period = current_period
self._total_payment = total_payment
self._total_discount = total_discount
self._current_tobe_payed = current_tobe_payed
self._current_balance = current_balance
self._is_current_term = is_current_term_dict
if tenant is not None:
self._tenant = tenant.tenant
else:
self._tenant = None
#property
def is_current_term(self):
if self._is_current_term is None:
self._get_total()
return self._is_current_term
#property
def tenant(self):
if self._tenant is None:
self._get_total()
return self._tenant
#property
def current_tobe_payed(self):
if self._current_tobe_payed is None:
self._get_total()
return self._current_tobe_payed
#property
def current_balance(self):
if self._current_balance is None:
self._get_total()
return self._current_balance
#property
def current_period(self):
if self._current_period is None:
self._get_total()
return self._current_period
#property
def total_payment(self):
if self._total_payment is None:
self._get_total()
return self._total_payment
#property
def total_discount(self):
if self._total_discount is None:
self._get_total()
return self._total_discount
def save(self, *args, **kwargs):
self.full_clean()
return super(LeaseTerm, self).save(*args, **kwargs)
def __unicode__(self):
return u' %i %s %s ' % (self.id, self.start_period, self.end_period)
#with_author
class Period(CommonInfo):
version = IntegerVersionField( )
order_value = models.PositiveSmallIntegerField()
start_date = models.DateField()
end_date = models.DateField()
name = models.CharField(max_length=30)
duration = models.PositiveSmallIntegerField(null=True, blank=True)
is_special = models.BooleanField(default=False)
is_marked = models.BooleanField(default=False)
_is_current = models.NullBooleanField( blank=True, null=True, default=None)
#not_terminated_active_objects = NotTerminatedActiveManager()
def __unicode__(self):
return u'%s %i %s ' % ("#", self.order_value, self.name)
class Lease(CommonInfo):
version = IntegerVersionField( )
unit = models.ForeignKey(Unit,on_delete=models.PROTECT)
is_terminated = models.BooleanField(default=False)
_total = None
_total_current = None
_total_payment = None
_total_current_payment = None
_total_discount = None
_total_current_discount = None
def _get_total(self):
from payment.models import LeasePayment
from conditions.models import LeaseDiscount
total_payment_dict = LeasePayment.objects.filter(lease_id=self.id, is_active = True ).aggregate(Sum('amount'))
if total_payment_dict ['amount__sum']:
total_payment = total_payment_dict['amount__sum']
else:
total_payment = 0
total_discount_dict = LeaseDiscount.objects.filter(leaseterm__lease_id=self.id, is_active = True ).aggregate(Sum('amount'))
if total_discount_dict ['amount__sum']:
total_discount = total_discount_dict['amount__sum']
else:
total_discount = 0
self._total_payment = total_payment
self._total_discount = total_discount
self._total = total_payment + total_discount
#property
def total_payment(self):
if self._total_payment is None:
self._get_total()
return self._total_payment
#property
def total_discount(self):
if self._total_discount is None:
self._get_total()
return self._total_discount
#property
def total(self):
if self._total is None:
self._get_total()
return self._total
def __unicode__(self):
return u'%s %i %s ' % ("lease#", self.id, self.unit)
def clean(self):
model = self.__class__
if self.unit and (self.is_active == True) and model.objects.filter(unit=self.unit, is_terminated = False , is_active = True).exclude(id=self.id).count() > 0:
raise ValidationError('Unit has active lease already, Terminate existing one prior to creation of new one or create a not active lease '.format(self.unit))
def save(self, *args, **kwargs):
self.full_clean()
return super(Lease, self).save(*args, **kwargs)
class CommonInfo(models.Model):
created = models.DateTimeField("creation date", auto_now_add=True)
modified = models.DateTimeField("modification date", auto_now=True)
description = models.TextField(null=True, blank=True)
is_active = models.BooleanField(default=True)
class Meta:
abstract = True
My solution so far:
leaseterms = LeaseTerm.objects.filter( is_active = True )
negative_balance_term = [obj.id for obj in leaseterms if obj.current_balance < 0]
count_negative_balance_term = LeaseTerm.objects.filter(id__in=negative_balance_term).count()
I'm upgrading things as the title says, and now doing a rebuild_index seems to do nothing.
The output is a simple:
$ ./manage.py rebuild_index --noinput
Removing all documents from your index because you said so.
All documents removed.
Indexing 17019 users
Indexing 76 gears
Indexing 186523 images
and all of my prepare_FOO functions are not run.
These are my settings:
HAYSTACK_DEFAULT_OPERATOR = 'AND'
HAYSTACK_SEARCH_RESULTS_PER_PAGE = 70
HAYSTACK_CONNECTIONS = {
'default': {
'engine': 'haystack.backends.solr_backend.SolrEngine',
'URL': 'http://127.0.0.1:8983/solr',
'EXCLUDED_INDEXES': [
'threaded_messages.search_indexes.Thread',
'threaded_messages.search_indexes.ThreadIndex',
],
},
}
And these are my indexes:
# Python
import string
import re
import datetime
# Django
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.db.models import Q
# Third party apps
from haystack.indexes import *
from hitcount.models import HitCount
from toggleproperties.models import ToggleProperty
# This app
from astrobin.models import Image
from astrobin.models import DeepSky_Acquisition
from astrobin.models import SolarSystem_Acquisition
from astrobin.models import UserProfile
from astrobin.models import Gear, CommercialGear, RetailedGear
from astrobin.utils import unique_items
# Other AstroBin apps
from nested_comments.models import NestedComment
def _get_integration(image):
deep_sky_acquisitions = DeepSky_Acquisition.objects.filter(image=image)
solar_system_acquisition = None
integration = 0
try:
solar_system_acquisition = SolarSystem_Acquisition.objects.get(image=image)
except:
pass
if deep_sky_acquisitions:
for a in deep_sky_acquisitions:
if a.duration and a.number:
integration += (a.duration * a.number)
elif solar_system_acquisition:
return 0
return integration
def _prepare_likes(obj):
return ToggleProperty.objects.toggleproperties_for_object("like", obj).count()
def _prepare_moon_phase(obj):
from moon import MoonPhase
deep_sky_acquisitions = DeepSky_Acquisition.objects.filter(image=obj)
moon_illuminated_list = []
if deep_sky_acquisitions:
for a in deep_sky_acquisitions:
if a.date is not None:
m = MoonPhase(a.date)
moon_illuminated_list.append(m.illuminated * 100.0)
if len(moon_illuminated_list) == 0:
# We must make an assumption between 0 and 100, or this won't
# show up in any searches.
return 0
return sum(moon_illuminated_list) / float(len(moon_illuminated_list))
def _prepare_first_acquisition_date(obj):
deep_sky_acquisitions = DeepSky_Acquisition.objects.filter(image=obj)
solar_system_acquisition = None
try:
solar_system_acquisition = SolarSystem_Acquisition.objects.get(image=obj)
except:
pass
date = None
if deep_sky_acquisitions:
date = deep_sky_acquisitions[0].date
for a in deep_sky_acquisitions:
if a.date is not None and date is not None:
if a.date < date:
date = a.date
elif solar_system_acquisition:
date = solar_system_acquisition.date
return date
def _prepare_last_acquisition_date(obj):
deep_sky_acquisitions = DeepSky_Acquisition.objects.filter(image=obj)
solar_system_acquisition = None
try:
solar_system_acquisition = SolarSystem_Acquisition.objects.get(image=obj)
except:
pass
date = None
if deep_sky_acquisitions:
date = deep_sky_acquisitions[0].date
for a in deep_sky_acquisitions:
if a.date is not None and date is not None:
if a.date > date:
date = a.date
elif solar_system_acquisition:
date = solar_system_acquisition.date
return date if date else datetime.datetime.min
def _prepare_views(obj, content_type):
views = 0
try:
views = HitCount.objects.get(object_pk = obj.pk, content_type__name = content_type).hits
except:
pass
return views
def _prepare_min_aperture(obj):
d = 0
for telescope in obj.imaging_telescopes.all():
if telescope.aperture is not None and (d == 0 or telescope.aperture < d):
d = int(telescope.aperture)
return d
def _prepare_max_aperture(obj):
import sys
d = sys.maxint
for telescope in obj.imaging_telescopes.all():
if telescope.aperture is not None and (d == sys.maxint or telescope.aperture > d):
d = int(telescope.aperture)
return d
def _prepare_min_pixel_size(obj):
s = 0
for camera in obj.imaging_cameras.all():
if camera.pixel_size is not None and (s == 0 or camera.pixel_size < s):
s = int(camera.pixel_size)
return s
def _prepare_max_pixel_size(obj):
import sys
s = sys.maxint
for camera in obj.imaging_cameras.all():
if camera.pixel_size is not None and (s == sys.maxint or camera.pixel_size > s):
s = int(camera.pixel_size)
return s
def _prepare_telescope_types(obj):
return [x.type for x in obj.imaging_telescopes.all()]
def _prepare_camera_types(obj):
return [x.type for x in obj.imaging_cameras.all()]
def _prepare_comments(obj):
ct = ContentType.objects.get(app_label = 'astrobin', model = 'image')
return NestedComment.objects.filter(
content_type = ct,
object_id = obj.id,
deleted = False).count()
class GearIndex(SearchIndex, Indexable):
model_weight = IntegerField()
text = CharField(document=True, use_template=True)
images = IntegerField()
# Total likes of all images taken with this item.
likes = IntegerField()
# Total integration of images taken with this item.
integration = FloatField()
# Total views on images taken with this item.
views = IntegerField()
# Number of bookmarks on images taken with this item.
bookmarks = IntegerField()
# Number of comments on images taken with this item.
comments = IntegerField()
producers = MultiValueField()
retailers = MultiValueField()
def index_queryset(self, using = None):
return self.get_model().objects\
.exclude(commercial = None)\
.filter(commercial__producer__groups__name = 'Paying')
def get_model(self):
return Gear
def get_images(self, obj):
filters = (\
Q(imaging_telescopes = obj) |\
Q(guiding_telescopes = obj) |\
Q(mounts = obj) |\
Q(imaging_cameras = obj) |\
Q(guiding_cameras = obj) |\
Q(focal_reducers = obj) |\
Q(software = obj) |\
Q(filters = obj) |\
Q(accessories = obj)\
)
return Image.objects.filter(filters).distinct()
def prepare_model_weight(self, obj):
# Printing here just because it's the first "prepare" function.
print "%s: %d" % (obj.__class__.__name__, obj.pk)
return 100;
def prepare_images(self, obj):
return len(self.get_images(obj))
def prepare_likes(self, obj):
likes = 0
for i in self.get_images(obj):
likes += ToggleProperty.objects.toggleproperties_for_object("like", i).count()
return likes
def prepare_integration(self, obj):
integration = 0
for i in self.get_images(obj):
integration += _get_integration(i)
return integration / 3600.0
def prepare_views(self, obj):
views = 0
for i in self.get_images(obj):
views += _prepare_views(i, 'image')
return views
def prepare_bookmarks(self, obj):
bookmarks = 0
for i in self.get_images(obj):
bookmarks += ToggleProperty.objects.toggleproperties_for_object("bookmark", i).count()
return bookmarks
def prepare_comments(self, obj):
comments = 0
for i in self.get_images(obj):
comments += _prepare_comments(i)
return comments
def prepare_producers(self, obj):
producers = CommercialGear.objects\
.filter(base_gear = obj)\
.exclude(Q(producer__userprofile__company_name = None) | Q(producer__userprofile__company_name = ""))
return ["%s" % x.producer.userprofile.company_name for x in producers]
def prepare_retailers(self, obj):
retailers = RetailedGear.objects\
.filter(gear = obj)\
.exclude(Q(retailer__userprofile__company_name = None) | Q(retailer__userprofile__company_name = ""))
return ["%s" % x.retailer.userprofile.company_name for x in retailers]
class UserIndex(SearchIndex, Indexable):
model_weight = IntegerField()
text = CharField(document=True, use_template=True)
images = IntegerField()
avg_integration = FloatField()
# Total likes of all user's images.
likes = IntegerField()
# Total likes of all user's images.
average_likes = FloatField()
# Normalized likes (best images only)
normalized_likes = FloatField()
# Number of followers
followers = IntegerField()
# Total user ingegration.
integration = FloatField()
# Average moon phase under which this user has operated.
moon_phase = FloatField()
# First and last acquisition dates, including all images of course.
first_acquisition_date = DateTimeField()
last_acquisition_date = DateTimeField()
# Total views from all images.
views = IntegerField()
# Min and max aperture of all telescopes used in this user's images.
min_aperture = IntegerField()
max_aperture = IntegerField()
# Min and max pixel size of all cameras used in this user's images.
min_pixel_size = IntegerField()
max_pixel_size = IntegerField()
# Number of bookmarks on own images
bookmarks = IntegerField()
# Types of telescopes and cameras with which this user has imaged.
telescope_types = MultiValueField()
camera_types = MultiValueField()
comments = IntegerField()
comments_written = IntegerField()
username = CharField(model_attr = 'username')
def index_queryset(self, using = None):
return self.get_model().objects.all()
def get_model(self):
return User
def prepare_model_weight(self, obj):
# Printing here just because it's the first "prepare" function.
print "%s: %d" % (obj.__class__.__name__, obj.pk)
return 200;
def prepare_images(self, obj):
return Image.objects.filter(user = obj).count()
def prepare_avg_integration(self, obj):
integration = 0
images = 0
for i in Image.objects.filter(user = obj):
image_integration = _get_integration(i)
if image_integration:
images += 1
integration += image_integration
return (integration / 3600.0) / images if images else 0
def prepare_likes(self, obj):
likes = 0
for i in Image.objects.filter(user = obj):
likes += ToggleProperty.objects.toggleproperties_for_object("like", i).count()
return likes
def prepare_average_likes(self, obj):
likes = self.prepare_likes(obj)
images = self.prepare_images(obj)
return likes / float(images) if images > 0 else 0
def prepare_normalized_likes(self, obj):
def average(values):
if len(values):
return sum(values) / float(len(values))
return 0
def index(values):
import math
return average(values) * math.log(len(values)+1, 10)
avg = self.prepare_average_likes(obj)
norm = []
for i in Image.objects.filter(user = obj):
likes = i.likes()
if likes >= avg:
norm.append(likes)
if len(norm) == 0:
return 0
return index(norm)
def prepare_followers(self, obj):
return ToggleProperty.objects.filter(
property_type = "follow",
content_type = ContentType.objects.get_for_model(User),
object_id = obj.pk
).count()
def prepare_integration(self, obj):
integration = 0
for i in Image.objects.filter(user = obj):
integration += _get_integration(i)
return integration / 3600.0
def prepare_moon_phase(self, obj):
l = []
for i in Image.objects.filter(user = obj):
l.append(_prepare_moon_phase(i))
if len(l) == 0:
return 0
return reduce(lambda x, y: x + y, l) / len(l)
def prepare_first_acquisition_date(self, obj):
l = []
for i in Image.objects.filter(user = obj):
l.append(_prepare_first_acquisition_date(obj))
if len(l) == 0:
return None
return min(l)
def prepare_last_acquisition_date(self, obj):
l = []
for i in Image.objects.filter(user = obj):
l.append(_prepare_last_acquisition_date(obj))
if len(l) == 0:
return None
return max(l)
def prepare_views(self, obj):
views = 0
for i in Image.objects.filter(user = obj):
views += _prepare_views(i, 'image')
return views
def prepare_min_aperture(self, obj):
l = []
for i in Image.objects.filter(user = obj):
l.append(_prepare_min_aperture(i))
if len(l) == 0:
return 0
return min(l)
def prepare_max_aperture(self, obj):
l = []
for i in Image.objects.filter(user = obj):
l.append(_prepare_max_aperture(i))
if len(l) == 0:
return 0
return max(l)
def prepare_min_pixel_size(self, obj):
l = []
for i in Image.objects.filter(user = obj):
l.append(_prepare_min_pixel_size(i))
if len(l) == 0:
return 0
return min(l)
def prepare_max_pixel_size(self, obj):
l = []
for i in Image.objects.filter(user = obj):
l.append(_prepare_max_pixel_size(i))
if len(l) == 0:
return 0
return max(l)
def prepare_bookmarks(self, obj):
bookmarks = 0
for i in Image.objects.filter(user = obj):
bookmarks += ToggleProperty.objects.toggleproperties_for_object("bookmark", i).count()
return bookmarks
def prepare_telescope_types(self, obj):
l = []
for i in Image.objects.filter(user = obj):
l += _prepare_telescope_types(i)
return unique_items(l)
def prepare_camera_types(self, obj):
l = []
for i in Image.objects.filter(user = obj):
l += _prepare_camera_types(i)
return unique_items(l)
def prepare_comments(self, obj):
comments = 0
for i in Image.objects.filter(user = obj):
comments += _prepare_comments(i)
return comments
def prepare_comments_written(self, obj):
return NestedComment.objects.filter(author = obj, deleted = False).count()
class ImageIndex(SearchIndex, Indexable):
model_weight = IntegerField()
text = CharField(document=True, use_template=True)
uploaded = DateTimeField(model_attr='uploaded')
likes = IntegerField()
integration = FloatField()
moon_phase = FloatField()
first_acquisition_date = DateTimeField()
last_acquisition_date = DateTimeField()
views = IntegerField()
solar_system_main_subject = IntegerField()
is_deep_sky = BooleanField()
is_clusters = BooleanField()
is_nebulae = BooleanField()
is_galaxies = BooleanField()
is_solar_system = BooleanField()
is_sun = BooleanField()
is_moon = BooleanField()
is_planets = BooleanField()
is_comets = BooleanField()
license = IntegerField(model_attr = 'license')
min_aperture = IntegerField()
max_aperture = IntegerField()
min_pixel_size = IntegerField()
max_pixel_size = IntegerField()
bookmarks = IntegerField()
telescope_types = MultiValueField()
camera_types = MultiValueField()
comments = IntegerField()
is_commercial = BooleanField()
subject_type = IntegerField(model_attr = 'subject_type')
username = CharField(model_attr = 'user__username')
def index_queryset(self, using = None):
return self.get_model().objects.filter(moderator_decision = 1)
def get_model(self):
return Image
def prepare_model_weight(self, obj):
# Printing here just because it's the first "prepare" function.
print "%s: %d" % (obj.__class__.__name__, obj.pk)
return 300;
def prepare_likes(self, obj):
return _prepare_likes(obj)
def prepare_integration(self, obj):
return _get_integration(obj)
def prepare_moon_phase(self, obj):
return _prepare_moon_phase(obj)
def prepare_first_acquisition_date(self, obj):
return _prepare_first_acquisition_date(obj)
def prepare_last_acquisition_date(self, obj):
return _prepare_last_acquisition_date(obj)
def prepare_views(self, obj):
return _prepare_views(obj, 'image')
def prepare_solar_system_main_subject(self, obj):
return obj.solar_system_main_subject
def prepare_is_deep_sky(self, obj):
return DeepSky_Acquisition.objects.filter(image = obj).count() > 0
def prepare_is_solar_system(self, obj):
if obj.solar_system_main_subject:
return True
if SolarSystem_Acquisition.objects.filter(image = obj):
return True
return False
def prepare_is_sun(self, obj):
return obj.solar_system_main_subject == 0
def prepare_is_moon(self, obj):
return obj.solar_system_main_subject == 1
def prepare_is_planets(self, obj):
return obj.solar_system_main_subject in range(2, 8)
def prepare_is_comets(self, obj):
return obj.solar_system_main_subject == 10
def prepare_min_aperture(self, obj):
return _prepare_min_aperture(obj)
def prepare_max_aperture(self, obj):
return _prepare_max_aperture(obj)
def prepare_min_pixel_size(self, obj):
return _prepare_min_pixel_size(obj)
s = 0
for camera in obj.imaging_cameras.all():
if camera.pixel_size is not None and (s == 0 or camera.pixel_size < s):
s = int(camera.pixel_size)
return s
def prepare_max_pixel_size(self, obj):
return _prepare_max_pixel_size(obj)
import sys
s = sys.maxint
for camera in obj.imaging_cameras.all():
if camera.pixel_size is not None and (s == sys.maxint or camera.pixel_size > s):
s = int(camera.pixel_size)
return s
def prepare_bookmarks(self, obj):
return ToggleProperty.objects.toggleproperties_for_object("bookmark", obj).count()
def prepare_telescope_types(self, obj):
return _prepare_telescope_types(obj)
def prepare_camera_types(self, obj):
return _prepare_camera_types(obj)
def prepare_comments(self, obj):
return _prepare_comments(obj)
def prepare_is_commercial(self, obj):
commercial_gear = CommercialGear.objects.filter(image = obj)
return commercial_gear.count() > 0
Any idea what I might be missing? Thanks!
Got it. 'ENGINE' should be all capitals, in the settings.