Multiple Tables & Modified Querysets - django-models

I've got to keep an inventory of servers and their memory modules & drives. I've created three tables. I want to be able to retrieve all information about the server, including memory and drive information, and display it in one page.
class Server(models.Model):
Name = models.CharField(max_length=25)
ServiceTag = models.CharField(primary_key=True,max_length=12) #Uniquely identifies each server
def __unicode__(self):
return u'%s %s ' % (self.Name, self.ServiceTag)
class MemoryModule(models.Model):
Manufacturer = models.CharField(max_length=15)
Size = models.CharField(max_length=15)
server = models.ForeignKey(Server, max_length=12)
mems = MemoryManager()
def __unicode__(self):
return u'%s %s' % (self.Manufacturer, self.Size)
class Drive(models.Model):
Manufacturer = models.CharField(max_length=15)
Size = models.CharField(max_length=15)
server = models.ForeignKey(Server, max_length=12)
drvs = DriveManager()
def __unicode__(self):
return u'%s %s %s %s %s' % (self.Manufacturer, self.Size)
I was considering adding the following "managers":
class MemoryManager(models.Manager):
def get_query_set(self):
return super(MemoryManager, self).get_query_set().filter(server='CC98361')
class DriveManager(models.Manager):
def get_query_set(self):
return super(DriveManager, self).get_query_set().filter(server='CC98361')
...so that the following would generate memorymodules & drives associated with the service tag value:
MemoryModule.mems.all()
Drive.drvs.all()
a. Is this an accurate approach
b. if so, how would I display "MemoryModule.mems.all() and Drive.drvs.all() in a template?

a. This looks correct, but have you tested it? With django models, there's more overhead to see if your code runs than there would be with python. I see no obvious errors; this looks by-the-book.
b. I would try something like:
<table>
{% for mem in MemoryModule.mems.all %}
<tr>
<td>{{ mem.Manufacturer }}</td>
<td>{{ mem.Size }}</td>
<td>{{ mem.drvs }}</td>
</tr>
{% endfor %}
</table>
EDIT
Oops! My mistake. The django template engine doesn't want anything that looks like functions. It's too developerish. At worst, it allows you to call functions, but only if they take no arguments and only if they don't look like function calls. Hence, no parentheses. That said, you still need to make MemoryModule visible, i.e. pass {"MemoryModule": models.MemoryModule} into the dictionary. Better yet would be to pass {"mems":models.MemoryModule.mems.all()} and just call {% for mem in mems %} in the template.

Related

iterating through a Django model field produces unwanted format

