Only the parent class using django-models-utils - django

I'm using django-models-utils in order to obtain all the children of a class. I've succeeded in that but now I don't seem to be able to obtain a view with just the parent class now.
This is the main class, the other classes are for reviews:
class Post(models.Model):
author = models.ForeignKey(User, null=True, blank=True)
title = models.CharField(max_length=200)
slug = models.SlugField(max_length=200, unique=True, blank=True)
text = models.TextField()
notable = models.BooleanField(default=False)
created = models.DateTimeField(editable=False, auto_now_add=True)
published = models.DateTimeField(null=True, blank=True)
modified = models.DateTimeField(editable=False, auto_now=True)
tags = models.ManyToManyField(Tag, blank=True)
objects = InheritanceManager()
This is the view for all posts (including the children), which is working:
def all_posts(request):
posts = Post.objects.order_by('published').filter(published__lte=timezone.now()).select_subclasses()
return render(request, 'blog/post_list.html', {'posts': posts})
This is the view for just the posts (which are not reviews, not children), but this isn't working as I'm getting all posts:
class RamblingList(ListView):
context_object_name = 'ramblings'
queryset = Post.objects.filter(published__lte=timezone.now()).order_by('published')
template_name = 'blog/rambling_list.html'
Can anyone tell me please what I'm doing wrong?

The InheritanceManager is not supposed to do that. If you call any filter without calling select_subclasses(), it will return all objects without the subclass cast.
It is clear in the documentation: http://django-model-utils.readthedocs.org/en/latest/managers.html#inheritancemanager
But when you iterate over nearby_places, you’ll get only Place instances back, even for objects that are “really” Restaurant or Bar
You could do something like this to achieve the desired effect:
queryset = Post.objects.filter(
published__lte=timezone.now()
).order_by('published').select_subclasses()
queryset = [x for x in queryset if type(x) == Post]

Related

How to use model functions in Views for multiple instances in Django?

I have a Blog Post Model and I have defined a function to calculate the no of likes.
The Model is as follows ->
class Post(models.Model):
user = models.ForeignKey(User, on_delete=models.PROTECT)
title = models.CharField(max_length=255)
description = models.CharField(max_length=1000,null=True)
Tags = models.CharField(max_length = 255,null=True,blank=True)
Created_date = models.DateTimeField(auto_now_add=True)
Updated_date = models.DateTimeField(auto_now=True)
category = models.ForeignKey(Category, on_delete=models.PROTECT)
Likes = models.ManyToManyField(to=User, related_name='Post_likes')
def __str__(self):
return self.title
def likesCount(self):
return self.Likes.count()
Now I am querying the Post Model from the DB to get all the Posts as follows ->
posts = Post.objects.select_related().prefetch_related('images_set','comments_post').annotate(Count('comments_post')).all()
Here when I loop over the posts I can call the likesCount function and it gives me the correct result as well but I want to return the No of likes to the template.
How can I do that?
in your template, try this:
{{ post.likes_set.count }}
and please make the field names lowercase, they are not Classes

How to render a foreign key field in Django

Desired outcome: When I render a Poller and its associated comments
I would like to also render the Vote a user selected for the Poller along with his comment (Note: A user can only comment if he voted on that poller).
Side note: A user can make one vote to a Poller and post one comment to a Poller. He can only comment if he voted beforehand.
# Models
class Poller(models.Model):
poller_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
created_on = models.DateTimeField(auto_now_add=True)
created_by = models.ForeignKey(Account, on_delete=models.CASCADE)
poller_text = models.CharField(max_length=333)
poller_choice_one = models.CharField(max_length=20)
poller_choice_two = models.CharField(max_length=20)
class Vote(models.Model):
poller = models.ForeignKey(Poller, on_delete=models.CASCADE, related_name='vote')
user = models.ForeignKey(Account, on_delete=models.CASCADE)
created_on = models.DateTimeField(auto_now_add=True)
poller_choice_one_vote = models.BooleanField(default=False)
poller_choice_two_vote = models.BooleanField(default=False)
def __str__(self):
return f'Vote by {self.user}'
class Comment(models.Model):
poller = models.ForeignKey(Poller, on_delete=models.CASCADE, related_name='PollerComment')
user = models.ForeignKey(Account, on_delete=models.CASCADE)
created_on = models.DateTimeField(auto_now_add=True)
comment = models.TextField(max_length=350)
flag_count = models.IntegerField(default=0)
upvote_count = models.IntegerField(default=0)
downvote_count = models.IntegerField(default=0)
# View
#require_GET
def render_single_poller(request, poller_id):
# Retrieve comments associated to the Poller
comments_qs = PollerComment.objects.filter(poller_id=poller_id)
context = {
'comments_qs': comments_qs,
}
return render(request, 'pollboard/single_poller.html', context)
I tried to do it via a template filter like so:
# pollboard_tags.py
#register.filter(name='get_vote')
def get_voted(self):
self.vote_made = 'Test'
print(self.vote.poller_choice_one_vote)
if self.vote.poller_choice_one_vote:
self.vote_made = 'One'
else:
self.vote_made = 'Two'
return self.vote_made
# template
<div class="commentors-poller-choice">{{ comment|get_vote }}</div>
throws
RelatedObjectDoesNotExist at /poller/68c725eb-277e-4b5b-a61b-b4a02bf5e854/
PollerComment has no vote.
I fear that I'm already overcomplicating things here. I hope there is a more straightforward solution to this like idk expanding the comments queryset by the required information for rendering?
If a user can vote on a poller only once, you can filter with:
#register.filter(name='get_vote')
def get_voted(self):
vote = Vote.objects.get(poller=self.poller, user=self.user)
return 'One' if vote.poller_choice_one_vote else 'Two'

