What is the best way to make view counter function in my views.py ?
I did find F() expressions in Django documentation , but how to make it work or any better idea?
Thank you in advance
def watch_video(request, slug):
video = get_object_or_404(Video, slug=slug)
template = "single_video.html"
#if this function will run , + 1 in Video.views ?
return render(request,template,{"video":video})
my model:
class Video(models.Model):
video_id = models.CharField(max_length=150)
title = models.CharField(max_length=150)
slug = AutoSlugField(populate_from="title")
description = models.TextField(blank=True)
views = models.PositiveIntegerField(default=0)
likes = models.PositiveIntegerField(default=0)
category = models.ForeignKey("VideoCategory")
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
tags = models.ManyToManyField("Tag")
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("watch", kwargs={"slug" : self.slug})
Call the update() on the queryset which filters the single video:
from django.db.models import F
Video.objects.filter(pk=video.pk).update(views=F('views') + 1)
video.views += 1 # to show valid counter in the template
It's very simple make an increase function in model which increment views by 1
Then in views.py call that increase function everytime a user visits that model's page and save it!
Related
I am new to Django and have hit a wall with a certain part of my project and I hope someone can help.
I have two ListViews in my views.py file which I would like to work similar to published/draft posts (I'm actually using sanitised and unsanitised reports). Currently, every time I try to access the "Unsanitised" list view (unsanitised_list.html), it just directs me to the the sanitised list view (intelreport_list.html)
views.py:
class IntelReportListView(ListView):
model = IntelReport
context_object_name = 'all_logs'
def get_queryset(self):
return IntelReport.objects.filter(create_date__lte=timezone.now()).order_by('-create_date')
class UnsanitisedListView(LoginRequiredMixin, ListView):
login_url = '/login/'
redirect_field_name = 'intel_db/unsanitised_list.html'
model = IntelReport
def get_queryset(self):
return IntelReport.objects.filter(sanitised__isnull=True).order_by('-create_date')
models.py
class IntelReport(models.Model):
gpms_choices = (
***REDACTED***
)
gpms = models.CharField(max_length=20, blank=True, null=True, choices=gpms_choices)
officer = models.CharField(max_length=50)
create_date = models.DateTimeField(auto_now_add=True)
sanitised = models.BooleanField(default=False)
source_eval_choices = (
***REDACTED****
)
source_eval = models.CharField(max_length=50, blank=True, null=True, choices=source_eval_choices)
intel_eval_choices = (
***REDACTED***
)
intel_eval = models.CharField(max_length=100, blank=True, null=True, choices=intel_eval_choices)
report = models.TextField(max_length=5000, blank=True, null=True)
def sanitised_log(self):
self.sanitised = True
self.save()
def get_absolute_url(self):
return reverse('log_details', kwargs={'pk':self.pk})
def __str__(self):
return str(self.pk)
urls.py
from django.urls import path
from intel_db import views
urlpatterns = [
path('welcome/', views.AboutView.as_view(), name='about'),
path('logs/', views.IntelReportListView.as_view(), name='log_list'),
path('logs/<int:pk>/', views.IntelReportDetailView.as_view(), name='log_detail'),
path('logs/new_log/', views.IntelReportCreateView.as_view(), name='new_log'),
path('unsanitised/', views.UnsanitisedListView.as_view(), name='unsanitised'),
path('logs/<int:pk>/sanitise_log/', views.sanitsed_report, name='sanitised_report'),
]
and on my landing page (landing.html), this is the link I'm using to try and reach the unsanitised_list.html:
**<a href="{% url 'unsanitised' %}">**
I cannot figure out why it keeps redirecting me to intelreport_lists.html (the sanitised logs) rather than unsanitised_list.html (the unsanitised logs).
I hope I'm not just missing something really simple but I've been over it and tried to re-write it innumerable times and can't get it right.
I hope this is enough information and any help would be greatly appreciated.
Cheers
You just have to override template_name when you extend ListView. I mean update your IntelReportListView and UnsanitisedListViewlike this,
class IntelReportListView(ListView):
model = IntelReport
context_object_name = 'all_logs'
template_name = 'YOUR_APP_NAME/intelreport_list.html'
def get_queryset(self):
return IntelReport.objects.filter(create_date__lte=timezone.now()).order_by('-create_date')
class UnsanitisedListView(LoginRequiredMixin, ListView):
login_url = '/login/'
redirect_field_name = 'intel_db/unsanitised_list.html'
template_name = 'YOUR_APP_NAME/unsanitised_list.html'
model = IntelReport
def get_queryset(self):
return IntelReport.objects.filter(sanitised__isnull=True).order_by('-create_date')
If you are interested to find out why it was redirecting to intelreport_list.html rather than unsanitised_list.html, whenever you extend ListView it will look for MODEL_NAME_list.html by default, where MODEL_NAME is name of the model that you have used inside your list views (in lower case). Since you have used model = IntelReport inside UnsanitisedListView, it's redirecting to intelreport_lists.html
I would like to return the total number of items I have in a databse from the following simple model:
class EquipmentType(models.Model):
type = models.CharField(max_length=100, unique=True)
description = models.CharField(max_length=250, default='')
date_posted = models.DateTimeField(auto_now_add=True)
# auto_now = timezone.now
image =models.ImageField(default='default.jpeg', upload_to='equipment/equipment_type')
active =models.BooleanField(default=True)
Below the model I've defined the following function:
#property
def get_total_num(self):
total = 0
equipmentType = EquipmentType.objects.all()
for type in equipmentType:
total = total + 1
return total
which I call in the template with a simple for testing:
<h3>numero tot: {{get_total_num}}</h3>
The db has about 44 objects, thus I would expect the function, once called, to return that number. Unfortunately it returns nothing (just the string 'numero tot').
This is the class based view I'm using:
class EquipmentType_ListView(LoginRequiredMixin, ListView):
model = EquipmentType
template_name = 'equipment/equipmentType_list.html' # default = <app>/<model>_<viewtype>.html
context_object_name = 'obj_list'
def get_queryset(self):
return EquipmentType.objects.filter(active = True).order_by('type')
Any suggestion on what is actually missing?
Thank you very much.
Carlo
There is no necesaary to write the extra function in the model.
You can simply use the count or length in your templates like this.
<h3>numero tot: {{obj_list.count}}
</h3>
OR {{obj_list|length}}
If you want to do it from the view
total_objs_count = EquipmentType.objects.count()
I want use category_slug or id_slug for detailview as productdetailview
and show all of product that category there but i don't know how do that
i used this views but i get errors 404. why is different between productdetailview and categorydetailview? could plz help me to solve this problem?
models.py
class Category(models.Model):
name = models.CharField(max_length=120,unique=True)
slug = models.SlugField(unique=True)
def __str__(self):
return self.name
class Brand(models.Model):
name = models.CharField(max_length=120,unique=True)
class Product(models.Model):
category = models.ManyToManyField(Category,blank=True)
brand = models.ForeignKey(Brand,on_delete=models.CASCADE)
car = models.ForeignKey(Car,on_delete=models.CASCADE)
title = models.CharField(max_length=120,unique=True)
slug = models.SlugField(unique=True)
description = models.TextField(max_length=10000)
price = models.DecimalField(max_digits=10,decimal_places=2)
stock = models.PositiveIntegerField()
active = models.BooleanField(default=True)
timestamp = models.DateTimeField(auto_now_add=True,auto_now=False)
updated = models.DateTimeField(auto_now=True,auto_now_add=False)
defalut = models.ForeignKey(Category,related_name="defalut_category",blank=True,null=True,on_delete=models.CASCADE)
class Meta:
ordering = ['-timestamp']
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('products:product_detail',kwargs={"slug":self.slug})
views.py
def ProductDetail(request,slug):
product = get_object_or_404(Product,slug=slug,active=True)
context = {
"product":product
}
template_name = "product_detail.html"
return render (request,template_name,context)
def CategoryDetail(request,category_slug):
category = get_object_or_404(Category,slug = category_slug)
product = Product.objects.filter(category=category)
context = {
'category':category,
'product': product
}
template_name ="category_detail.html"
return render(request,template_name,context)
urls.py
app_name ='category'
urlpatterns = [
path('category-list/',views.CategoryList,name="category_list" ),
re_path(r'^(?P<category_slug>[-\w]+)/$', views.CategoryDetail, name='category_detail'),
My error
Page not found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/category/elctroinc/
Raised by: products.views.CategoryDetail
No Category matches the given query.
You're seeing this error because you have DEBUG = True in your Django settings file. Change that to False, and Django will display a standard 404 page.
Problem was in category_slug as two friends said that #Manjo Jadhav ,#JPG
i used id instead of category_slug and it's working .
tnx for help friends.
I am trying to code with a Django ecommerce plugin called django-cart. I want to find the sum of the prices of all items in the cart. The cart model has the following code:
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
class Cart(models.Model):
creation_date = models.DateTimeField(verbose_name=_('creation date'))
checked_out = models.BooleanField(default=False, verbose_name=_('checked out'))
def _valor_carrinho(self):
return self.objects.all().aggregate(Sum('total_price'))
valor_carrinho = property(_valor_carrinho)
class Meta:
verbose_name = _('cart')
verbose_name_plural = _('carts')
ordering = ('-creation_date',)
def __unicode__(self):
return unicode(self.creation_date)
class ItemManager(models.Manager):
def get(self, *args, **kwargs):
if 'product' in kwargs:
kwargs['content_type'] = ContentType.objects.get_for_model(type(kwargs['product']))
kwargs['object_id'] = kwargs['product'].pk
del(kwargs['product'])
return super(ItemManager, self).get(*args, **kwargs)
class Item(models.Model):
cart = models.ForeignKey(Cart, verbose_name=_('cart'))
quantity = models.PositiveIntegerField(verbose_name=_('quantity'))
unit_price = models.DecimalField(max_digits=18, decimal_places=2, verbose_name=_('unit price'))
# product as generic relation
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
link_item = models.CharField(max_length=100)
tipo_item = models.CharField(max_length=50)
cor_item = models.CharField(max_length=50, blank=True)
modelo_item = models.CharField(max_length=50, blank=True)
tamanho_item = models.CharField(max_length=50, blank=True)
objects = ItemManager()
class Meta:
verbose_name = _('item')
verbose_name_plural = _('items')
ordering = ('cart',)
def __unicode__(self):
return u'%d units of %s' % (self.quantity, self.product.__class__.__name__)
def total_price(self):
return self.quantity * self.unit_price
total_price = property(total_price)
# product
def get_product(self):
return self.content_type.get_object_for_this_type(id=self.object_id)
def set_product(self, product):
self.content_type = ContentType.objects.get_for_model(type(product))
self.object_id = product.pk
product = property(get_product, set_product)
And I am trying to use valor_carrinho (sorry for the mixup between Portuguese and English in the code) as the sum of the total_price field of all the items in the cart. But when I use it in a template, it returns nothing. What am I doing wrong?
I think it should be:
def _valor_carrinho(self):
return self.item_set.all().aggregate(Sum('total_price'))
to get all items for a specific Cart instance, I am NOT sure total_price works here, but to access the items of the cart it is item_set, hopefully it is enough to get you started!
The concept that that is using is reverse foreign key lookup, which is explained here
I am not sure that this does work as I think aggregate goes to the database layer and total_price has been defined as a property. I am going to denormalise and make the equivalent of total_price a field so that I can use the aggregate function.
Try the following code, it works for me so it might work for you:
view.py
def get_cart(request):
cart = Cart(request)
cart.summary()
return render_to_response('cart.html', dict(cart=Cart(request)),{'cart':cart})
cart.html
<h3> Total : {{ cart.summary }}</h3>
I am using the get_absolute_url method to get the url for a dynamic query, however when the link is displayed, it only shows the first parameter and not the second in the get_absolute_url method. It only does this when I use the ForeignKey of the model as the first parameter. Below is the code.
class Topic(models.Model):
topic_id = models.AutoField(primary_key=True)
forum_id = models.ForeignKey(Forum)
topic_title = models.CharField(max_length=400)
topic_date_time = models.DateTimeField(auto_now_add=True)
topic_user_id = models.IntegerField()
topic_views = models.IntegerField(default=0)
topic_replies = models.IntegerField(default=0)
topic_is_locked = models.BooleanField(default=False)
topic_is_sticky = models.BooleanField(default=False)
def __unicode__(self):
return '%s' % _(u'self.topic_title')
def get_absolute_url(self):
**return '/forums/%i/%i/' % (self.forum_id, self.topic_id)**
How can I fix this? Thanks!
def get_absolute_url(self):
return '/forums/%s/%s/' % (str(self.forum_id.pk), self.topic_id)
edit: jerzyk comment mentions these other points:
using #permalink with get_absolute_url and reversing the url using the view and arguments so you don't have to hardcode the urls.
using _id instead of .pk
def get_absolute_url(self):
return '/forums/%s/%s/' % (self.forum_id_id, self.topic_id)