Django ownership foreign key to User or UserExtenstion - database

I'm quite new with Django, and so far I have a pretty basic setup where I attach an extra model to the default User model from (django.contrib.auth.models). In my accounts.models.py I have something in the line of:
class UserExtension(models.Model):
user = models.OneToOneField(User, primary_key=True)
# more code
I also have another model which needs to be specified an owner. My question is: Which is the better (more django-ish, more readable, more efficient, more flexible) way to signify the owner:
class Owned(models.Model):
# code
owner = models.ForeignKey(User)
# more code
or:
class Owned(models.Model)
# code
owner = models.ForeignKey(UserExtension)
# more code
I'll really appreciate if you mention pros and cons of those approaches.

I'd recommend the first option. The user model is the nontrivial model in the sense that an owned object should not be able to exist without a user, but could exist without a UserExtension.
Also consider that in Django 1.5 you are able to create custom user model, eliminating the need for the UserExtension class. See the documentation for more information.

Consider using UserProfile for any per user add-on information. Check out this blog to see how to do it. Then you can be assured that you are creating UserProfile object every time you create the User.
Now whether you FK on User or UserProfile depends logically on what you are doing within Owned. If Owned works with User's data/field, FK on User; if it works with UserProfile's data, FK on UserProfile.

Related

Django, relate User with another table

So I got the tables you can see in the image below:
.
What I would like to do is to create a relationship so that each user (of django auth_user) will be enrolled(or able to enrol) to exactly one "course" so that he will be able to see next events for his modules.
Do I have to create another table and place 2 foreign keys or this is a way to do it in 'php' and it's more simple with Django? I was suggested to create 'student' model inheriting from 'User' with extended behavior and one to many relationship on auth. I tried to do that but unfortunately had not results since I'm really new to Django & Python.
If every auth_user (or auth.User) will be or have the opportunity to be enrolled on a course I would create a 'user profile' model that has a 1-to-1 relationship with the django User model. You can store additional User data in this model, including what course they are enrolled on. See https://docs.djangoproject.com/en/dev/topics/auth/customizing/#extending-the-existing-user-model for more details but here is an example:
class UserProfile(models.Model):
user = models.OneToOneField('auth.User')
course = models.ForeignKey('courseapp.Course', null=True)
You would probably need to create a signal that gets fired each time an auth.User object is saved, such that if it is the first time that User object has been saved, it automatically creates the UserProfile:
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from yourusersapp.models import UserProfile
def create_user_profile(sender, instance, created, **kwargs):
# Automatically creates a UserProfile on User creation.
if created:
UserProfile.objects.create(user=instance)
post_save.connect(create_user_profile, sender=User)
When you query a User object, you can then reference the User object's profile like:
user_object.userprofile
You could then create a Course object and link the user_object indirectly via its UserProfile to that Course:
course = Course.objects.create(name='course_name', next_field='whatever')
user_profile = user_object.userprofile
userprofile.course = course
userprofile.save()
Now you have a user object with a UserProfile that is linked to only 1 course. Many users can be on the same course, but a user can only be on 1 course. You can also reference all users on a particular course like:
course = Course.objects.get(name='course_name')
course_users = course.userprofile_set.all()
HTH
I think that you can go about this one of two ways.
Extend the User model. 'Student' would probably be a good name for your new model. It would have a OneToOne relationship with 'User', and a ForeignKey relationship with 'Course'. It can store any other information that is applicable to students only. Documentation for how to do that can be found here https://docs.djangoproject.com/en/1.6/topics/auth/customizing/#extending-the-existing-user-model
Create a custom User model that has a ForeignKey relationship with Course. This approach is a bit more complicated, but yields a slightly cleaner end result. Documentation for that is here. https://docs.djangoproject.com/en/1.6/topics/auth/customizing/#substituting-a-custom-user-model
Sorry if it seems like I'm just sending you to the Django docs, but both of those sections are well written and should explain things pretty clearly. If you'd like to post another question with example code we can try and see why your original attempt at extending the User model didn't work. By the way, your "Student" model shouldn't have to inherit from the User model in order to extend it.

app engine ndb - how to load entity by key using id?

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().

Custom South migration with custom fields - Django

