I am trying to create a string of the key of a ReferenceProperty within a webapp template:
Assume the following simple datastore model:
def User(db.Model):
first_name = StringProperty()
last_name = StringProperty()
def Email(db.Model):
user = ReferenceProperty(User)
email = EmailProperty()
I then pass a list of Email entities to a webapp template in list named member_list. Within the template, I want to create a string of the key of each Email entity's 'user' property for use in a URL, such as:
{% for member in member_list %}
<a href="/member_handler/{{INSERT_STRING_OF_MEMBER.USER_KEY_HERE"}}>blah</a>
I realize I could pass a string of the key to the template, but I would prefer to do the string conversion in template if possible; I have tried various permutations of str() and _ str_ to no avail.
Since you know the entity in question will be a Member instance, and presumably won't have a parent entity, it's much simpler (and produces nicer URLs) to use the key name or ID of the member, rather than the full string key. You can get this with user.key().name() (user.key.name in a Django template) or user.key().id(). Which one you need depends on whether you created the entity with a key name or not.
If you have an email object, there's no need to fetch the User from it just to get its key. Instead, call Email.user.get_value_for_datastore(member), which will return the Key object of the User it references. You can then extract the relevant field as you wish. There's no way to do this in Django, though, so you'll either need to do it outside Django and pass it in, or add a method to the Email class that returns the key.
Once you have an ID or Name and want to fetch the User object it references, call User.get_by_id(id) or User.get_by_key_name(name) as appropriate.
member.user.key should do the trick:
{% for member in member_list %}
<a href="/member_handler/{{member.user.key"}}>blah</a>
blah
Related
Currently I am reading
Django 4 By Example - Fourth Edition
We are creating a Post model in blog app.
The table is named as blog_post as per the sqlmigrate commands.
But when we add a ForeignKeyfrom Post to User model by
author = models.ForeignKey(User, on_delete=models.CASCADE,
related_name='blog_posts')
the related_name is blog_posts instead of blog_post.
Why is it in plural instead of the actual table name?
The related_name=… parameter [Django-doc] is used to query items in reverse. In this case it means that for a given User (author), you can retrieve all the Posts that author has written with:
my_user.blog_posts.all()
Since there can be zero, one, or more such Posts, this is a collection, and hence it is usually written in plural form. my_user.blog_post.all() would hint that this is a single item, which is not the case.
If you do not specify a name, the default for related_name=… will be modelname_set, with modelname the name of the model in lowercase, so post_set, again to hint that this is a collection of Post objects.
For a OneToOneField [Django-doc] the related_name=… is usually singular, since then there would only be at most one such Post. The default for the related_name=… for a OneToOneField is therefore modelname, so here it would be post.
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
I'm new to django and am having trouble reading data from a model in a template.
Here's the model.
class Team(models.Model):
team_name = models.CharField(max_length=30, default="Team")
created = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return self.team_name
The view.
def create_team(request):
team = Team.objects.all()
return render_to_response("ideas/profile.html", {'team':team})
And the template.
<h2>Available groups: {{team.team_name}} </h2>
Likelihood this is an obvious fix: 99%. Thanks anyway guys!
team is not an object, it's a queryset -- simplistically, a list of objects. Even if there's only one object in the table, it's simply a list of one. As a result, you can't just reference model attributes on it as if it were an instance of the model -- you have to pull the instance out first:
{% for t in team %}
{{ t.team_name }}
{% endfor %}
A couple of notes. As the loop shows, naming it team doesn't make sense. That implies one thing, and now we're going to loop through a single entity? Best practice here is to name single items singular and querysets, lists, etc. plural. Then we would do for team in teams which makes a lot more sense.
Secondly, don't use the model name in the attribute name. team.team_name is redundant, when team.name would work just as well. If there's another "name" attribute, then prefix that one, but the model itself should have priority on top-level attribute names.
I am trying to load an entity by key using the id it was assigned by the datastore but I don't see any api method to do this (using NDB). I thought I would be able to make a Key from an integer id and use key.get() to load the entity, but I don't see a way to make a key from just an id. I suspect I am missing something obvious here. How should I load an entity where I only know the id of it?
Another way: ndb.Key(YourModel, id).get().
YourModel.get_by_id() gets a model instance by id.
here the docs:
https://developers.google.com/appengine/docs/python/ndb/modelclass#Model_get_by_id
don't think you can't get an entity by id without knowing the kind because instances of different Model classes can have the same id/key_name
Models in NDB don't define their key type as part of the model. This is nifty in that you can have one given model type that is accessible through multiple different kinds of keys and parents, which makes them more flexible. But it's somewhat problematic because it isn't always clear what the key represents or where it comes from.
So in cases where there's only ever one kind of key for a given model (which is almost every model), I like to create a class method for generating that key, which adds a bit of semantic clarity:
class Book(ndb.Model):
title = ndb.StringProperty()
pages = ndb.IntegerProperty()
#classmethod
def make_key(cls, isbn):
return ndb.Key(cls, isbn)
b = Book.make_key('1234-5678').get()
Sure the added code is not strictly necessary, but it adds clarity and makes my models more long-term maintainable.
You can parse the id to key string:
key = ndb.Key(YourModel, id).urlsafe().
and then:
result = YourModel.query(YourModel.key== key).get().
I have 5 types of objects in an application let's say A, B , C, D, E
The application lists objects of all type, where it shows their name, created user and other Info.
Now, to be able to show user's name in every object listing, I have some options
1) Store the USER entity key in every object and then when I retrieve say list of Objects of type A, then also retrieve user's keys and their names and then attach them to objects of type A
2) When a object of any type is created, also store a property "Name" which will be name of user who created the object (Yikes approach IMHO, what if the user changes his name later ;)
But I am not convinced both ways above are right! I am looking for an answer, from someone who might have faced similar problem
Actually you've already answered yourself, option 2 is not advisable, since an user can change his/her username, and cascading the change (manually) in the DataStore is not a good choice.
http://code.google.com/appengine/docs/python/datastore/typesandpropertyclasses.html#ReferenceProperty
Example from the link:
class Author(db.Model):
name = db.StringProperty()
class Story(db.Model):
author = db.ReferenceProperty(Author)
story = db.get(story_key)
author_name = story.author.name
author = db.get(author_key)
stories_by_author = author.story_set.get()
The option1 can be done easily with ReferenceProperty.
No extra code needed if the performance is not your major concern.
I haven't use java on Google App Engine,
but google app engine did support object relationship you needed as well.
http://code.google.com/appengine/docs/java/datastore/jdo/relationships.html#Owned_One_to_One_Relationships
I want to ensure an object is unique, and to throw an error when a user tries to save it (e.g. via the admin) if not? By unique, I mean that some of the object's attributes might hold the same values as those of other objects, but they can't ALL be identical to another object's values.
If I'm not mistaken, I can do this like so:
class Animal(models.Model):
common_name = models.CharField(max_length=150)
latin_name = models.CharField(max_length=150)
class Meta:
unique_together = ("common_name", "latin_name")
But then each time I refactor the model (e.g. to add a new field, or to change the name of an existing field), I also have to edit the list of fields in the parenthesis assigned to unique_together. With a simple model, that's OK, but with a substantial one, it becomes a real hassle during refactoring.
How can I avoid having to repeat typing out the list of field names in the unique_together parenthesis? Is there some way to pass the list of the model's fields to a variable and to assign that variable to unique_together instead?
Refactoring models is a rather expensive thing to do:
You will need to change all code using your models since field names correspond to object properties
You will have to change your database manually since Django cannot do this for you (at least the version I used the last time when I worked with Django couldn't)
Therefore I think updating the list of unique field names in the model meta class is the least issue you should worry about.
EDIT: If you really want to do this and all of your fields must be "unique together", then the guy at freenode is right and you'll have to write a custom metaclass. This is quite complicated and errorprone, plus it might render your code incompatible to future releases of Django.
Django's ORM "magic" is controlled by the metaclass ModelBase (django.db.models.base.ModelBase) of the generic base class Model. This class is responsible to take your class definition with all fields and Meta information and construct the class you will be using in your code later.
Here is a recipe on how you could achieve your goal:
Subclass ModelBase to use your own metaclass.
Override the method __new__(cls, name, bases, dict)
Inspect dict to gather the Meta member (dict["Meta"]) as well as all field members
Set meta.unique_together based on the names of the fields you gathered.
Call the super implementation (ModelBase.__new__)
Use the custom metaclass for all your unique models using the magic member __metaclass__ = MyMetaclass (or derive an abstract base class extending Model and overriding the metaclass)