Fetch currently logged in user relation with a given model instance - mysql

Assume we have a model called Author as such:
class Author(models.Model):
name = models.CharField(max_length=250)
We also have a feature which enables users to follow a certain author:
class UserFollow(models.Model):
author = models.ForeignKey(Author)
user = models.ForeignKey(User)
If you have a button in your UI that enables logged in users to follow / unfollow these authors. One way to check if this user is already following a certain author is to make a query on the existence of a record in UserFollow. However, when you're fetching a list of 10 / 20 .. etc authors, how would you check each author for the currently logged in user?
The usual approach would result in +X number of extra queries depending on how many items you're loading per page. Is there a more efficient way to achieve the same effect?
Thanks in advance

you can fetch all instances of UserFollow in view, pass it as a variable to the template and then you can check if given author is in this list
def my_view(request):
following = list(UserFollow.objects.filter(user=request.user))
template_context = {
'following': following
}
template:
{% for author in authors %}
{% if author in following %}
{# do some magic #}
{% endif %}
{% endfor %}

Related

Queries in query set group in to one query using Django

I have a query set like the below.
<QuerySet[{'user':'xyz','id':12,'home':'qwe','mobile':1234},
{'user':'xyz','id':12,'home':'qwe','mobile':4321},
{'user':'abc','id':13,'home':'def','mobile':1233},
{'user':'abc','id':13,'home':'def','mobile':1555},]>
This QuerySet is returned by django using
users.objects.all()
For Each query in the query set, I'm drawing a user table in the front-end which shows the details of users. If the same 'user' registers with two 'mobile' numbers, it is showed as two rows in the table instead of one. My goal is to display two numbers in the same row instead of creating two rows.
I have thought of two possible solutions which are below:
Solution 1: I have thought of merging the two queries into one if the 'user' value matches in both the queries. For this we need to make lot of checks using conditional statements which works slowly when lot of users are there.
Solution 2: I have searched on Google and came up with Group By Django, but it is not working. I have tried below
query = users.objects.all().query
query.group_by = ['mobile']
results = QuerySet(query=query, model=users)
Please provide a way so that two queries can be clubbed into one based on 'user' and after clubbing 'mobile' should contain two values.
Edit: I will pass this query set to a template via view where the table is being drawn. At present, for each query, one row is the in table. Since the above query set has four queries, we will have four rows. But I want to display the information in just two rows since the 'id' and 'user' are same. Code for template is below:
{% if users %}
{% for user in users %}
{% for k,v in required_keys.items %}
<td>{{ user | get_item:k }}
{% endfor %}
{% endfor %}
{% endif %}
Required key is an dictionary which contains the keys which are used to display in table. Example:
Required_keys = {
'User Name':user,
'Contact':mobile,
'Address':home,
}
The get item is a function which gets the value when key is passed.
def get_item(dictionery,key):
return dictionery.get(key)
Edit 2: I have tried for a solution and it's not a full solution but it partially solves the problem. The solution perfectly works with one user. However if there are many users, the solution doesn't work. See below for example:
# input query set to the function which partially solves the problem
<QuerySet[{'user':'xyz','id':12,'home':'qwe','mobile':1234},
{'user':'xyz','id':12,'home':'qwe','mobile':4321},]>
# Now our team has written a function which gives the following output
<QuerySet[{'user':'xyz','id':12,'home':'qwe','mobile':1234,4321},]>
But if there are more than one user, the output is same as input, it doesn't club the queries. See the function below:
def merge_values(cls,values):
import itertools
grouped_results = itertools.groupby(values,key=lambda x:x['id'])
merged_values = []
for k,g in grouped_results:
groups=list(g)
merged_value = {}
for group in groups:
for key, val in group.iteritems():
if not merged_value.get(key):
merged_value[key] = val
elif val != merged_value[key]:
if isinstance(merged_value[key], list):
if val not in merged_value[key]:
merged_value[key].append(val)
else:
old_val = merged_value[key]
merged_value[key] = [old_value, val]
merged_values.append(merged_value)
return merged_values
The values parameter for the function is the whole query set. But this function
works if there is only one user in query set as mentioned above. But if there
are multiple users, it fails.
Edit 3: I have found why above function won't work for multiple users(don't know whether this is correct). The input query set to the function (for one user) is
<QuerySet[{'user':'xyz','id':12,'home':'qwe','mobile':1234},
{'user':'xyz','id':12,'home':'qwe','mobile':4321},]>
Since the two user queries are one after another, they are clubbed. But if there are multiple users, the query set passed to the function is
<QuerySet[{'user':'xyz','id':12,'home':'qwe','mobile':1234},
{'user':'xyz','id':13,'home':'qwe','mobile':4321},
{'user':'abc','id':12,'home':'def','mobile':1233},
{'user':'abc','id':13,'home':'def','mobile':1555},]>
In the above query set, the user with same id are not one after another, so the function failed to get desired output.
You can use the function which you have written, only change is required is need to order the values based on id.
So before taking the values from the objects, order_by('id'), then take your required values and pass it to your function to merge the values.
Eg.
query_set = Mymodel.objects.filter(name='Required').order_by('id')
values = query_set.values('id', 'field1', 'field2')
merged_values = merge_values(values)
As a start, what would be helpful is to organise your models better. You have user information duplicated in your user model. If a you know that a user has multiple mobile numbers, it may be better to create a separate model for that:
class Mobile(models.Model)
number = models.IntegerField()
user = models.ForeignKey(User)
Then, when you are make a query and you want to get all the mobile numbers, you would first get all the users using users = User.objects.all() in your view, then in your template:
{% for user in users %}
{% for mobile in user.mobile_set.all %}
<td>{{ user }}</td>
<td>{{ mobile.number }}</td>
{% endfor %}
{% endfor %}
As a side note, I feel it's better practice to name your models as a singular (User instead of Users)