I am pretty new to Django and just got a job that involves maintaining and adding features to a site I did not design, so I am still kind of confused about the structure and what not of the project. The site is using South for database migrations and I've got a hang of using it to add new applications to the project. The trouble I am having now is that I need to delete a certain field in a model because it is no longer needed and on the admin page it is required to be filled out. From my understanding of Django so far it appears to be a custom field. It is defined like this in its own separate library application(still not sure if thats the right lingo).
class Genre(models.Model):
name = models.CharField(max_length=255)
def __unicode__(self):
return u"%s" % self.name
Here is the models that uses the custom field if that helps out any.
class Entry(models.Model):
artist = d51fields.ForeignKey(Artist, instantiate_fn=instant_artist)
album = d51fields.ForeignKey(Album, js_methods=['match_artist_and_startswith'], instantiate_fn=instant_album)
track = d51fields.ForeignKey(Track, js_methods=['match_album_and_startswith'], instantiate_fn=instant_track)
genre = models.ForeignKey(Genre)
submitted = models.DateTimeField(auto_now_add=True)
is_rotation = models.BooleanField()
dj = models.ForeignKey(DJ)
show = models.ForeignKey(Show, null=True, blank=True)
objects = EntryManager()
def __unicode__(self):
return "%s [%s]" % (self.artist, self.track)
class Meta:
verbose_name = "entry"
verbose_name_plural = "entries"
I've looked at the documentation for migrating custom fields but it is all really confusing for me, so I am looking for some more help. I just want to get rid of the table holding the Genre field and clean up the dependencies with the foreign keys associated with it. Do you think I should write some custom rules for South and use a migration or just try and do it manually in Postgresql. I tried doing it with just Postgres and I failed miserably.
Any guidance would be greatly appreciated. If you want more info about the situation just ask and I can add it to the post. I have a feeling there is a lot of dependencies I will have to deal with, but hopefully there is a simple fix.
Also if some one knows how to get a good view of the database structure that would be great.
Thanks so much. All of you guys are great.
Edit1
Here what I got when I removed the ForeignKeys and then ran
manage.py schemamigration logs --auto
! Cannot freeze field 'logs.entry.artist'
! (this field has class d51_admin_autofk.fields.ForeignKey)
! Cannot freeze field 'logs.entry.album'
! (this field has class d51_admin_autofk.fields.ForeignKey)
! Cannot freeze field 'logs.entry.track'
! (this field has class d51_admin_autofk.fields.ForeignKey)
! South cannot introspect some fields; this is probably because they are custom
! fields. If they worked in 0.6 or below, this is because we have removed the
! models parser (it often broke things).
I am not totally sure what sort of action I should take next. I looked into the South documentation and it wasn't too clear about how to write the rules for migrating things like this.
I don't see any custom field anywhere in the code you posted. All I see is two models, all containing standard fields shipped with Django.
If I understand correctly, you can just delete all ForeignKey references to your Genre model. Then run ./manage.py schemamigration <yourappname> --auto. This will ask you for a default value for the genre field in the Entry model, provide an ID of some kind. (This is because migrations can be applied both forwards and backwards, so if you try to undo the migration, this is the value that will get inserted in all your model instances.)
Finally, just applying the migration should make it happen: ./manage.py migrate <yourappname>.
After that you should be safe to drop the table storing your Genre model.
Be sure to try this on a development server though, just to make sure it doesn't blow up. (-;

django related_name for field clashes

I am getting a field clash in my models:
class Visit(models.Model):
user = models.ForeignKey(User)
visitor = models.ForeignKey(User)
Error: One or more models did not validate:
profiles.visit: Accessor for field 'user' clashes with related field 'User.visit_set'. Add a related_name argument to the definition for 'user'.
profiles.visit: Accessor for field 'visitor' clashes with related field 'User.visit_set'. Add a related_name argument to the definition for 'visitor'.
what would be a sensible 'related_field' to use on visitor field? This model
basically represents the visits that take place to a
particular user's profile.
Also should I replace any of the ForeignKey's with a ManyToManyField? The logic is a bit confusing.
Edit:
This seems to fix it, but I am unsure if it's what I want. :)
class Visit(models.Model):
user = models.ForeignKey(User)
visitor = models.ForeignKey(User, related_name='visitors')
When you have a ForeignKey, it creates a property named with the model name plus _set to the referenced model. The problem here is that both foreign keys want to create a property on User named visit_set. The solution is to add related names that are different for each foreign key.
Usually, I use plurals for related names. In cases like these, I add an "as" clause to the related name:
class Visit(models.Model):
user = models.ForeignKey(User, related_name="visitsAsUser")
visitor = models.ForeignKey(User, related_name="visitsAsVisitor")
You don't want a ManyToManyField unless you can have zero or more visitors per Visit, or users per Visit.
If a visit is a strong concept in your application, then it might make sense to have it the way you defined: visit consists of a 'user user' and a 'user visitor'.
If, however, a visit is just a way in which users relate among themselves, then perhaps you should have a ManyToMany relation between users. For that purpose you should probably use ManyToManyField.symmetrical in a User Profile (in which you extend the information that comes with auth.models.User).
In any case, regarding the related_name, you may either disable the backwards relation if you won't be accessing the visits from the user, or use a sensible name such as visits_to_self on user and visits_to_others on visitor, which would allow seeing who visited a user by calling user.visits_to_self and who the user visited by user.visits_to_others.

Elegant way to store anonymous users with nick names in django?

I have a simple Post model in my django app:
class Post(models.Model):
category = models.CharField(max_length=10, choices=choices)
message = models.CharField(max_length=500)
user = models.ForeignKey(User, editable=False)
I'd like to implement the feature of having anonymous users create posts with nick names. Unfortunately django doesn't allow you to save an instance of AnonymousUser as a foreignkey to the Post class.
I was thinking of adding a "dummy" user record into the db that represents the anonymous user(id=0, or some negative number if possible) that would be used for all posts without a user. And if it is present a nullable name field would be used to represent the nickname of the anonymous user.
This solution seems a bit hacky to me. Is there any cleaner more effecient solution?
If you can identify new users by some session information, you could just create normal user accounts, pro forma so to speak - with a flag to identify them as volatile (this may lead to some regular maintenance cleanup).
If, during session lifetime, the user actually want to register, you can reuse the user account on your side and the user can keep all his data on his.
As #slacy commented and #Dominique answered; instead of rolling your own take a look at existing projects, e.g. this:
http://www.stereoplex.com/blog/introducing-django-lazysignup
Not tested , but this can help:
https://github.com/danfairs/django-lazysignup
You can add blank=True and null=True to User ForeignKey and set it to None, if user is anonymous. You just need to store the nickname somewhere.
I am new to Django. A friend told me not to use ForeignKey further stating that using CharField is ok. ForeignKey is slower than CharField, as it has some check for user info.

Resources