Python3.4 Django1.9 Noob here... :)
I am trying to loop through a Django field but am not getting the desired results, here's the picture:
the models field "info" can hold strings and in some cases python lists. My issue in this case is when it's a list and I have to iterate through it...
e.g.:
say the "info" field has something like this: ['2016-02-23', '2016-03-01'] and I try to loop through it on the Django1.9 template like this:
{% for i in dates %} {{i}}<br /> {% endfor %}
I expect to see something like this:
2016-02-23
2016-03-01
instead I get this:
[
'
2
0
1
6
-
0
2
-
2
3
'
,
'
2
0
1
6
-
0
3
-
0
1
'
]
which makes me think the mySQL field holding the data is fooling me into thinking this is a python list... my ability to change the format of the database field are limited... any help would be appreciated!
models.py
class Events(....
info = models.CharField(max_length=150, blank=True)
views.py
dates_list = []
obj_dates = Events.objects.filter(id=id)
for i in obj_dates:
dates_list.append(i.info)
context = {"dates": dates_list)
Django 1.9 template
{% for i in dates %} {{i}} {% endfor %}
just looking at your code
obj_dates = Events.objects.filter(id=id)
is only going to get you one entry (as you are filtering by id) - you are returning a queryset with only one object.
When you use:
for i in obj_dates:
dates_list.append(i.info)
you are appending a string "['2016-02-23', '2016-03-01']"
to dates_list. That is to say that dates_list is just a list containing a single string - it appears to be a list containing a list but it is a list containing a string.
in python strings are iterable, so the template is iterating through one character in the string at a time, thus returning you
[
'
2
...
Solutions
A. The hacky way
dates_list.append(list(i.info))
that will convert that string "['2016-02-23', '2016-03-01']" into a list
B. a more django-ish approach
Ask yourself can you store dates in a better fashion that as text in a charfield?
One way to do it is to use a dateField then use m2m so you can store multiple dates.
class Events(models.Model)
info = models.CharField(max_length=150, blank=True)
dates = models.ManyToManyField(Dates, related_name='events', blank=True)
class Dates(models.Model)
date = models.DateField(auto_now=False, auto_now_add=False)
Thanks to luke_aus for the help!
I also found something that could work in some cases...
If you see yourself in a situation having to unpack or loop through a Python list stored in a CharField, try this... it worked very well in my case...
Views.py
import ast
date_list = []
for i in obj:
l = {
'dates': ast.literal_eval(i.info), # i.info is a CharField containing a python list
}
dates_list.append(l)
Template
{% for d in dates %}
{{d}}<br>
{% endfor %}
2016-02-23
2016-03-01

Extract HTML table content based on "thead"

Here is a basic HTML table :
<table>
<thead>
<td class="foo">bar</td>
</thead>
<tbody>
<td>rows</td>
…
</tbody>
</table>
Suppose there are several such tables in the source file. Is there an option of hxextract, or a CSS3 selector I could use with hxselect, or some other tool, which would allow to extract one particular table, either based on the content of thead or on its class if it exists ? Or am I stuck with not so simple awk (or maybe perl, as found before submitting) scripting ?
Update :
For content-based extraction, perl's HTML::TableExtract does the trick :
#!/usr/bin/env perl
use open ':std', ':encoding(UTF-8)';
use HTML::TableExtract;
# Extract tables based on header content, slice_columns helpful if colspan issues
$te = HTML::TableExtract->new( headers => ['Multi'], slice_columns => 0);
$te->parse_file('mywebpage.html');
# Loop on all matching tables
foreach $ts ($te->tables())
{
# Print table identification
print "Table (", join(',', $ts->coords), "):\n";
# Print table content
foreach $row ($ts->rows)
{
print join(':', #$row), "\n";
}
}
However in some cases a simple lynx -dump mywebpage.html coupled wih awk or whatever can be just as efficient.
This would require a parent selector or a relational selector, which does not as yet exist (and by the time it does exist, hxselect may not implement it because it does not even fully implement the current standard as of this writing). hxextract appears to only retrieve an element by its type and/or class name, so the best it'd do is td.foo, which would return the td only, not its thead or table.
If you are processing this HTML from the command line, you will need a script.

If I return an array in Ruby can I call .each on it?

I have this method in my Artist model
def upcomingEvents
#remote = Songkickr::Remote.new 'asdf123asdf'
id = #remote.artist_search(:name).results.first.id
artistConcerts = #remote.artist_events(id, :per_page => '10').results
return artistConcerts
end
Which should return 10 results from the API call I make.
Then in my view I'm trying to do a .each call to iterate through the 10 returns objects.
<% #concert.artist.upcomingEvents.each do |event| %>
<p><%= link_to event.display_name + " " + event.location.city, event.uri, :target => "_blank"%></p>
<% end %>
the .display_name and .city and .uri methods are built into the gem I'm using that's an API wrapper. When I try to do this nothing gets printed though so I just wanted to make sure what I was trying to do is possible, and if not, how can I do it?
Yes you call each on an array. If you have any doubts you can simply check the ruby (or rails) doc: http://www.ruby-doc.org/core-2.1.1/Array.html
P.s. I would write tests for every step if I were you. This way you can see if every part is returning the right result. Without tests you could use binding.pry to check for unexpected outcomes. In your case I wonder if #concert.artist.upcomingEvents returns anything but an empty array.

How to get length of (or count) of datastore entities through a reference collection definition in google datastore from client side

I have 1 to many datastore relationship between 2 Entities (google datastore) --- i.e. an instance in the Restaurant_Table can have many reviews from the Review_Table - as labeled by collection "restaurant_reviews"
As I spin through each restaurant (in a loop) to a list each of them in my template through jinja, I want to display the number or count of reviews there are for a single restaurant. All restaurants are passed from server in the form of a query from the datastore in variable restaurants as shown in the jinja2 logic in my template.
I'm getting an error that the query object TypeError: object of type 'Query' has no len(). Any other ideas on how to get the # of reviews for a single restaurant?? help!
{% for each in restaurants %}
<script>
var html_output = "";
var review_count ={{each.restaurant_reviews|length}};
...
{% endfor %}
DATASTORE ENTITY definition is:
class Review_Table(db.Model):
date_submission = db.DateTimeProperty(required=True, indexed=True)
course_id = db.ReferenceProperty(Restaurant_Table,
indexed=True, collection_name='restaurant_reviews')
To get the number of entities represented by the query you can use the count method:
db.Query(Kind).count()
You can't do this within a jinja template -- you would need to build your output in your handler, and then render to your template.
However, as the docs say the .count() method "is faster by a constant factor than actually retrieving all of the results, but the running time still scales linearly with the sum of offset + limit." Meaning, this could get really, really slow if you get a large number of restaurants/ reviews.
A better option, in my opinion, would be to add an extra property to your Restaurants model "num_reviews", which your handler would update every time a new review is added -- making very slightly more expensive/slower writes would become hugely cheaper/faster reads because no extra querying would have to be done.
Performance could be an issue, but this will accomplish the task:
var review_count = {% for n in restaurant_reviews %}{% if loop.index == 1 %}{{ loop.length }}{% endif %}{% endfor %};

Django Models - Conditionally adding an object to a ManyToManyField before saving

The following does not quite work, its purpose is:
Upon save, check for the existence of 'supervisor' in the 'operators', and add it too them if not.
class JobRecord(models.Model):
"""JobRecord model"""
project = models.ForeignKey(Project)
date = models.DateField()
supervisor = models.ForeignKey(User, related_name='supervisor_set')
operators = models.ManyToManyField(User, related_name='operators_set', help_text='Include the supervisor here also.')
vehicles = models.ManyToManyField(Vehicle, blank=True, null=True)
def __unicode__(self):
return u"%s - %s" % (self.project.name, self.date.strftime('%b %d'))
# --- over ride methods ---- #
def save(self, **kwargs):
# this must be done to get a pk
super(JobRecord, self).save(**kwargs)
# which makes this comparison possible
if self.supervisor not in self.operators.__dict__:
self.operators.add(self.supervisor)
# it seems to get this far ok, but alas, the second save attempt
# does not seem to work!
print self.operators.values()
super(JobRecord, self).save(**kwargs)
Thanks for your expertise, would be 'expert'!
You can do something like this to check if the supervisor is in the operators:
if self.operators.filter(id=self.supervisor.id).count() == 0:
And you don't need to save a second time after modifying the many to many field. (Many to many relations are stored in their own table.)
Ok, I've modified the to make the following. Actually, either conditional seems to do the trick. The issue now is that the add() method is not working for me.
#...
def save(self, **kwargs):
super(JobRecord, self).save(**kwargs)
if self.operators.filter(id=self.supervisor.id).count() == 0:
#if self.supervisor not in self.operators.values():
# either conditional will get to this point
self.operators.add(self.supervisor) # <-- this line doesn't save proper?
i have the same issue. if you are using a django form, do your check after the form is saved, and then add the many to many there. that was the only way i could get around it.

Resources