Liquid Tag in Where Filter in Jekyll

The following:
{% assign devices = site.data.equipment | where:"department","sound" | group_by:"servicelocation" %}
Is helping me build a list of sound devices from the equipment data list, grouped by location. The file resides in the _includes folder and is entitled equipment_list.html.
When I include this file in a _page, it displays exactly what I need, but I am attempting to take it one step further.
{% assign departmentname = page.name | remove:"equipment_list_" | remove:".md" %} yields the word sound based upon the _page/equipment_list_sound.md file.
{{ departmentname }} = "sound" as expected.
Can I insert this value into the where filter somehow to be able to re-use the equipment list page over and over again for different departments?
where:"department","{{departmentname}}" fails, and any variation I can imagine also fails. Is it possible?
You can use : {% assign devices = site.data.equipment | where:"department", departmentname | group_by:"servicelocation" %}

How to avoid a lot of queries when counting associated entities with Doctrine?

Imagine an User entity with an association with Group (many-to-many). I need to display user details (along with - say - group names or groups count). In my controller (Symfony 2) I can get all users:
$users = $this->em->getRepository('My\Entity\User')
->getAll();
// Assign $users to whatever the view engine
return $this->render('users.html.twig', array('users' => $users));
Of course , being the association LAZY by default, no JOIN operations with Group are performed. This is good most of the time.
But what happens when I try to get group count in my view?
{% for user in users %}
{{ user.groups|length }}
{% endfor %}
The result is: one query performed for each raw. That is, the number of the query equals the number of the user. What happens with 1000 users (and no pagination)?
How can fetch all associated entity for the User class (i.e. issue just one query)?
You do that by creating custom repository method where you join your entities.
More info -> http://symfony.com/doc/master/book/doctrine.html#joining-related-records

How do you refer to Config values from the admin interface in Zotonic validators?

I would like to be able to refer to a System Configuration value set in the Zotonic admin interface within a template.
In particular I would like to create a configurable password complexity regex so I can write a validate statement like the following:
{% validate id="new_password" type={format pattern=config.mod_admin_identity.password_regex %}
How do you refer to Config values from the admin interface in Zotonic validators?
The answer is quick to retrieve thanks to Arjan's new search I went from http://zotonic.com/search?q=config to http://zotonic.com/documentation/719/m-config and quickly devised a solution using m_config.
Here is a modification to _action_dialog_set_username_password.tpl that provides password complexity enforcement based on an admin config for module mod_admin_identity with key password_regex that auto-degrades to a simple presence check:
{% if m.config.mod_admin_identity.password_regex.value %}
{% validate id="new_password" type={presence} type={format pattern=m.config.mod_admin_identity.password_regex.value} %}
{% else %}
{% validate id="new_password" type={presence} %}
{% endif %}

Expense of django query

I have two tables: Actor and Images. The Images table is linked to the Actor table through a Foreign Key. I might make a query on Actor that pulls a list of all the actors with first name beginning with the letter A. Let's say I store this query result in actor_list and pass it to the template. I can get a list of all the Images through the template by iterating. Something like:
{% for actor in actor_list %}
{% for image in actor.img_set %}
{{ image }}
{% endfor %}
{% endfor %}
Is this costly to the database? Does the associated img_set come through with the initial actor object list, or does a new query hit the database every time I call for the actor.img_set?
You should install the Django debug toolbar and see what SQL queries are happening under the covers.
If you are getting too many queries, you can try using select_related() to pull in the related data in the initial query.
Better than using the django toolbar is using the connections library. With Debug set to True:
>>> from django.db import connection
>>> for actor in actor_list:
>>> for image in actor.img_set:
>>> image
>>> connection.queries()
This will show all the queries that were executed and the amount of time that each took.
The debug toolbar is cool, though, for many uses. :-)