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>
Related
I'm trying to make this app where I can select the items I want to buy. I want to add two cakes to the cart, for example, but so far I can't select more than one. How do I do that? The field I need to change is 'food' since this one has options like 'cake', 'pastries', etc. I want the user to be able to add as many of each item as they want. I tried with many=True but something is not working out.
This is the serializer so far:
class OrderSerializer(serializers.ModelSerializer):
class Meta:
model = Order
fields = '__all__'
class FoodSerializer(serializers.ModelSerializer):
class Meta:
model = Food
fields = '__all__'
This is the model:
class Food(models.Model):
name = models.CharField(max_length=100, unique=True)
def __str__(self):
return self.name
class Order(models.Model):
food = models.ManyToManyField('Food', related_name='order', blank=True)
def __str__(self):
return self.food
you will need to add a model where you can add the quantity of an item that you can order:
class OrderFood(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
ordered = models.BooleanField(default=False)
item = models.ForeignKey(Item, on_delete=models.CASCADE)
quantity = models.IntegerField(default=1)
def __str__(self):
return f"{self.quantity} of {self.item.title}"
and then you can add or remove an item (or type of food) to/from the order in the views:
class AddToCartView(APIView):
def post(self, request, *args, **kwargs):
item_id = request.data.get('id', None)
if item_id is None:
return Response({"message": "Invalid request"}, status=HTTP_400_BAD_REQUEST)
item = get_object_or_404(Item, id=item_id)
order_item = OrderFood.objects.filter(item=item,user=request.user)
if order_item.exists():
order_item = order_item.first()
order_item.quantity += 1
order_item.save()
else:
order_item = OrderFood.objects.create(item=item,user=request.user)
order_item.save()
not 100% sure about the code ,you'll need to verify it, hope that could help
In my Django app, when I add the host_count field to my serializer to get the number of hosts for each domain, the performance of the API response suffers dramatically.
Without host_count: 300ms
With host_count: 15s
I tried adding 'host_set' to the prefetch_related method but it did not help.
Would an annotation using Count help me here? How can I optimize the fetching of this value?
serializers.py
class DomainSerializer(serializers.Serializer):
name = serializers.CharField(read_only=True)
org_name = serializers.CharField(source='org.name', read_only=True)
created = serializers.DateTimeField(read_only=True)
last_host_search = serializers.DateTimeField(read_only=True)
host_count = serializers.SerializerMethodField()
def get_host_count(self, obj):
return Host.objects.filter(domain=obj).count()
views.py
class DomainList(generics.ListAPIView):
def get(self, request, format=None):
domains = Domain.objects.prefetch_related('org').all()
serializer = DomainSerializer(domains, many=True)
return Response(serializer.data)
models.py
class Domain(models.Model):
created = models.DateTimeField(auto_now_add=True)
last_host_search = models.DateTimeField(auto_now=True)
name = models.CharField(unique=True, max_length=settings.MAX_CHAR_COUNT, blank=False, null=False)
org = models.ForeignKey(Org, on_delete=models.CASCADE, blank=True, null=True)
You can work with .annotate(…) [Django-doc] to count the related objects in the same query:
from django.db.models import Count
class DomainList(generics.ListAPIView):
def get(self, request, format=None):
domains = Domain.objects.prefetch_related('org').annotate(
host_count=Count('host')
)
serializer = DomainSerializer(domains, many=True)
return Response(serializer.data)
In the serializer, you then simply retrieve the corresponding attribute:
class DomainSerializer(serializers.Serializer):
name = serializers.CharField(read_only=True)
org_name = serializers.CharField(source='org.name', read_only=True)
created = serializers.DateTimeField(read_only=True)
last_host_search = serializers.DateTimeField(read_only=True)
host_count = serializers.IntegerField(read_only=True)
This will make a query that looks like:
SELECT domain.*, org.*, COUNT(host.id)
FROM domain
LEFT OUTER JOIN org ON domain.org_id = org.id
LEFT OUTER JOIN host ON host.domain_id = domain.id
GROUP BY domain.id, org.id
I created a model object.
This object has several boolean fields.
# models.py
class TeamCharacteristic(models.Model):
team = models.ForeignKey('Teams',on_delete=models.CASCADE)
power1 = models.BooleanField(null=True, blank=True)
power2 = models.BooleanField(null=True, blank=True)
power3 = models.BooleanField(null=True, blank=True)
power4 = models.BooleanField(null=True, blank=True)
power5 = models.BooleanField(null=True, blank=True)
class Meta:
verbose_name = 'Team style'
verbose_name_plural = 'Teams style'
def __str__(self):
return "{} 's style".format(
self.team,
)
Some of them are right and others are wrong.
I want to show only the fields that have the correct value in the template.
How can I do this in a shorter way instead of checking each field individually?
# views.py
from django.shortcuts import render, get_object_or_404
from .models import Matches
from denemee.apps.home.models import TeamCharacteristic
def matches_details(request, page_id=None, team=None, **kwargs):
m_detail = get_object_or_404(Matches, id=page_id)
home_team_chr = get_object_or_404(TeamCharacteristic, team=m_detail.h_team)
away_team_chr = get_object_or_404(TeamCharacteristic, team=m_detail.a_team)
payload = {
'm_detail': m_detail,
'home_team_chr': home_team_chr,
'away_team_chr': away_team_chr
}
return render(request, 'match_detail.html', payload)
You can send your home_team_chr and home_team_chras serialized objects and then iterate over the fields and check for the True values in booleans.
Check out this answer for more details.
I have working models, forms, views and urls for a django CRUD app managing customer functions for a business. I just cant seem to figure out how to write a view to allow a user to add comments, or other data related to the customer and stored in other models using a single view and template.
So for example; for customer a, all the comments for customer a with the option to add, amend etc.. and the same for the other related models.
I understand how to do it for one I will be able to make quick progress. (old school programmer here)
Here is what I am working with - keeping it simple.
MODELS
class Emergency(models.Model):
# Fields
name = CharField(null = False, blank = False, max_length=60)
address = TextField(blank=True, null=True, help_text='Street and town', verbose_name='Address')
telephone = CharField(blank=False, null=False, unique= True, max_length=20)
relationship = CharField(choices=(('P', 'Parent'),('S', 'Son'),('D', 'Daughter'),('R', 'Relative'),('L', 'Partner')),max_length = 1,default='R')
class Meta:
ordering = ('-pk',)
def __unicode__(self):
return u'%s' % self.pk
def get_absolute_url(self):
return reverse('conform_emergency_detail', args=(self.pk,))
def get_update_url(self):
return reverse('conform_emergency_update', args=(self.pk,))
class Client(models.Model):
# Fields
surname = CharField(null = False, blank = False, max_length=30)
name = CharField(null = False, blank = False, max_length=60)
# Relationship Fields
emergencycontact = models.ForeignKey(Emergency, on_delete=models.CASCADE, name = 'Emergency Contact')
class Meta:
ordering = ('-pk',)
def __unicode__(self):
return u'%s' % self.pk
def get_absolute_url(self):
return reverse('conform_client_detail', args=(self.pk,))
def get_update_url(self):
return reverse('conform_client_update', args=(self.pk,))
class Clientnotes(models.Model):
# Fields
slug = AutoSlugField(populate_from='name', blank=True)
created = DateTimeField(auto_now_add=True, editable=False)
last_updated = DateTimeField(auto_now=True, editable=False)
note = CharField(blank=False, null=False, max_length= 300 )
# Relationship Fields
modified_by = models.ForeignKey(User, related_name='clientnotes_modified_by', on_delete=models.CASCADE, name= 'Changed by')
clientnotes = models.ManyToManyField(Client, name = 'Clients notes')
class Meta:
ordering = ('-created',)
def __unicode__(self):
return u'%s' % self.slug
def get_absolute_url(self):
return reverse('conform_clientnotes_detail', args=(self.slug,))
def get_update_url(self):
return reverse('conform_clientnotes_update', args=(self.slug,))
FORMS
class ClientForm(forms.ModelForm):
class Meta:
model = Client
fields = ['surname', 'name']
class ClientnotesForm(forms.ModelForm):
class Meta:
model = Clientnotes
readonly_fields = ['slug', 'modified_by']
fields = ['note']
VIEWS
class ClientListView(ListView):
model = Client
class ClientCreateView(CreateView):
model = Client
form_class = ClientForm
class ClientDetailView(DetailView):
model = Client
class ClientUpdateView(UpdateView):
model = Client
form_class = ClientForm
TEMPLATE NAMES
client_detail.html
client_form.html
client_list.html
I have simple views, forms and templates to list, view detail and add and it all works well - with the exception of related models because i am not able to add both models at the same time. I need a simple clear simpletons guide with what i have provided so it clicks into place.
It's a sort of cms type application
I have an article model and some specializations in models.py
class Article(models.Model):
foo = models.CharField(max_length=50)
bar = models.CharField(max_length=100,blank=True)
DISPLAY_CHOICES = (
('N', 'None'),
('C','Carousel'),
('M','Marketing'),
('F','Featurette')
)
display = models.CharField(max_length=1, choices = DISPLAY_CHOICES)
def __unicode__(self):
return self.title
class Artist(Article):
website = models.URLField(max_length=200,blank=True)
class Venue(Article):
location = models.CharField(max_length=150)
map_link = models.URLField(max_length=200,blank=True)
class Event(Article):
time = models.DateTimeField()
venue = models.ForeignKey(Venue)
performers = models.ManyToManyField(Artist)
I want to render these in different ways depending on the value of article.display but when I call
articles.objects.all()
I still need the extra attributes form the subclasses so I wrote
#views.py
def castToSubClass(article):
try:
return Artist.objects.get(article_ptr_id = article.id)
except:
try:
return Event.objects.get(article_ptr_id = article.id)
except:
try:
return Venue.objects.get(article_ptr_id = article.id)
except:
return article
def index(request):
carousel = [castToSubClass(article) for article in Article.objects.filter(display='C']
marketing = [castToSubClass(article) for article in Article.objects.filter(display='M'[:3]]
featurettes = [castToSubClass(article) for article in Article.objects.filter(display='F']
return render_to_response('frontpage.html',
{
'carousel': carousel,
'marketing':marketing,
'featurettes': featurettes
})
to turn them all in the appropriate subclass object, this apart from seeming clunky seems to mean I'm hitting the database twice for every (or nearly every) item in the queryset.
Is there a way to do this in the initial calls to the manager instead?
Thanks.
Use one model to store everything, and add a field to distinguish the article type, so that you can render different look for every type combine with display in the template(Like tumblr do).
class Article(models.Model):
foo = models.CharField(max_length=50)
bar = models.CharField(max_length=100,blank=True)
DISPLAY_CHOICES = (
('N', 'None'),
('C','Carousel'),
('M','Marketing'),
('F','Featurette')
)
display = models.CharField(max_length=1, choices = DISPLAY_CHOICES)
ARTICLE_TYPE_CHOICES = (
('artist', 'Artist'),
('venue', 'Venue'),
('event', 'Event'),
)
type = models.CharField(max_length=32, choices = ARTICLE_TYPE_CHOICES)
website = models.URLField(max_length=200,blank=True, null=True)
location = models.CharField(max_length=150, blank=True, null=True)
map_link = models.URLField(max_length=200,blank=True, null=True)
time = models.DateTimeField(null=True)
venue = models.ForeignKey('self', null=True)
performers = models.ManyToManyField('self', null=True)
def __unicode__(self):
return self.title
#views.py
def index(request):
carousel = Article.objects.filter(display='C')
marketing = Article.objects.filter(display='M')
featurettes = Article.objects.filter(display='F')
return render_to_response('frontpage.html',{'carousel': carousel, 'marketing':marketing, 'featurettes': featurettes})