iterate over instance field containing multiple instances? - mysql

This is my fist time using django and I'm having some problems to understand how data is stored, so I can not really use it as I want to. I made many researches but I don't find any related question probably because I don't have the right keywords.
In my app model I created a WebPage and Count class:
class Count(models.Model):
date = models.DateField(default=date.today)
count = models.IntegerField(default=0)
class WebPage(models.Model):
link = models.CharField(max_length=60)
id = models.AutoField(primary_key=True)
clicks = models.IntegerField(default=0)
stats = models.ForeignKey(Count)
Then I created a WebPage object with multiple Count objects and I'd like to create a method to retrieve the sum of the count instances.
def get_clicks(self):
self.clicks=0
for object in self.stats:
self.clicks+=object.count
return str(self.clicks)
but I get the error 'Count' object is not iterable which is logic because I defined self.stats as an single Count object. I told my self that if the Count instances are not stored in self.stats they could be stored as "global" Count instances so I iterated over the object instances for object in self._meta.fields but the multiple Count instances are missing:
statistics.WebPage.link
statistics.WebPage.id
statistics.WebPage.clicks
statistics.WebPage.stats
And I think that iterate over the "global" Count objects it is not an option because I could not know which Count instance belong to which WebPage.
Where the self.stats Count instances hidden? Thanks for the help!
(I'm using django 1.7)

The problem is that your ForeignKey is the wrong way round. The model that the FK is defined in is the "many" side of the one-to-many relationship. That is, the way you have it, each Count has many WebPages, whereas I think you want the other way round.
Then you can sum the counts attached to your web page in one go via aggregation:
from django.db.models import Sum
total_clicks=my_web_page.count_set.aggregate(Sum('count'))
or, to get clicks for a whole queryset of webpages:
my_web_page_queryset.annotate(clicks=Sum('count__count'))

web_page = Webpage.objects.get(pk=1)
def get_clicks(web_page):
return web_page.contact_set.count()
This will work if you get a single Webpage. If you get a group of webpages, you can loop through them and call get_clicks for each.

Related

Laravel Eloquent - auto-numbering on has many relationship

I'm very much a beginner when it comes to database relationships hence what I suspect is a basic question! I have two database tables as follows:
Projects
id
company_id
name
etc...
rfis
id
project_id (foreign key is id on the Projects table above)
Number (this is the column I need help with - more below)
question
The relationships at the Model level for these tables are as follows:
Project
public function rfi()
{
return $this->hasMany('App\Rfi');
}
RFI
public function project()
{
return $this->belongsTo('App\Project');
}
What I'm trying to achieve
In the RFI table I need a system generated number or essentially a count of RFI's. Where I'm finding the difficulty is that I need the RFI number/count to start again for each project. To clarify, please see the RFI table below which I have manually created with the the 'number' how I would like it displayed (notice it resets for each new project and the count starts from there).
Any assistance would be much appreciated!
Todd
So the number field depends on the number of project_id in the RFI table. It is exactly the number of rows with project_id plus one.
So when you want to insert a new row, you calculate number based on project_id and assign it.
RFI::create([
'project_id' => $project_id,
'number' => RFI::where('project_id', $project_id)->count() + 1,
...
]);
What I understood is that you want to set the value of the "number" field to "1" if it's a new project and "increment" if it's an existing project. And you want to automate this without checking for it every time you save a new row for "RFI" table.
What you need is a mutator. It's basically a method that you will write inside the desired Model class and there you will write your own logic for saving data. Laravel will run that function automatically every time you save something. Here you will learn more about mutators.
Use this method inside the "RFI" model class.
public function setNumberAttribute($value)
{
if(this is new project)
$this->attributes['number'] = 1;
else
$this->attributes['number']++;
}
Bonus topic: while talking about mutators, there's also another type of method called accessor. It does the same thing as mutators do, but just the opposite. Mutators get called while saving data, accessors get called while fetching data.

How to limit results in reverse relation in Django

I have two tables, one called Company and the other called User, each user is related to one company using ForeignKey. So I can use reverse relation in Django to get all users for specific company (e.g. company.users)
In my case, I'm building ListAPIView which return multiple companies, and I'd like to return latest created user. My problem is that I don't want to use prefetch_related or select_related so it will load all the users, as we might end up having thousands of users per each company! Also I don't want to load each latest user in a separate query so we end up having tens of queries per API request!
I've tried something like this:
users_qs = models.User.objects.filter(active=True).order_by('-created')
company_qs = models.Company.objects.prefetch_related(
Prefetch('users', queryset=users_qs[:1], to_attr='user')
).order_by('-created')
In this case, prefetch_related failed as we can't set limit on the Prefetch's queryset filter (it gives this error "Cannot filter a query once a slice has been taken.")
Any ideas?
I think you are providing an object instead of a queryset Prefetch('users', queryset=users_qs[:1], to_attr='user')

How to get records with last dates in Django ORM(MySQL)?

I have models:
class Reference(models.Model):
name = models.CharField(max_length=50)
class Search(models.Model):
reference = models.ForeignKey(Reference)
update_time = models.DateTimeField(auto_now_add=True)
I have an instance of Reference and i need to get all last searches for the reference. Now i am doing it in this way:
record = Search.objects.filter(reference=reference)\
.aggregate(max_date=Max('update_time'))
if record:
update_time = record['max_date']
searches = reference.search_set.filter(update_time=self.update_time)
It is not a big deal to use 2 queries except the one but what if i need to get last searches for each reference on a page? I would have got 2x(count of references) queries and it would not be good.
I was trying to use this solution https://stackoverflow.com/a/9838438/293962 but it didn't work with filter by reference
You probably want to use the latest method.
From the docs, "Returns the latest object in the table, by date, using the field_name provided as the date field."
https://docs.djangoproject.com/en/1.8/ref/models/querysets/#latest
so your query would be
Search.objects.filter(reference=reference).latest('update_time')
I implemented a snippet from someone in gist but I don't remember the user neither have the link.
A bit of context:
I have a model named Medicion that contains the register of mensuration of a machine, machines are created in a model instance of Equipo, Medicion instances have besides of a Foreign key to Equipo, a foreign key to Odometro, this model serves as a kind of clock or metre, that's why when I want to retrieve data (measurements aka instances of Medicion model) for a certain machine, I need to indicate the clock as well, otherwise it would retrieve me a lot of messy and unreadable data.
Here is my implementation:
First I retrieve the last dates:
ult_fechas_reg = Medicion.objects.values('odometro').annotate(max_fecha=Max('fecha')).order_by()
Then I instance an Q object:
mega_statement = Q() # This works as 'AND' Sql Statement
Then looping in every date retrieved in the queryset(annotation) and establishing the Q statement:
for r in ult_fechas_reg:
mega_statement |= (Q(odometro__exact=r['odometro']) & Q(fecha=r['max_fecha']))
Finally passed this mega statement to the queryset that pursues to retrieve the last record of a model filtered by two fields:
resultados = Medicion.objects.filter(mega_query).filter(
equipo=equipo,
odometro__in=lista_odometros).order_by('odometro', 'fecha') # lista_odometros is a python list containing pks of another model, don't worry about it.

Laravel 4 Eager Loading filtering and selecting only matching results

I'm trying to output the filter results with only matching elements.
I have two tables (in the real project, which will be 5), let's say companies and projects. A company may have more than one project or may not have any.
These are the relations:
/app/models/Company.php
<?php
class Company extends Eloquent {
public function projects() {
return $this->hasMany('Project','companyID');
}
protected $table = 'companies';
}
/app/models/Project.php
<?php
class Project extends Eloquent {
public function companies() {
return $this->belongsTo('Company','companyID');
}
}
What I want to do is, I want to get results of them both but only with matching parameters.
I've tried this:
return Company::with(array('projects'=>function($query){
$query->where('id',99); //project's id is 99
}))->get();
This is the output JSON
If I change the value from 99 to 1 (there is a result with products.id of 1), it changes into this:
I only want to get the second result from the second JSON i've posted.
As you can see in the second JSON (I'm using this parser to check), all companies are loaded regardless of the project, and only the rows matched have the object projects.
There will be more 'with's and I don't know how to filter only matching elements.
I also tried having() inside closure, but it's still same:
$query->having('projects.id','=',99);
Is there a way to filter only matching results (without using a loop) which the output will only include the results having the matched projects object?
Edit: Actually, 5 tables will be filtered.
companies, projects, works, users and user_works
Let's say;
"Companies" have many projects.
"Projects" have many works
"Works" have many users, also "Users" may have more than one work (pivot table user_works).
All relations are set correctly from models.
I want to do a global searching to these.
Something like: "Bring me the user id 1's works which has company id of 5 and project id of 4", but none of the fields are mandatory.
So these are also valid for searching: "Bring me everyone's works on project id of 2", or "bring me id 2's works", or "bring me all the works starting from today", "bring me the id 1's works on project 2", "Bring me this year's works done of company id 1".
Thanks in advance
Using whereHas() is the solution on my case. It filters relation and affects the results returned in the main query.
If you have the id of the project, would it make more sense to go that route? $project = Project::find(99); and then the company variables would be accessible with $project->companies->name;
It would make more sense to rename the companies() function to company() because a project will only ever belong to one.

Can I create sperate queries for different views?

I'm learning sqlalchemy and not sure if I grasp it fully yet(I'm more used to writing queries by hand but I like the idea of abstracting the queries and getting objects). I'm going through the tutorial and trying to apply it to my code and ran into this part when defining a model:
def __repr__(self):
return "<User('%s','%s', '%s')>" % (self.name, self.fullname, self.password)
Its useful because I can just search for a username and get only the info about the user that I want but is there a way to either have multiple of these type of views that I can call? or am I using it wrong and should be writing a specific query for getting different data for different views?
Some context to why I'm asking my site has different templates, and most pages will just need the usersname, first/last name but some pages will require things like twitter or Facebook urls(also fields in the model).
First of all, __repr__ is not a view, so if you have a simple model User with defined columns, and you query for a User, all the columns will get loaded from the database, and not only those used in __repr__.
Lets take model Book (from the example refered to later) as a basis:
class Book(Base):
book_id = Column(Integer, primary_key=True)
title = Column(String(200), nullable=False)
summary = Column(String(2000))
excerpt = Column(Text)
photo = Column(Binary)
The first option to skip loading some columns is to use Deferred Column Loading:
class Book(Base):
# ...
excerpt = deferred(Column(Text))
photo = deferred(Column(Binary))
In this case when you execute query session.query(Book).get(1), the photo and excerpt columns will not be loaded until accessed from the code, at which point another query against the database will be executed to load the missing data.
But if you know before you query for the Book that you need the column photo immediately, you can still override the deferred behavior with undefer option: query = session.query(Book).options(undefer('photo')).get(1).
Basically, the suggestion here is to defer all the columns (in your case: except username, password etc) and in each use case (view) override with undefer those you know you need for that particular view. Please also see the group parameter of deferred, so that you can group the attributes by use case (view).
Another way would be to query only some columns, but in this case you are getting the tuple instance instead of the model instance (in your case User), so it is potentially OK for form filling, but not so good for model validation: session.query(Book.id, Book.title).all()