So, I'm trying to build up a simple site with a MongoDB database and Django (using MongoEngine), but I am stuck trying to understand how the user profiles work. I can save the mongo_auth.MongoUser document to the database just fine, but when it comes down to actually saving the profile, I'm not doing the right thing. Here is the User Profile model/document I am trying to setup with the MongoUser:
from mongoengine.django.auth import User
from mongoengine import *
[...]
class UserProfile(Document):
user = EmbeddedDocumentField('User')
telephone = models.CharField(max_length=30,null=True,blank=True)
address = models.CharField(max_length=100, null=True, blank=True)
birthdate = models.DateField(null=True, blank=True)
def create_user_profile(sender, instance, created, **kwargs):
if created:
profile, created = UserProfile.objects.get_or_create(user=instance)
post_save.connect(create_user_profile, sender=User)
In Django with relational databases, the UserProfile was a models.Model and the user field was a OneToOne relationship, but I don't know how to map that with the MongoUser, so I guessed the following lines:
class UserProfile(Document):
user = EmbeddedDocumentField('User')
But, apparently, it's not right since Django can't load the profile:
Unable to load the profile model, check AUTH_PROFILE_MODULE in your project settings
I think my settings.py is configured correctly since I can save a MongoUser just fine (without a profile), and the following line tells Django where to find the UserProfile:
AUTH_PROFILE_MODULE = 'comptes.UserProfile'
I am still new to Django and MongoDB, so all help will be greatly appreciated.
Thanks!
You must use mongoengine.fields.ReferenceField. Something like this
class UserProfile(Document):
user = ReferenceField('User')
Related
I think an example will explain it better.
Lets say I am making an application for various Libraries to show what books they have available.
The site will have Users that are registered through the built-in user registration system and User model. These Users (think of it like library members) can visit the Libraries and browse and checkout the available books.
The site will also allow Libraries to register themselves, and part of that registration is declaring a "Librarian," a person who controls what books are available in their particular Library.
I want to create a Library Registration Form that takes the information of this Library and its Librarian and not only creates an instance of the Library model, but also an instance of the User model. The Librarian automatically becomes a User.
This is my current models.py:
class Library(models.Model):
name = models.CharField(max_length=200)
website = models.URLField()
street = models.CharField(max_length=200)
city = models.CharField(max_length=200)
state_or_province = models.CharField(max_length=200)
postal_code = models.CharField(max_length=200)
date_registered = models.DateField(auto_now_add=True)
librarian = models.OneToOneField(User, on_delete=models.CASCADE)
#receiver(post_save, sender=Library)
def create_user(sender, instance, created, **kwargs):
if created:
User.objects.create(user=instance)
instance.user.save()
I am currently lost as to how to build views.py and forms.py. I am not even sure that model is built correctly, since I need the form to include not only the Library information, but also User information (first_name, last_name, email, password...). Do I need to duplicate that information in the Library model in order for it to pass to the form?
Basically, I don't have a good grasp of how to models connect to one another via Django tools and files. If anyone can point me in the right direction, I would appreciate it. Thanks!
You can do this with standard django, however it is quite long.
Or you can use django-extra-views, to make your life nice and easy.
class LibrarianInline(GenericInlineFormSet):
model = User
fields = '__all__'
class LibraryInline(CreateWithInlinesView):
model = Library
inlines = [LibrarianInline]
fields = '__all__'
There is also a simpler way of doing it with standard django. Force the librarian to be created first and only then allow them to create a Library.
urls.py
urlpatterns = [
url(r'^/create-librarian$',
LibrarianCreateView.as_view(), name='create_librarian'),
url(r'^/create-library/for/(?P<librarian_id>\d+)$',
LibraryCreateView.as_view(), name='create_library'),
]
views.py
from django.shotcuts import reverse
from django.generic.views import CreateView
class LibrarianCreateView(CreateView):
model = User
def form_valid(self, form):
librarian = form.save(commit=True)
return redirect('create_library', {'librarian_id': librarian.id})
class LibraryCreateView(CreateView):
model = Library
def form_valid(self, form):
library = form.save(commit=False)
librarian_id = self.kwargs['librarian_id']
# You can do validation here if you fancy
library.librarian_id = librarian_id
library.save()
return self.get_success_url()
By requiring the id of the Librarian to create the Library, it prevents it being created without a librarian.
Here is what I am trying to accomplish:
- Have admins login to the admin page using the default way (username and password).
- Have users register/login to my web app using a custom User Model which uses email instead of password. They can also have other data associated that I don't need for my admins.
- Separate the admin accounts and user accounts into different tables.
I checked how to create a Custom User class by extending AbstracBaseUser, but the result I got is that my admins also became the new user type. So can I have the Custom User model be used for my app users while keeping the default admin system untouched? Or what is a good alternative to my design?
The recommended Django practice is to create a OneToOne field pointing to the User, rather than extending the User object - this way you build on top of Django's User by decorating only the needed new model properties (for example):
class Profile(models.Model):
user = models.OneToOneField(User,parent_link=True,blank=True,null=True)
profile_image_path = models.CharField(max_length=250,blank=True, null=True)
phone = models.CharField(max_length=250,blank=True, null=True)
address = models.ForeignKey(Address,blank=True,null=True)
is_admin = models.NullBooleanField(default=False,blank=True,null=True)
class Meta:
verbose_name = 'Profile'
verbose_name_plural = 'Profiles'
After couple more hours of digging, I think it is best to keep a single User model and use permissions and roles for regulations.
There are ways that can make multiple different user model authentications work, such as describe in here: How to have 2 different admin sites in a Django project? But I decided it wasn't worth it for my purposes.
I have created a custom User SignUp Class.
class SignUp(models.Model):
userId = models.CharField(max_length=8, blank=False, unique=True)
Name = models.CharField(max_length=200)
VehicleNumber= models.CharField(max_length=12)
ContactNum = models.IntegerField(default=0)
def __unicode__(self):
return smart_unicode(self.Name)
I have used this to create a Sign up form. Now, I am not getting a way for creating user login. Note: I can't use django in-built users because they don't have a field for images.
You can extend the built-in django user, by adding OneToOneField.
YourCustomUser(models.Model):
user = models.OneToOneField(User,related_name='profile')
image = models.ImageField()
//put here your others attributes
If you have YourCustomUser instance and want to access to User built-in instance
your_custom_instance.user
If you have User built-in instance and want to retrieve e.i the image
user.profile.image
You can use and extend the built-in model User. The shortest path is
from django.contrib.auth.models import User
from django.db import models
class UserWithPhoto(User):
image = models.ImageField()
but is better practice to use User Profiles, you can read about it in: User authentication in Django
You can read about this in Django user profile and here Extending the User model with custom fields in Django.
Why is better user profile over extending the User model directly?
If you extend the User model you will have the changes applied to all you users. Think about this, you could have Administrators, Developers, Reviwers, even Guests, all of them might have some field that others don't, so a different profile for each one is the better solution than subclassing User for each one, or even worst create a single class with all fields you need for all kinds of users (only think about it hurts ).
[Django 1.5.1]
I've set up django-profiles and django-registration for my small site in a way that involves a 'custom' registration backend such that during registration, a new user fills out their username, password, and profile fields in one go. But I'm now trying to allow users to log in with Facebook and trying to use django-facebook. As far as I understand, logging in through django-facebook's Facebook login will authenticate someone, but that won't create a user object nor a profile object.
So the idea I had in mind would be to add an extra profile field which holds a user's potential Facebook ID(which I believe is unique) if they want to use Facebook. Then force a check on every template if the user has a profile or not, and if not, to direct them to the 'create profile' page. Then whenever a user logs in through the Facebook login, it'll somehow link their session with the corresponding profile object which matches the Facebook ID (and consequently the user object corresponding to the profile object). I think I'd have to apply a filter and then create a 'signal', but I'm not too sure how to do that.
This sounds very convoluted though. How might I be able to get this accomplished the right way?
Here's how I suggest you do things. Do away with django-facebook and look into django-allauth. It will handle accounts (registration, logic, connecting social accounts).
Also, django-profiles has many issues with 1.5+ for me and I don't bother with it and instead create my own profiles app and UserProfile model with any additional fields that wouldn't be handled by django-allauth.
An example from one of my implementations
class UserProfile(models.Model):
user = models.OneToOneField(User)
default_address = models.OneToOneField(Address, blank=True, null=True)
default_tshirt_size = models.CharField(blank=True, null=True, choices=constants.tshirt_sizes, max_length=50)
default_shoe_size = models.CharField(blank=True, null=True, choices=constants.shoe_sizes, max_length=50)
Your user profile model should be pointing to the same User model allauth is using.
from allauth.utils import get_user_model
User = get_user_model()
Here's a neat method I use to create the User's profile automatically if it hasn't been already.
User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])
Then just create a sign-up form class with a save() method that takes user as an argument. Link to this class in your settings file.
ACCOUNT_SIGNUP_FORM_CLASS = 'yourproject.yourapp.forms.SignupForm'
See this post on for a somewhat relevant example, except of course with your implementation you'll probably want to get the UserProfile based on the user.id at that point, and save the additional values to the profile instance.
How to customize user profile when using django-allauth
I am extending the Django User model to include a foreign key pointing at another model like so (just like it says in the Django docs):
models.py:
class Ward(models.Model):
name = models.CharField(max_length=100)
def __unicode__(self):
return self.name
# Extending the user model
class WardMember(models.Model):
user = models.OneToOneField(User)
ward = models.ForeignKey(Ward)
def __unicode__(self):
return self.ward.name
admin.py:
class WardMemberInline(admin.StackedInline):
model = WardMember
can_delete = False
verbose_name_plural = 'ward member'
# Define a new User admin
class UserAdmin(UserAdmin):
inlines = (WardMemberInline, )
admin.site.register(Ward)
# Re-register UserAdmin to get WardMember customizations
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
When I create a new user in the admin interface I want this new WardMember.ward extension to be required. Currently it's not enforcing that. Here's what happens:
Create user succeeds without a ward
Create other records as user succeed
Edit user now won't let me save unless there is a ward selected
I'd really like #1 above to fail.
I've tried figuring out how to override save() for User using a proxy object but that's not working. I looked into the pre_save signal but the docs explicitly say that's not for vetoing saves.
What is the right approach?
Additional information:
I'm using 1.4. I see that in 1.5 I can extend the user class but I'm not in a position to update to 1.5 just yet.
I ended up forging ahead with Django 1.5, but I'll leave this here in case someone has a final answer to contribute that works with 1.4.
In django 1.3.1 I use this code and works fine:
from django.contrib.auth.models import User
class FilterSearchQueries(models.Model):
title = models.CharField(max_length=250)
owner = models.ForeignKey(User)
place = models.CharField(max_length=250)
query = models.TextField()