Calling related name models in query (Q) "Django" - django

I have profile model like :
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="profile")
first_name = models.CharField(max_length=30, blank=True, null=True)
last_name = models.CharField(max_length=30, blank=True, null=True)
and I have a search view like :
def users_search_view(request):
query = request.GET.get('q')
users = User.objects.filter(Q(email__icontains=query)|Q(username__icontains=query),is_superuser=False,is_staff=False)
ctx = {'users':users,
'q':query}
return render(request,"staff/users_search.html", ctx)
I want to have search by first name and also last name from Profile model, in my search, How can I make something like Q(email__icontains=query) for related modals ?

You can .filter(…) [Django-doc] with:
User.objects.filter(Q(profile__first_name__icontains=query) | Q(profile__last_name__icontains=query) | Q(email__icontains=query) | Q(username__icontains=query),is_superuser=False,is_staff=False)
One can use double underscores (__) to look "through" relations. This will result in a LEFT OUTER JOIN where we thus filter on the related Profile record for that User.

Just keep adding Q objects to your filter and use dunder (__) to access related fields.
E.g. User.objects.filter(Q(username__icontains=q) | Q(profile__first_name__icontains=q))

Related

Django - ManyToMany - how to filter on parent's ManyToMany object

I have problems with writing a filter on my queryset models:
class Order(models.Model):
items = models.ManyToManyField(OrderLine)
store = models.ForeignKey(Store, blank=True, null=True, on_delete=models.SET_NULL)
class OrderLine(models.Model):
orderItemId = models.IntegerField(blank=False, null=False, unique=True)
quantity = models.IntegerField(blank=True, null=True)
class Store(models.Model):
storeName = models.CharField(max_length=200, blank=True, null=True)
access_from_account = models.ManyToManyField(EDUser, blank=True)
I have my queryset of EDUser "accounts"
Now I want to select OrderLines that belongs to Order that are from Store that is visible by an account in access_from _account.
So, for example:
store_name_1 has access_from_account user_1, user_2
store_name_2 has access_from_account user_1
There at Orders that belongs to store_name_1. Those Orders have many OrderLines.
I would like to select order_lines that should be accessible by user_1.
Can I do it by:
acounts is queryset of ['user_1']
lines = OrderLine.objects.filter(order__store__access_from_account__in=accounts)?
I tried that, but I get some strange values...
Any suggestion of how to do it properly? I would like to avoid making lists and iterate over them.
Thanks in advance :)
The query
lines = OrderLine.objects.filter(
order__store__access_from_account__in=accounts
)
will work propery. The only problem is that if accounts contains two users, like user1 and user2, and both accounts have access to a store, it will duplicate the lines. You will thus retrieve OrderLines for user1 and for user2. This is due to the LEFT OUTER JOIN on the junction table in between. You can solve this by making use of .distinct() [Django-doc]:
lines = OrderLine.objects.filter(
order__store__access_from_account__in=accounts
).distinct()
If you are working with a single EDUser, then you do not need the __in lookup:
# for a single user
lines = OrderLine.objects.filter(
order__store__access_from_account=myuser
)

Django model order the queryset based on booleanfield True/False that related with User FK profile

I have two django models as follows:
The first one is a user profile, which has a FK to User model:
class Profile(models.Model):
PRF_user = models.OneToOneField(User, related_name='related_PRF_user', on_delete=models.CASCADE)
PRF_Priority_Support = models.BooleanField(default=False)
and the second is ticket model which has a FK to User model:
class ticket(models.Model):
ticket_status_options = [
('open', 'open'),
('wait_customer_reply', 'wait_customer_reply'),
('replied_by_staff', 'replied_by_staff'),
('replied_by_customer', 'replied_by_customer'),
('solved', 'solved'),
]
TKT_USER = models.ForeignKey(User, related_name='TKT_USER', on_delete=models.CASCADE)
TKT_DEB = models.ForeignKey('Site_departments', related_name='related_ticket_department', on_delete=models.CASCADE)
TKT_SUB = models.CharField(max_length=50, db_index=True, verbose_name="ticket subject")
TKT_BOD = models.TextField(verbose_name="ticket body")
TKT_image_attachment = models.ImageField(upload_to='TKT_img_attachment', blank=True, null=True , default=None)
TKT_CREATED_DATE = models.DateTimeField(auto_now_add=True)
TKT_UPDATED_DATE = models.DateTimeField(auto_now=True)
I want to sort the tickets based on user profile Priority_Support:
If the user profile PRF_Priority_Support is True, I want to sort it first inside my views QuerySet, otherwise (if PRF_Priority_Support is False) I want to sort it normally.
How can I do this?
You should name your model starting with a capital letter.
And for ordering the tickets, you can use something like this:
' queryset_list = ticket.objects.order_by('-TKT_USER__related_PRF_user__PRF_Priority_Support')
In filtering, when you want to span relationships, you use double underscore __ .
More on this here:
https://docs.djangoproject.com/en/3.1/topics/db/queries/#lookups-that-span-relationships
Another way is adding ordering to your model's Meta class.
For Example:
MyModel(models.Model):
class Meta:
ordering = ('-my_boolean_field ',)
Hi you should filter as follow:
Model.objects.filter(field=True) or False depending on what you need
Regards