How to use Get and Filter in set to get values related to a particular user

Im trying to get values of an order which a particular user made, I mean I have an e commerce app where a user can made purchases, I successfully got the order item to display when a user wants to make an order, but i want to get all the orders which are already purchased by that user to display in a different page (Order History), Im trying to use queryset for the Serializers but its just not work despite severally tweaks, and i have ready the docs but cant seem to get it right. Please help,
Model:
user = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
ref_code = models.CharField(max_length=20, blank=True, null=True)
items = models.ManyToManyField(eOrderItem)
start_date = models.DateTimeField(auto_now_add=True)
ordered_date = models.DateTimeField(null=True)
ordered = models.BooleanField(default=False)
payment = models.ForeignKey(
'Payment', on_delete=models.SET_NULL, blank=True, null=True)
coupon = models.ForeignKey(
'Coupon', on_delete=models.SET_NULL, blank=True, null=True)
being_delivered = models.BooleanField(default=False)
received = models.BooleanField(default=False)
refund_requested = models.BooleanField(default=False)
refund_granted = models.BooleanField(default=False)
transaction_id = models.CharField(max_length=200, null=True)
qr_code = models.ImageField(upload_to='qrcode', blank=True)
This is the serializer for the (Order History)
class TicketSerializer(serializers.ModelSerializer):
order_items = serializers.SerializerMethodField()
class Meta:
model = Order
fields = '__all__'
def get_order_items(self, obj):
return OrderItemSerializer().data
View:
class TicketDetailView(RetrieveAPIView):
serializer_class = TicketSerializer
permission_classes = (IsAuthenticated,)
def get_object(self):
try:
# order = Order.objects.get(user=self.request.user).filter(ordered=True)
# order = Order.objects.filter(order=True)
# order = Order.objects.get(user=self.request.user, ordered=True)
order = Order.objects.filter(ordered=False, user=self.request.user)
return order
except ObjectDoesNotExist:
return Response({"message": "You do not have any ticket"}, status=HTTP_400_BAD_REQUEST)
from the view, you can see i try tried may options with queryset, but its not work, It works when i use get(user=self.request.user), but when i pass Order=True(for order history) it says get() returned more than one Order -- it returned 3! and i understand because i use get() (other options dont work) when i pass Order=False (as it works for the order item to be purchased) it works because its just one at a time.
What do i do please, i just want to be about to get all the items that are order by a particular user.
You expect multiples results that's why you should override get_queryset() and not get_object() (should be used for detail views):
def get_queryset(self):
return Order.objects.filter(ordered=False, user=self.request.user)

Object-level permissions in Django

