order_by causing not distinct items - django

I've implemented a messaging system:
class Message(models.Model):
user = models.ForeignKey(User, unique=False, related_name = 'messages')
conversation = models.ForeignKey('Conversation', related_name = 'messages')
body = models.TextField(max_length=750)
reads = models.ManyToManyField(User, related_name='read_messages', null=True, blank=True)
# Other
date_created = models.DateTimeField(auto_now=False, auto_now_add=True, blank=True)
date_modified = models.DateTimeField(auto_now=True, auto_now_add=False, blank=True)
class Conversation(models.Model):
participants = models.ManyToManyField(User, related_name='conversations')
type = models.CharField(max_length=1, default="D", choices=config.CONVERSATION_TYPE_OPTIONS)
Using Django Rest Framework, I'd like to order a conversation by the last message.
class ConversationFilter(filters.BaseFilterBackend):
"""
Filters to only show by current user
"""
def filter_queryset(self, request, queryset, view):
return queryset.filter(
participants=request.user,
).order_by('-messages__date_created')
However once I add the order_by method, the queries are no longer distinct. Adding distinct() does not work either. What is going on here?

You have a one to many relationship between Conversation and Message.
When you join the message table into the Conversation query (which happens when you add the order_by clause using messages), then you will get multiple Conversation entries, one for each message.

Related

django.core.exceptions.FieldError: Cannot resolve keyword 'date' into field. Join on 'date' not permitted

# Here is my models
This is my CustmerBuySell model DB designed.
class CustomerBuySell(models.Model):
customer = models.ForeignKey(CustomerAdd, on_delete=models.CASCADE)
customer_buy_sell_debit = models.DecimalField(max_digits=10, decimal_places=2, default=0.00)
customer_buy_sell_credit = models.DecimalField(max_digits=10, decimal_places=2, default=0.00)
description = models.CharField(max_length=250, blank=True)
date = models.DateField()
sms = models.BooleanField(default=False)
picture = models.ImageField(upload_to='customer_buy_sell_pics', default='images.png')
created_at = models.DateTimeField(auto_now_add=True, blank=True, null=True)
updated_at = models.DateTimeField(auto_now=True, blank=True, null=True)
def __str__(self):
return self.customer.customer_name
class Meta:
verbose_name = "Customer BuySell"
verbose_name_plural = "Customer BuySell"
# Here, is my View.
This is the class-based APIView, which I have used. And try to use the aggregate query in this view.
class DailyCustomerBuySellAPIView(APIView):
def get(self, request):
customer_buy_sell = CustomerBuySell.objects.extra(select={'day': 'date( date )'}).values('day').order_by(
'date__date').annotate(available=Count('date__date'))
serializer = CustomerBuySellSerializer(customer_buy_sell, many=True)
return Response({"customer_buy_sell": serializer.data})
# And, finally here are my Serializers
I have no idea what's the problem! Please help me.
class CustomerBuySellSerializer(serializers.ModelSerializer):
# customer = CustomerAddSerializer()
class Meta:
model = CustomerBuySell
fields = '__all__'
def to_representation(self, instance):
representation = super(CustomerBuySellSerializer, self).to_representation(instance)
if instance.customer is not None:
customer_name = instance.customer.customer_name
previous_due = instance.customer.previous_due
representation['custo`enter code here`mer_name'] = customer_name
representation['previous_due'] = previous_due
return representation
There are many problems with your approach. Let me mention each of them one by one:
First of all remove date__date from your APIVIew
Before:
customer_buy_sell = CustomerBuySell.objects.extra(select={'day': 'date( date )'}).values('day').order_by(
'date__date').annotate(available=Count('date__date'))
Instead, write it as:
from django.db.models.functions import Extract
customer_buy_sell = CustomerBuySell.objects.annotate(day=Extract('date','day')).values('day').order_by('day')
if you need a count of the days then you can try
customer_buy_sell_count = customer_buy_sell.count()
Another thing that you are doing wrong is you pass a dict to serializer as you are already using values that return a dictionary of days and not object of CustomerBuySell so you do not need to pass it to serializer otherwise you have to do it according to your need.
In CustomerBuySellSerializer you are using a model serializer with __all__ while you are passing an extra fields day that is not part of it.
So in short there are so many syntax issues with your Django and Django Rest Framework.Great way to fix such issues is to set with an experience programmer so that he can improve the flow of the code. Later on you can focus on logic.
I suppose it is just a typo: Change date__date to date

how to filter data in different models in django?

