Django Admin: Intersection (Natural Inner Join) between Two Models - sql

I'm a Django beginner. I have two models that I would like to display as one table in the Django admin interface. Below are the simplified versions of the models:
class Final_Application_Personal_Detail(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=20)
id_no = models.CharField(max_length=14)
class Final_Application_Beneficiary_Detail(models.Model):
user = models.ForeignKey(User)
beneficiary_name = models.CharField(max_length=20)
beneficiary_id_no = models.CharField(max_length=14)
I suppose because these two models conceptually form part of one form (a Final_Application form), I could have maybe used Django's formwizard - however, because in reality both personal details and beneficiary details are quite a lot to fill in, I thought I'd want to give the user a chance to fill them in separately (in django formwizard, as far as I know, if the user doesn't fill out all the data at once, then all previous data is also lost because the form can't be saved with unvalidated fields).
I want to join the two models in Django admin so that the administrative user can see all a user's information (personal details and beneficiary's details) on one page. So, I'd like to do an inner join on the above-mentioned tables on the field 'user'. The SQL would look like this:
SELECT *
FROM Final_Application_Personal_Detail
JOIN Final_Application_Beneficiary_Detail
ON Final_Application_Personal_Detail.user = Final_Application_Beneficiary_Detail.user
With regards to Django's ORM, I've looked into the keyword argument related_to in order to join the tables. I don't think that will work, however...it seems as if 'select_related' is just another way to stipulate a foreign key. I now want to use raw SQL in order to join the tables. I've tried using the cursor function to implement raw SQL, but I don't quite know how to implement it so that the output shows in Django's admin interface. Also, I'm a little bit afraid of using raw SQL, because as far as I understand, raw SQL can introduce security risks (I've read that Django's ORM prevents SQL injections).
Thank you for your help.

You can't do this with django admin. However, you can use inlines to edit both models in the User admin.
from django.contrib import admin
from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin
class Final_Application_Personal_DetailInline(admin.StackedInline):
model = Final_Final_Applicationl_Detail
class Final_Application_Beneficiary_DetailInline(admin.StackedInline):
model = Final_Final_Application_Beneficiary_Detail
admin.site.unregister(User)
#admin.register(User)
class CustomUserAdmin(UserAdmin):
inlines = [
Final_Application_Personal_DetailInline,
Final_Application_Beneficiary_DetailInline,
]

Related

Is it possible to use a my SQL inner join query inside my ASP.NET WEB API app directly, or is it better to translate, if so how can it be done?

I'm working on my first (kinda) big personal project and I am stuck. I have 4 tables, 3 of which have foreign keys linking into tbl_model_details. All tables are listed below.
tbl_model_details
tbl_model_type
tbl_model_name
tbl_model_scale
Ideally I want to show data through my controller with HTTP Get. I can get Postman to to return data from my controller using _context.tbl_model_details.ToList();
Currently Postman is showing the id's for the other tables, but want them to show data from other columns within those tables instead of the id.
Within SQL I was able to build this query which displays the information I would like from the other tables, Is there an equivalent that I could make to run inside my controller? Or is there a way I can use this query that I have already made?
SELECT model_scale, model_name, info, picture, model_type, part_number, amount_owned, modified, limited_addition, date_purchase, price_paid, upc
from tbl_model_details
join tbl_model_type
on tbl_model_details.type_id = tbl_model_type.type_id
join tbl_model_name
on tbl_model_details.name_id = tbl_model_name.name_id
join tbl_model_scale
on tbl_model_details.scale_id = tbl_model_scale.scale_id
Any help from you guys would be great.
Thanks
You can use Entity Frameworks LINQ Include. This will allow you to include the sub-models in the same query:
_context.tbl_model_details
.Include(details => details.tbl_model_type)
.Include(details => details.tbl_model_name)
.ToList();
Without knowing your relationships, DBSet and Model setups, I can say that the statement will look exactly like the one I mentioned, but this may help you get on the right track.
This will allow you to later retrieve data from the sub-models:
#Model.tbl_model_scale.model_scale;

How to create a temp boolean field with Django orm

