I am trying to create a model with a foreign key which references the django model User.
I have found that you are supposed to use this model when creating something like this:
author = models.ForeignKey(User)
however any time i try to assign this from my view with this line:
if form.is_valid():
c = form.save(commit=False)
c.author=request.user.id
c.save()
I get an error complaining about how author should come from the model User. There is no User property (at least that i (a noob working on their first django project) could find) which has the user id. what is the preferred method for linking a post to it's author in django? am i going about this completely the wrong way? is there a better way of solving this problem that i am just not thinking of?
You just assign this only not id,
c.author=request.user
For assigning user, it should be like:
c.author= User.objects.filter(id= request.user.id)[0]
Related
I'm using model_mommy with Django tests to create objects. I'm having trouble creating a model with a reverse FK. I can do it the opposite way round as a workaround, but whilst it works it doesn't look right so I wonder if I can do it the other way round?
Say I have two models, User and Profile, related via an FK from Profile to User (it's not a one to one, it's just an FK). The Profile model has a bool attribute call is_aardvark.
In model mommy I can create recipes like so:
aardvark_profile = Recipe(Profile, is_aardvark=True)
non_aardvark_profile = Recipe(Profile, is_aardvark=False)
Then I can create a User with an aardvark profile in my test with something like:
user = mommy.create_recipe(aardvark_profile).user
This doesn't seem right, as I'm creating a user via the aardvark_profile recipe. I want to create a User via some sort of User recipe ideally (maybe in future I'll have some other model FKd to User, so the above wouldn't work).
I've tried things like the below, which doesn't work:
# doesn't work
broken_aardvark_user = Recipe(User, profile_set=mommy.create_recipe(aardvark_profile)
Is this even possible? Any ideas? I could just create a helper method to do this for me if all else fails.
Thanks!
You could do this:
from model_mommy.recipe import Recipe, related
aardvark_profile = Recipe(Profile, is_aardvark=True)
aardvark_user = Recipe(User, profile_set=related('aardvark_profile'))
Hope it helped
[1] http://model-mommy.readthedocs.org/en/latest/recipes.html#recipes-with-foreign-keys
Right now I'm using Django's built in admin system to manage users, to which I've attached a profile to contain additional data using the following:
class Profile(models.Model):
user = models.OneToOneField(User, editable = False)
# Data fields here...
As it stands the User and Profile pk (and accordingly id number) will be the same if and only if the profile is created right after the user is created. I could guarantee that this would be the case during the registration process, and while that would cover most uses, creating users with the admin interface could cause mismatched ids to occur. Thus this does not seem like a very robust way to solve this problem and I'd like to hardcode the pk's to be the same. I'm not sure how to do this.
I thought the following would work:
profile_id = models.IntegerField(default=user.pk, editable = False,
primary_key = True)
But it gives me the error:
AttributeError: 'OneToOneField' has no attribute 'pk'
What's the best way to guarantee that the profile and user have the same pk? Note: I'd really rather not deal with extending the base user model as using the OneToOneField to link the two seems to be sufficient for all my needs.
Thanks!
[edit]
My reasoning for asking the question:
My immediate problem was that I wanted a dictionary of values of the User's Profile, which I was retrieving usingprofile_values = Profile.objects.filter(pk=user.id).values()[0]. This highlighted the bug, and I "hacked" around it last night using pk=user.profile.id instead. In the light of the morning this does not seem like such a terrible hack. However, it seems like having pk discrepancies could lead to quiet and hard to catch bugs down the line, and thus forcing them to match up would be a Good Idea. But I'm new to Django so I'd entirely accept that it is, in fact, never a problem if you're writing your code correctly. That said, for almost academic reasons, I'd be curious to see how this might be solved.
[/edit]
Like you already agree that it was never a problem because we have a OneToOne mapping between the two models.
So when you need to get the profile obj corresponding to a User:
profile_values = Profile.objects.get(user_id=user)
assuming,
class Profile(models.Model):
user = models.OneToOneField(User)
...
If your column name is not user, then use the corresponding name in get query.
Still if you are curious as to how to achieve same pk for both models, then we can set a signal on every save of User model. See the documentation.
def create_profile(sender, **kwargs):
if kwargs["created"]:
p = Profile(user=kwargs["instance"], ...)
p.save()
django.db.models.signals.post_save.connect(create_profile, sender=User)
create_profile() will be called every time any User object is saved.
In this function, we create Profile object only if a new User instance has been created.
If we start from blank slate, then I think this will always make sure that a Profile exists for every User and is created right after User was created; which in turn will give same pk for both models.
pk is a parameter in a filter() query, but not a field name. You probably want to use user.id.
I've overloaded admin form for a model by adding an extra-field
class MyModelAdminForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput(), required=False)
class Meta:
model = MyModel
The password field isn't exists in model and I don't want it to be stored automatically.
I want to retrieve the value of this form field in the pre_save method :
#receiver(pre_save, sender=Member)
def my_pre_save_method(sender, **kwargs):
...
Actually I don't find a way to retrieve it.
Is this possible ? And How ?
Thanks
I don't full understand what you're asking here.
Anyhow, your question is far too general to answer in full. As an overview you only 'pass' clean form data in a view i.e. when you create an instance of that object. In your case this would be 'Member'.
I would suggest you start learning Django with the tutorials. They really do help, honest.
pre_save is called from model's save and it works on form level. The field password is not a model field so this will not be available on the instance of model and hence you can't access it in pre_save.
So, you can only retrieve is in the view using cleaned_data, and then use it in some way you want.
Here is the sutuation i hit.
I have both User and ProfileUser. I would like to add additional logic to the model and since I can't add it to the Django User model, I have to add it to the ProfileUser. Currently all my models however have ForeignKey(User). Should I keep them like that or should I user ForeignKey(UserProfile) on my other models?
Example for my view if I keep the ForeignKey(User):
class myview(request):
user = request.user
userProfile = user.get_profile()
neededStuff = userProfile.get_needed_stuff()
and then in the UserProfile model:
def get_needed_stuff(self):
user= self.user # Or actually, is this right
goals = Goal.objects.get(<conditions that i wont bother writing here>)
return goals
So for this case, and for further development of the site, which foreign key should i use?
I think You should use User. UserProfile should be custom and can differ on each project. So if you will use same code for another project you can probably fail because of that. Also it is always easy to get user object in code and from that you have no problems to get profile user.get_profile() as you show (and profile is not always needed). So ingeneral I think it will be easier to use other modules and passing them just user object (or id) and not the profile.
What is also could be the solution - write your own class which will be responsible for the users. Just write methods to return profile, return stuff_needed or whatever you want and everything just by passing user object and additional parameters about what you want.
So in short, I'm for using User for Foreign keys, because in my opinion it just more logical, while the User model is always the main one (you always have it) and UserProfile is just extension.
Ignas
If you just want all the goals belonging to a specific user add a foreign key to User in your Goal model.
class Goal(models.Model):
user = models.ForeignKey(User)
def myview(request):
goals = Goal.objects.filter(user=request.user)
Or alternately save all the goals for a user on your UserProfile model and do
def myview(request):
user_profile = user.get_profile()
goals = user_profile.goals
...or use a method to do processing to calculate them
goals = user_profile.calculate_goals()
I've been pondering the same thing myself for one of my sites but i decided to use UserProfile rather than User.
Not sure if its the right decision but it just seems more flexible.
Two questions please:
I need two foreign keys back to User, one for author and one for coauthor. I have managed by setting related_name equal to + but am not sure if this is smart or the best way. Thoughts or pointers?
When making an add entry via the django admin for this model, the author choices are names like john_smith, etc. Where would I call get_full_names() from in order to display full names rather than usernames with underscores? Thanks.
from django.contrib.auth.models import User
from django.db import models
class Books(models.Model):
title = models.CharField()
author = models.ForeignKey(User)
coauthor = models.ForeignKey(User, related_name='+')
Kevin
I would change the related name to a value that is more intelligible - such as books_where_coauthor and also add a similar one of books_where_author as then you can get the relevant books by going from theuser.books_where_author.all() etc
Regarding your Admin query, you're getting the username because that's what the default __unicode__() method of User spits out.
Unless you'd like to hack your contrib.auth.models file (not recommended), I'd suggest using a custom modelform in the admin, and manually setting the names of the choices in the ModelChoiceField, either by subclassing that field and making a custom one that renders its widget with get_full_name if possible, or do it via something like this snippet. That said, I am sure there's a simpler way to do that, but I've forgotten. Dangit.
With regard to the second part of my question (displaying full names instead of usernames in the ChoiceField of a form), I found this link to be just the ticket: