How can I access ALL model attributes from two tables joined together using django ORM - mysql

I want to access all values from two related tables that I joined together based on one of the tables attributes:
obj = A.objects.filter(B__sample='sample_name').select_related()
but when i do:
{% for o in obj %}
{{o.sample}}
{{o.results}}
{{o.qc}}
{% endfor %}
only o.results and o.qc (from table A) are returned, o.sample is not returned (from table B)
how do i access all of the values from table A and B from my queryset object?

You've misunderstood how models work in Django.
sample is an attribute from model B, and will always be that. Django won't ever add it as a direct attribute to model A; that would be confusing.
You still access it via an instance of model B; the magic that Django gives you is that o.B (or whatever your ForeignKey is called) will access that model B instance, so you can do o.B.sample. Since you've used select_related, that won't incur another database hit.

obj = A.objects.filter(B__sample='sample_name').select_related('b')
try this , with small foreign model name

Related

Comparing lists in DBT jinja macro inside for loop

I am storing output of each column in a list for the below query
select table,
columns,
flag
from {{ model }}
for each table I need to compare the flag. how do i get flag in list for the corresponding table
{% for n in table %}
{%- if flag[n] == 'False' %}
I tried as above its not working its returning null value
It's important to understand that jinja is a templating language. In dbt, we use jinja to automate the creation of sql that then gets executed in our data warehouse. Accordingly, data from your data warehouse does not (typically) flow through your jinja code.
flag is a reference to a column in your database, so to evaluate the contents of flag, you need to write sql to do that job.
The only exception is if you are using run_query or a similar macro to pull the data from your database into your jinja context at model-compile time. But I don't see any reference to that in your code (and frankly that's a complicating detail that's only relevant if you are trying to write SQL dynamically). If you are just trying to compare the value from a record in your database as part of your model, just do it in sql.

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)

Using Doctrine2 with Foreign Keys in Symfony2

I have a MySQL database (that is later imported into Doctrine) set up that links 3 different tables by way of foreign keys. The relationship is as follows: Many As go to one B, and many Bs go to one C. For the web page that I am trying to create, I need some of the related B's information on a page about A, while being categorized by C.
Think of it like this: A is "dog_food", B is "company", and C is "company_category". That is, on a page displaying different kinds of dog food, I need to display information about the manufacturing company; I only display those dog foods based on how the user specifies what kind of company they want to buy from.
Pulling information dynamically from A is trivial, since the repository is pulled and the rows exist as entities. Say, {{ dog_food.price }} would call (if specified in a for loop, this is Twig code) a single instance's price.
I have read about the #OneToOne, #OneToMany, etc. annotations, but have not been able to find a way to easily utilize their effects inside of a Twig template. The aggregate entities and repositories for all 3 tables exist as variables in the Controller. It should be mentioned that, continuing with this example, that there is a single companyID field in table B corresponding to multiple dog foods, and a single categoryID associated with multiple companies.
What happens if I want to list the company name above the price? How do I access that information in Doctrine, and furthermore, in Twig?
I will translate what you've said above into code that I would effectively write if I was you:
So, I assume that, along with the mapping you defined , your company category entity is called 'Company_category', your dog food entity is called 'Dog_food'.
I would pass the id of the company_category to an action in my controller,
then, I would retrieve all the companies that belong to that company_category, something like this:
public function xyzAction($id){
$companies=$this->getDoctrine()->getRepository('XYZYourBundle:Company')
->findBy(array('company_category'=>$id));
//Hold on I will just complete it
}
Then I would retrieve all the dog foods objects from my DB, that the company's exist in $companies, the result returned in the first line of code,
to do this, I would first:
1-Define my own criteria:
this would help you define a complex , powerful conditions and it's easy to use.
2-Use my criteria to filter the result of the repository, this would be useful
So let's update our action:
public function xyzAction($id){
$companies=$this->getDoctrine()->getRepository('XYZYourBundle:Company')->findBy(array('company_category'=>$id));
$criteria = new \Doctrine\Common\Collections\Criteria();
$criteria->where($criteria->expr()->in('company',$companies));
$dogfoods=$this->getDoctrine()->getRepository('XYZYourBundle:Dog_food')->matching($criteria)
//Hold on I will just complete it
}
and finally render our dogfood objects to a twig template:
public function xyzAction($id){
$companies=$this->getDoctrine()->getRepository('XYZYourBundle:Company')->findBy(array('company_category'=>$id));
$criteria = new \Doctrine\Common\Collections\Criteria();
$criteria->where($criteria->expr()->in('company',$companies));
$dogfoods=$this->getDoctrine()->getRepository('XYZYourBundle:Dog_food')->matching($criteria)
return $this->render('XYZYourBundle:test.html.twig', array(
'dogfoods'=>$dogfoods));
}
Now, let's place ouselves in a twig template, we're gonna iterate through our $dogfoods objects and we will display some information, assuming you defined the needed getters and setters;
{% for dogfood in dogfoods %}
{{dogfood.price}}
{{dogfood.company}}
{% endfor %}
Edit :
you can get the company's name by either:
-implement a tostring method that returns the company's name and in twig use
{{dogfood.company}}
or
-in twig, use
{{dogfood.company.name}}
Hope this helps you, if something doesn't work just tell me.

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

Can I specify a set of base parameters for a Linq-to-sql DataContext?

I have a LINQ-to-SQL DataContext that represents a parent-child relationship of Products to Prices. I'm iterating through a list of products and retrieving the prices for each one. The problem is that the tables behind both the Products and Prices contain a list of Products or Prices for multiple environments, determined by a 3 field complex key. I want to retrieve the Products and Prices for only one of those environments.
I can do this be specifying a long where clause in each LINQ query consisting of the product key and the complex environment key, something like this:
var price = ( from condition in conditiontype where condition.MaterialNumber == material && condition.Client == "400" && condition.SalesOrg == "1000" && condition.DistributionChannel == "10" select condition.ConditionDetails[0].ConditionValue );
what I'd like to be able to do is to specify the Client, SalesOrg, and DistributionChannel globally for the DataContext so that all I need to specify in the query itself is the Product ID (MaterialNumber). That way when I starting querying our Production environment a simple change to the DataContext will change what environment I'm querying.
Is this possible? Either a brief code sample or pointers to the background theory would be wonderful!
You could have a pre-written Expression<T> which you then have those values in it:
public Expression<Func<int>> GetPrices = p => // do Lambda here
Alternatively you can put properties into your DataContext (remember, it's a partial class so it's easy to extend) which you set and are then read in by your expression.