Can you access a parent field from a child object in Django? - python

tl;dr: I want to express something like [child.child_field_value, child.parent_field_value] on a Django child model and get an iterable like ['Alsatian', 'Dog'] or similar.
Context: I'm trying to prepare a dict for a JSON API in Django, such that I have two models, Evaluation and its parent Charity.
In the view I filter for all Evaluations meeting certain parameters, and then use a dict comp nexted in a list comp on evaluation.__dict__.items() to drop Django's '_state' field (this isn't the focus of this question, but please tell me if you know a better practice!):
response = { 'evaluations': [{
key:value for key, value in evaluation.__dict__.items()
if key not in ['_state']} for evaluation in evaluations]}
But I want a good way to combine the fields charity_name and charity_abbreviation of each Evaluation's parent charity with the rest of that evaluation's fields. So far the best way I can find/think of is during the dict comp to conditionally check whether the field we're iterating through is charity_id and if so to look up that charity and return an array of the two fields.
But I haven't figured out how to do that, and it seems likely to end up with something very messy which isn't isn't functionally ideal, since I'd rather that array was two key:value pairs in line with the rest of the dictionary.

Related

How to add an entry to firebase using requests module?

I have a firebase database that holds a list of words, so has structure like this:
words_to_add
--words
----0:'hello'
----1:'goodbye'
so basically its {words: ['hello','goodbye']}.
I want to add to this dictionary so that its holds additional words.
I have tried to use requests.patch("Firebase_URL", data= '{"words":"[new_list_of_words]"}' and with requests.put() but they overwrite the contents of words to a string of the list which isn't what I want. How could I just add another entry to list?
A path request to the REST API of the Realtime Database takes each key in the dictionary you pass to it and writes the value from your request into the database for that key. Since you specify words as the key, all existing words will be replaced.
You can perform a deep update by providing a path as the key, so for example data= '{"words/2": "banana", "words/3": "pie"}'. Although I haven't tested this on arrays, it should add the second and third element to the array.
The problem with this is of course is that you'd have to know (and agree with any other users) on how many items there currently are in the array, leading to all kinds of possible problems. This is one of the many reasons that Firebase recommends against using arrays in it's vintage blog post: Best Practices: Arrays in Firebase.
In this case, the better structure would be to use a map like his for the words in your database:
words: {
"hello": true,
"goodbye": true
}
The true value here is just needed since Firebase won't store a key without a value and has no real meaning.
Now that we have a map of words, you can path it with:
requests.patch("Firebase_URL", data='{"words/banana":true, "words/pie":true}'

How can I query for multiple properties not known in advance using Expando?

I'm making an application in which a user can create categories to put items in them. The items share some basic properties, but the rest of them are defined by the category they belong to. The problem is that both the category and it's special properties are created by the user.
For instance, the user may create two categories: books and buttons. In the 'book' category he may create two properties: number of pages and author. In the buttons category he may create different properties: number of holes and color.
Initially, I placed these properties in a JsonProperty inside the Item. While this works, it means that I query the Datastore just by specifying the category that I am looking for and then I have to filter the results of the query in the code. For example, if I'm looking for all the books whose author is Carl Sagan, I would query the Item class with category == books and the loop through the results to keep only those that match the author.
While I don't really expect to have that many items per category (probably in the hundreds, unlikely to get to one thousand), this looks inefficient. So I tried to use ndb.Expando to make those special properties real properties that are indexed. I did this, adding the corresponding special properties to the item when putting it to the Datastore. So if the user creates an Item in the 'books' category and previously created in that category the special property 'author', an Item is saved with the special property expando_author = author in it. It worked as I expected until this point (dev server).
The real problem though became visible when I did some queries. While they worked in the dev server, they created composite indexes for each special/expando property, even if the query filters were equality only. And while each category can have at most five properties, it is evident that it can easily get out of control.
Example query:
items = Item.query()
for p in properties:
items = items.filter(ndb.GenericProperty(p)==properties[p])
items.fetch()
Now, since I don't know in advance what the properties will be (though I will limit it to 5), I can't build the indexes before uploading the application, and even if I knew it would probably mean having more indexes that I'm comfortable with. Is Expando the wrong tool for what I'm trying to do? Should I just keep filtering the results in the code using the JsonProperty? I would greatly appreciate any advice I can get.
PD. To make this post shorter I omitted a few details about what I did, if you need to know something I may have left out just ask in the comments.
Consider storing category's properties in a single list property prefixed with category property name.
Like (forget me I forgot exact Python syntax, switched to Go)
class Item():
props = StringListProperty()
book = Item(category='book', props=['title:Carl Sagan'])
button = Item(category='button', props=['wholes:5'])
Then you can do have a single composite index on category+props and do queries like this:
def filter_items(category, propName, propValue):
Item.filter(Item.category == category).filter(Item.props==propName+':'+propValue)
And you would need a function on Item to get property values cleaned up from prop names.

Django: Iterating over multiple instances of a single model in a view

I'm relatively new to Django and face a problem that I couldn't solve yet:
I have two models which look like:
class Item(models.Model):
char1 = models.CharField(max_length=200)
char2 = models.CharField(max_length=200)
class Entry(models.Model):
item = models.ForeignKey(Item)
choice = models.IntegerField()
I have stored many Items in my database, and I want basically in one view to randomly iterate through all the stored Items, and for each Item display char1 and char2 with an IntegerField and a 'next' button, that stores a new Entry (with the actual Item, and typed integer) in my database and directs me to the next (random) Item.
During research I found for example the form wizard and formsets, but this is not what I want, the wizard needs multiple form models that he can display successive, but I want to display (randomly) each instance of only one model (Item) and store one Entry for each.
I hope someone can give me a hint where to look for, because nowhere I found a documentation/tutorial for this use case, and since I'm not very experienced with Django, I can't figure it out at the moment...
Best regards and thanks in advance!
Judging by your title, the problem is the iterating over multiple items from a single (possibly random/unsorted) model.
If I'm not mistaken, what you are looking for is Pagination. From that text, a small example is:
>>> from django.core.paginator import Paginator
>>> objects = ['john', 'paul', 'george', 'ringo']
>>> p = Paginator(objects, 2)
>>> p.count
4
>>> p.num_pages
2
>>> p.page_range
[1, 2]
Although a list is shown above, Paginator can also be used on Django QuerySets, and it's functionality incorporated into Django Templates.
Let me know if this isn't what you're after.
Cheer.
Paulo Bu's answer provides the way to get the random ordering in the first place from Django's AP. The tricky part about what you're doing is that it's not really RESTful to save the particular random ordering of the items between page loads, because that is not stateless. By default, your randomly ordered queryset is going to fall out of existence as soon as you serve the request, and there will be no guarantee that you will circulate through all the items instead of getting repeats and misses. So you'll want to save that ordering. There are a bunch of options for how you might approach this:
Serve the entire randomized list of item IDs with every request, and have the backend serve up the data for the current item by index
Serve all of the data -- full items and entries -- then you can either render everything client-side
Store the randomized list as a session variable
Store a permanent random ordering of the items by adding a float between 0 and 1 to every Item, ordering on that float, and starting at a random index (if you don't care whether each user has the same overall permutation)

'if' element is not in list on Google App Engine

I am building an application for Facebook using Google App Engine. I was trying to compare friends in my user's Facebook account to those already in my application, so I could add them to the database if they are friends in Facebook but not in my application, or not if they are already friends in both. I was trying something like this:
request = graph.request("/me/friends")
user = User.get_by_key_name(self.session.id)
list = []
for x in user.friends:
list.append(x.user)
for friend in request["data"]:
if User.get_by_key_name(friend["id"]):
friendt = User.get_by_key_name(friend["id"])
if friendt.key not in user.friends:
newfriend = Friend(friend = user,
user = friendt,
id = friendt.id)
newfriend.put()
graph.request returns an object with the user's friends. How do I compare content in te two lists of retrieved objects. It doesn't necessarily need to be Facebook related.
(I know this question may be quite silly, but it is really being a pain for me.)
If you upgrade to NDB, the "in" operator will actually work; NDB implements a proper eq operator on Model instances. Note that the key is also compared, so entities that have the same property values but different keys are considered unequal. If you want to ignore the key, consider comparing e1._to_dict() == e2._to_dict().
You should write a custom function to compare your objects, and consider it as a comparison of nested dictionaries. As you will be comparing only the attributes and not functions, you have to do a nested dict comparison.
Reason: All the attributes will be not callable and hopefully, might not start with _, so you have to just compare the remaining elements from the obj.dict and the approach should be bottom up i.e. finish off the nested level objects first (e.g. the main object could host other objects, which will have their own dict)
Lastly, you can consider the accepted answer code here: How to compare two lists of dicts in Python?

singular or plural identifier for a dictionary?

When naming a container , what's a better coding style:
source = {}
#...
source[record] = some_file
or
sources = {}
#...
sources[record] = some_file
The plural reads more natural at creation; the singular at assignment.
And it is not an idle question; I did catch myself getting confused in an old code when I wasn't sure if a variable was a container or a single value.
UPDATE
It seems there's a general agreement that when the dictionary is used as a mapping, it's better to use a more detailed name (e.g., recordToSourceFilename); and if I absolutely want to use a short name, then make it plural (e.g., sources).
I think that there are two very specific use cases with dictionaries that should be identified separately. However, before addressing them, it should be noted that the variable names for dictionaries should almost always be singular, while lists should almost always be plural.
Dictionaries as object-like entities: There are times when you have a dictionary that represents some kind of object-like data structure. In these instances, the dictionary almost always refers to a single object-like data structure, and should therefore be singular. For example:
# assume that users is a list of users parsed from some JSON source
# assume that each user is a dictionary, containing information about that user
for user in users:
print user['name']
Dictionaries as mapping entities: Other times, your dictionary might be behaving more like a typical hash-map. In such a case, it is best to use a more direct name, though still singular. For example:
# assume that idToUser is a dictionary mapping IDs to user objects
user = idToUser['0001a']
print user.name
Lists: Finally, you have lists, which are an entirely separate idea. These should almost always be plural, because they are simple a collection of other entities. For example:
users = [userA, userB, userC] # makes sense
for user in users:
print user.name # especially later, in iteration
I'm sure that there are some obscure or otherwise unlikely situations that might call for some exceptions to be made here, but I feel that this is a pretty strong guideline to follow when naming dictionaries and lists, not just in Python but in all languages.
It should be plural because then the program behaves just like you read it aloud. Let me show you why it should not be singular (totally contrived example):
c = Customer(name = "Tony")
c.persist()
[...]
#
# 500 LOC later, you retrieve the customer list as a mapping from
# customer ID to Customer instance.
#
# Singular
customer = fetchCustomerList()
nameOfFirstCustomer = customer[0].name
for c in customer: # obviously it's totally confusing once you iterate
...
# Plural
customers = fetchCustomerList()
nameOfFirstCustomer = customers[0].name
for customer in customers: # yeah, that makes sense!!
...
Furthermore, sometimes it's a good idea to have even more explicit names from which you can infer the mapping (for dictionaries) and probably the type. I usually add a simple comment when I introduce a dictionary variable. An example:
# Customer ID => Customer
idToCustomer = {}
[...]
idToCustomer[1] = Customer(name = "Tony")
I prefer plurals for containers. There's just a certain understandable logic in using:
entries = []
for entry in entries:
#Code...

Categories