Image I have following models:
class Product(models.Model):
name = models.CharField(max_length=20)
class Receipt(models.Model):
product = models.ForeignKey(Product)
user = models.ForeignKey(User)
I have an input list of product ids and a user. I want to query for each product, whether it's been purchased by this user. Notice I need a queryset with all exist products based on given input because there are other fields I need for each product even not purchased by this user, so I cannot use Product.objects.filter(receipt__user=user).
So can I create a temp Boolean field to present this property in one single query? I am using Django 1.8 and postgresql 9.3
Update requirements:To separate products into two groups. One is bought by this specific user, the other one is not. I don't think any given filter can implement this. This should be implement by creating a new temp field either by annotate or F expression.
I think, you need .annotate() expression as
from django.db.models.expressions import Case, When, Value
product_queryset = Product.objects.annotate(
is_purchased=Case(
When(receipt__user=current_user, then=Value('True')),
default=Value('False')
))
How to access the annotated field?
product_queryset.first().is_purchased
Thx for #JPG's answer.
I just realize except conditional expressions, there's another easy way to do it.
Just using prefetch_related will implement everything in two queries. Although it's double than conditional expressions, but it's still a considerable time complexity solution.
products = Product.objects.filter(id__in=[1,2,3,4,5]).prefetch_related ('receipt_set').all()
Then we can detect user for this product in Python by
for p in products:
print user in [receipt.user_id for receipt in p.purchase_set.all()]

How to create a single query across associations

I have a user model that has one profile and also has one goal. The profile has a privacy field which is of type hstore, and in that field there can be a hash that indicates that it is OK to publicly display the goal, the hash looks like { 'show_goals' => '1' } if the goal can be displayed. I want a list of all goals that can be displayed publicly. My initial attempt was
def list_public
profiles = Profile.includes(:user).where("privacy #> hstore('show_goals','1')")
goals = []
profiles.each do |p|
goals << p.user.goals.first
end
goals
end
end
This works fine when there was a small number of users opting into allow their goals to be displayed, but is clearly not scaleable. Is there a single or a couple of ActiveRecord sql queries that can do the job of this code? I am using ruby on rails 5.1.
The easiest way is to also eager load the goals in your query:
profiles = Profile.includes(:user, user: :goals).where("privacy #> hstore('show_goals','1')")
This will produce one additional query fetching all the goals. You can then still use the remaining code as is, p.user.goals.first will not generate an additional database query.

How to avoid N+1 query

I have the following models:
User
Ability
PricingRule
defined with the following relationships:
user has many pricing rules
ability has one pricing rule
The idea is to fetch all abilities matching some criteria and for each, fetch its pricing rule. However a custom pricing rule for a particular ability can be defined on a per user basis.
Currently I fetch all matching abilities and iterate on them to either:
try to find a current ability matching a user's pricing rule
or default to the ability's pricing rule
I am using Rails and ActiveRecord and here what I have so far:
user = User.first
Ability.all.map do |a|
user.pricing_rules.matching_ability(a).first || a.pricing_rule
end
Per user pricing rule customization should be done on demand by the business. The common workflow is to get the pricing rule from the abilities.
Any ideas or help to get me on the right track would be much appreciated.
EDIT:
Where the matching_ability implementation is as follow:
def self.matching_ability(ability)
where(name: ability.name)
end
You can "eager load" to avoid N+1 queries like so:
user = User.includes(pricing_rules: :abilities).first
Ability.includes(:pricing_rule).map do |a|
user.pricing_rules.matching_ability(a).first || a.pricing_rule
end
You should see in the SQL generated that this adds a LEFT OUTER JOIN to your queries, so ActiveRecord is loading the associated records in just the two queries. In particular, the user will be loaded with its pricing_rules and the abilities on each pricing_rule, and the abilities will be loaded with their pricing_rules.
However, implementing matching_ability using where may generate additional queries, returning you to the N+1 problem. To take advantage of the "eager load" in the first query, you may need to refactor to:
self.matching_ability(ability)
select{|a| a.name == ability.name}
end

SubmitChanges with LINQ to SQL and User Defined Functions

On the SQL server I create a UDF. Let's name it fnCompanyDetails. It selects some information about a company from several joint tables.
I then drag-and-drop this function in the new .dbml of my VB project. I want to use it with LINQ. Smth like this:
Dim company = (From c In d.fnCompanyDetails(sap)
Select New With {
.Sap = c.txtSAP,
.CompanyName1 = c.txtCompanyName1, _
.CompanyName2 = c.txtCompanyName2, _
})
The result of this query I display to the user in a form. If some field is changed I want to send the changes to my database, but is this possible if I'm quering like this, from a UDF?
Thank y
No, it is unfortunately not possible to do in a simple way. Linq-to-sql supports reading to custom types, but only support updates through the entity types that exactly corresponds to a table.
Normally the best way is to always read pure entity objects if they are read with the intention to update them.
Another solution is to create entity objects out of the data returned from the udf and then attach those entities to the context. If you attach the entities in their original state first and then make changes after attaching, you should get away without any change tracking problems.