my models
class Player(TimeStampedModel):
name = models.CharField(max_length=200)
email = models.CharField(max_length=200)
email_verified = models.BooleanField(default=False, blank=True)
phone = models.CharField(max_length=200)
phone_verified = models.BooleanField(default=False, blank=True)
company_id = models.ImageField(upload_to=get_file_path_id_card, null=True,
max_length=255)
company_id_verified = models.BooleanField(default=False, blank=True)
team = models.ForeignKey(Team, related_name='player', on_delete=models.DO_NOTHING)
def __str__(self):
return self.name
this is my model , how to filter data in multiple model?
You can use a Queryset to filter by modal object's field.
You can use this to also filter relationships on models.
In your example, you can do a filter of all the Player entries that have a Character that have Weapon with strength > 10
Player.objects.filter(character__weapon__strength__gt=10)
You can also separate them out into 3 variables for readability purposes.
player_q = Player.objects.filter(character__isnull=False)
ch_q = player_q.filter(weapon__isnull=False)
wpn_dmg = ch_q.filter(strength__gt=10)
Please note that filters are lazy and thus don't return actual model instances untill they're evaluated. I think in this case gt returns an instance.
This documentation goes over all the fieldset lookups you can do with QuerySet object methods filter(), get(), and exclude()

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)

Django Nested Form - Always Showing Object instead of model details

I'm working on a Django project generated via Mezzanine. I've been able to create my models, however I want to have a form where an admin can select from a list to assign a value in a many to many or a one to many relationship. For example, I have a model for Schemas:
class Schema(AutoCreatedUpdatedMixin, SoftDeleteMixin):
"""List of all Schemas in a given database"""
name = models.CharField(max_length=128, null=False)
status = models.BooleanField(max_length=128, null=False, default=True, verbose_name="Is Active")
description = models.CharField(max_length=65535, null=True, blank=True, default=None)
database = models.ForeignKey(Database, on_delete=models.CASCADE)
pull_requests = models.ManyToManyField(Link)
questions = models.ManyToManyField(Question, blank=True)
comments = models.ManyToManyField(Comment, blank=True)
technical_owners = models.ManyToManyField(Employee, related_name='technical_owners_schemas', blank=True)
business_owners = models.ManyToManyField(Employee, related_name='business_owners_schemas', blank=True)
watchers = models.ManyToManyField(Employee, related_name='watchers_schemas', blank=True)
def __unicode__(self):
return "{}".format(self.name)
And I have a model for Employees
class Employee(AutoCreatedUpdatedMixin, SoftDeleteMixin):
"""List of people with any involvement in tables or fields: business or technical owners, developers, etc"""
name = models.CharField(max_length=256, blank=False, null=False, default=None, unique=True)
email = models.EmailField(blank=True, null=True, unique=True)
def __unicode__(self):
return "{}".format(self.employee)
An employee can own multiple schemas and a schema can be owned by multiple employees. My database has an active employee in it, however when I try to create a Schema the employee shows up as Employee Object. Rather I would want the form to show the Employee.name. How can I do this? My admin file contains the following:
class SchemasAdmin(admin.ModelAdmin):
list_display = ['name', 'status', 'database', 'description']
ordering = ['status', 'database', 'name']
actions = []
exclude = ('created_at', 'updated_at', 'deleted_at')
First of all are you using python 2 or 3? For 3, the __str__ method should be used instead of __unicode__. I am writing this because it seems that there's a problem with the __unicode__ method of Employee, which although is defined as:
def __unicode__(self):
return "{}".format(self.employee)
th Employee class does not have an employee attribute (unless there's such an attribute in the mixins that class inherits from (AutoCreatedUpdatedMixin, SoftDeleteMixin) but I don't think that is the case.
In any case, the problem is that you haven't defined a propery __str__ (if using python 3) or __unicode__ (for python 2) method on the Employee class - just define it like:
return self.name
and you should see the employee's name in the django admin select fields.

Django merge two QuerySets

I want to merge these two QuerySets. HotkeyAndPrefix do not have entries for every Collection in all_collections. This means len(all_collections) >= len(all_collections_hotkeys_and_prefixes). How can i merge these two QuerySets? If there is no entrie found for a Collection in HotkeyAndPrefix I want hotkey = None, prefix=None. Can I achieve this in one query?
models.py:
class Collection(models.Model):
creator = models.ForeignKey(User, blank=True, null=True)
...
class HotkeyAndPrefix(models.Model):
user = models.ForeignKey(User, null=True)
assigned_collection = models.ForeignKey(Collection, null=True)
hotkey = models.CharField(max_length=1, blank=True, null=True)
prefix = models.CharField(max_length=20, blank=True, null=True)
class Meta:
unique_together = ('user', 'assigned_collection')
view.py
admin = User.objects.filter(username='admin')[0]
all_collections = Collection.objects.filter(creator=admin)
current_user = request.user
all_collections_hotkeys_and_prefixes = HotkeyAndPrefix.objects.filter(assigned_collection__in=all_collections, user=current_user)
You need to use exclude() query. You can take the list of values which are in the
HotkeyAndPrefix.objects.filter(assigned_collection__in=all_collections, user=current_user) queryset
using
all_collections_hotkeys_and_prefixes_values = all_collections_hotkeys_and_prefixes.values_list('assigned_collection',flat=True)
and you can filter out the value, not in the all_collections_hotkeys_and_prefixes_values with one more query
all_collections_hotkeys_and_prefixes_excluded = all_collections.exclude(pk__in=all_collections_hotkeys_and_prefixes_values)
now you have two querysets, one of collection for which a user has hotkey/prefix and another for which the user doesn't