How to search for objects in the Django User model

I have a Profile model:
from django.contrib.auth.models import User
class Profile(models.Model):
first_name = models.CharField(max_length=100, blank=True)
last_name = models.CharField(max_length=100, blank=True)
user = models.OneToOneField(User, on_delete=models.CASCADE)
birthday = models.DateField(null=True, blank=True)
bio = models.TextField(blank=True, max_length=1000)
location = models.CharField(max_length=100, blank=True)
...
And a search contacts view:
class SearchContactsView(ListView):
model = Profile
template_name = 'users/contact_search.html'
context_object_name = 'qs'
def get_queryset(self):
q1 = self.request.GET.get('contact_name')
q2 = self.request.GET.get('contact_location')
if q1 or q2:
return Profile.objects.filter(Q(first_name__icontains=q1) |
Q(last_name__icontains=q1),
location__icontains=q2)
return Profile.objects.all()
It is working fine but I would like to be able to search for contacts via the user field as well. Does anyone know a way to do that?
EDIT my user's username's are created by them when they sign up to the site and are currently uneditable. They are displayed on the admin page via a dropdown since they are a OneToOneField. I think my issue is that django recognises them only as an IntegerField('pk') but I need to somehow cast them as a string value. Am I right in thinking that, and if so how can this be achieved?
You can add to your template to allow user to input user_username and save that username to q3:
q3 = self.request.GET.get('user_username')
After that you can adjust your If condition accordingly, then change your return to something like:
Profile.objects.filter(Q(first_name__icontains=q1) |
Q(last_name__icontains=q1),
location__icontains=q2,
user__username=q3)

Filtering Django query filtering

I'm doing some querying currently and I was wondering if I would be able to query something from these 3 models where the return would give me all the projects the users are working on. I know about the basic filtering however thats not really enough in this case, how would one go about querying through 2 foreign keys.
class User(models.Model):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
email = models.EmailField()
class ProjectUser(models.Model):
project = models.ForeignKey("Project", on_delete=models.CASCADE)
user = models.ForeignKey("User", on_delete=models.CASCADE)
is_lead = models.BooleanField(default=False)
class Meta:
unique_together = (("project", "user"),)
class Project(models.Model):
name = models.CharField(max_length=255)
client = models.CharField(max_length=255)
complete = models.BooleanField(default=False)
You can obtain the Projects a user is working on with:
Project.objects.filter(
projectuser__user=user
)
The double underscores are used to look "through" relations. Furthermore the default related_query_name=… parameter [Django-doc] is, if not specified, the name of the model in lowercase.

How can I filter a model in django based on a field of a many to many related object?

I have two models related to each other with a many to many. I want to filter for one, Message, based on a field on the other, User.created_at, compared to a field on the first, Message.edit_date.
class Message(Model):
content = CharField(max_length=512, blank=True, null=True)
created_at = models.DateTimeField(blank=True, null=True)
edit_date = models.DateTimeField(blank=True, null=True)
users = models.ManyToManyField('User', related_name='message_user')
class User(Model):
name = content = CharField(max_length=48)
created_at = models.DateTimeField(blank=True, null=True)
Right now I am achieving this by looping over the two models and comparing them in the loop, which is slow.
message_query = Message.objects.none()
for user_name, created_at_date in Users.objects.filter(name='Tina').values_list('id', 'created_at').iterator():
message_query.add(Q(
users=user_id,
edit_date__gte=created_at_date,
), Q.OR)
messages = Message.objects.filter(message_query)
Is there any way to create a filter for the items I'm attempting to filter for in a query?
You can filter on fields on the related model directly using F expressions. Something like this should work:
from django.db.models import F
# This will return all messages where one of the associated users
# was created_at before the message edit_date.
Message.objects.filter(
edit_date__gte=F('users__created_at')
).distinct()
Note that this will return duplicate results if more than one user matches this condition for any given message - hence the distinct() the end.