I have a ListView as follows, enabling me to loop over two models (Market and ScenarioMarket) in a template:
class MarketListView(LoginRequiredMixin, ListView):
context_object_name = 'market_list'
template_name = 'market_list.html'
queryset = Market.objects.all()
login_url = 'login'
def get_context_data(self, **kwargs):
context = super(MarketListView, self).get_context_data(**kwargs)
context['scenariomarkets'] = ScenarioMarket.objects.all()
context['markets'] = self.queryset
return context
The two market models are as follows:
class Market(models.Model):
title = models.CharField(max_length=50, default="")
current_price = models.DecimalField(max_digits=5, decimal_places=2, default=0.50)
description = models.TextField(default="")
shares_yes = models.IntegerField(default=0)
shares_no = models.IntegerField(default=0)
b = models.IntegerField(default=100)
cost_function = models.IntegerField(default=0)
open = models.BooleanField(default=True)
def __str__(self):
return self.title[:50]
def get_absolute_url(self):
return reverse('market_detail', args=[str(self.id)])
class ScenarioMarket(models.Model):
title = models.CharField(max_length=50, default="")
description = models.TextField(default="")
b = models.IntegerField(default=100)
cost_function = models.IntegerField(default=0)
most_likely = models.CharField(max_length=50, default="Not defined")
open = models.BooleanField(default=True)
def __str__(self):
return self.title[:50]
def get_absolute_url(self):
return reverse('scenario_market_detail', args=[str(self.id)])
And my user model is as follows:
class CustomUser(AbstractUser):
points = models.DecimalField(
max_digits=20,
decimal_places=2,
default=Decimal('1000.00'),
verbose_name='User points'
)
bets_placed = models.IntegerField(
default=0,
verbose_name='Bets placed'
)
net_gain = models.DecimalField(
max_digits=20,
decimal_places=2,
default=Decimal('0.00'),
verbose_name='Net gain'
)
class Meta:
ordering = ['-net_gain']
What I want happen is that different users see different sets of markets. For example, I want users from company X to only see markets pertaining to X, and same for company Y, Z, and so forth.
Four possibilities so far, and their problems:
I could hardcode this: If each user has a company feature (in addition to username, etc.), I could add a company feature to each market as well, and then use if tags in the template to ensure that the right users see the right markets. Problem: Ideally I'd want to do this through the Admin app: whenever a new market is created there, it would be specified what company can see it.
I could try to use Django's default permissions, which of course would be integrated with Admin. Problem: Setting a view permission (e.g., here) would concern the entire model, not particular instances of it.
From googling around, it seems that something like django-guardian might be what I ultimately have to go with. Problem: As I'm using a CustomUser model, it seems I might run into problems there (see here).
I came across this here on SO, which would enable me to do this without relying on django-guardian. Problem: I'm not clear on how to integrate that into the Admin app, in the manner that django-guardian seems able to.
If anyone has any advice, that would be greatly appreciated!
You can add some relationships between the models:
class Company(models.Model):
market = models.ForeignKey('Market', on_delete=models.CASCADE)
...
class CustomUser(AbstractUser):
company = models.ForeignKey('Company', on_delete=models.CASCADE)
...
then in your view you can simply filter the queryset as appropriate:
class MarketListView(LoginRequiredMixin, ListView):
context_object_name = 'market_list'
template_name = 'market_list.html'
login_url = 'login'
def get_queryset(self):
return Market.objects.filter(company__user=self.request.user)
Note, you don't need the context['markets'] = self.queryset line in your get_context_data; the queryset is already available as market_list, since that's what you set the context_object_name to.

Django inline model formset with 2 models

First of all, please forgive for my newbie questions. I did copy most of the code, and try to understand from Django documents.
Code as below:
models.py
class Order(models.Model):
ORDER_CHOICES = (
('import', 'IMPORT'),
('export', 'EXPORT')
)
storage = models.ForeignKey(Storage, on_delete=models.PROTECT)
order_type = models.CharField(max_length=6, choices=ORDER_CHOICES)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now_add=True)
class Item(models.Model):
def random_barcode():
return str(random.randint(10000000, 99999999))
type = models.ForeignKey(Type, on_delete=models.CASCADE)
order = models.ForeignKey(Order, on_delete=models.CASCADE, null=True)
brand = models.ForeignKey(Brand, on_delete=models.CASCADE)
item_name = models.CharField(max_length=50, help_text='Name of goods, max 50 characters')
barcode = models.CharField(max_length=8, default=random_barcode, unique=True)
production_date = models.DateField()
expired_date = models.DateField()
def __str__(self):
return self.item_type
forms.py
class ItemForm(ModelForm):
class Meta:
model = Item
exclude = ['order',]
fields = ['type', 'brand', 'item_name', 'production_date', 'expired_date']
ItemFormSet = inlineformset_factory(Order, Item, form=ItemForm, extra=1)
views.py
class CreatePO(CreateView):
model = Order
context_object_name = 'orders'
template_name = 'storages/create_po.html'
fields = ['order_type', 'storage',]
*#dun't know how to write below code....*
1st question: how to use inline formset to write the CreatePO view?
2nd question: I need my create PO template as below picture, how to add a "Quantity" field?
This kind of template need Javascript, right? Any alternative solution? I have no knowledge with javascript.
First of all, move the def random_barcode(): before def __str__(self): it looks so ugly formated code.
Then let's have a look in your pic, if you haven't proper experience with Javascript you can use Admin Views from Django, it's much more simple and supported by Django 2.1. Read more if you would like to give permission to everyone in a admin-views page https://docs.djangoproject.com/el/2.1/releases/2.1/#model-view-permission
So quantity will be just added inside Item class
quantity = models.PositiveSmallIntegerField(default=1)
Also for your form, in my opinion, you need modelform_factory, so I suggest to read this one https://docs.djangoproject.com/en/2.1/topics/forms/modelforms/#modelform-factory-function