Stupid question time. In Django, if you want to specify the name of a model's table, you'll do this:
class MyModel(models.Model):
...
class Meta:
db_table = 'mymodel'
Is it possible to change the name of Django's default auth_user table in a similar fashion? I'm always running manual queries against the user table and it would be much faster to type 'user' than 'auth_user'. I've looked at the Django docs and done some Internet searches and I haven't seen anyone address this question.
Thanks!
Both Selcuk and Daniel Roseman have given you good answers. You can extend either one of the classes User or AbstractUser, with the small difference that for the latter you will also need to add the swappable attribute in you Meta class.
Here is an example:
from django.contrib.auth.models import AbstractUser # (or simply User)
class MyUser(AbstractUser):
class Meta:
swappable = 'AUTH_USER_MODEL' # ONLY for AbstractUser
db_table = 'user'
However, pay attention to using 'user' as a table name, because there are databases where this is a reserved word !!!
Good luck.
Related
I am trying to add a new field in django_comment model. According to the documentation, most custom comment models will subclass the CommentAbstractModel model:
from django.db import models
from django_comments.models import CommentAbstractModel
class CommentWithTitle(CommentAbstractModel):
title = models.CharField(max_length=300)
If I generate a migration, then it adds all the fields into migrations (all fields from comment model plus title field).
And after running migrations, CommentWithTitle table and django_comments table are created. But django_comments would be useless (not in use).
Another approach is to generate the table this way:
from django_comments.models import Comment
class CommentWithTitle(Comment):
title = models.CharField(max_length=300)
And it generates the migration with one field only with the reference of comment_ptr.
My Question is: which approach is better? I think the first model is good as it has all fields in one table. But that generates the django_model which is not in use at all.
I would follow the documentation.
Looking at the implementation, Comment is basically just extending CommentAbstractModel with db_table specified.
class Comment(CommentAbstractModel):
class Meta(CommentAbstractModel.Meta):
db_table = "django_comments"
I'm suspecting that if you do the second option you mentioned, the migration would throw an error because the db_table will be created twice.
I read the documentation about many-to-many relationships and the examples. What I could not find is a hint on where to put the ManyToManyField. In my case I have an extended user model Client and a model Pizza. Every client may mark one or more pizzas as favourites. Those are my two models:
from django.db import models
from django.contrib.auth.models import User
class Client(models.Model):
user = models.OneToOneField(User)
#? favourite_pizza = models.ManyToManyField()
class Pizza(models.Model):
name = models.CharField(max_length=255)
#? favourite_pizza = models.ManyToManyField()
In what model should I add the ManyToManyField? Does it matter?
PS The important information is how many favourite pizzas a client has (and which). It is less important how many clients marked a pizza as a favourite (and who). Consequently I would chose to put the ManyToManyField in the Client class.
From the Django documentation:
Generally, ManyToManyField instances should go in the object that’s going to be edited on a form.
Technically it does not matter. The question is from which model-side you will query the database.
I have a question regarding the custom user model in Django 1.5
So right now the default user model looks just fine to me, I just need to add a few other variables such as gender,location and birthday so that users can fill up those variables after they have successfully registered and activated their account.
So, what is the best way to implement this scenario?
Do I have to create a new app called Profile and inherit AbstractBaseUser? and add my custom variable to models.py? Any good example for me to follow?
thank you in advance
You want to extend your user model to the AbstractUser and add your additional fields. AbstractUser inherits all of the standard user profile fields, whereas AbstractBaseUser starts you from scratch without any of those fields.
It's hard to define best practices this close to the release, but it seems that unless you need to drastically redefine the User model, then you should use AbstractUser where possible.
Here are the docs for extending the User model using AbstractUser
Your models.py would then look something like this:
class MyUser(AbstractUser):
gender = models.DateField()
location = models.CharField()
birthday = models.CharField()
MyUser will then have the standard email, password, username, etc fields that come with the User model, and your three additional fields above.
Then you need to add the AUTH_USER_MODEL to your settings.py:
AUTH_USER_MODEL = 'myapp.MyUser'
Initially, I started my UserProfile like this:
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User)
verified = models.BooleanField()
mobile = models.CharField(max_length=32)
def __unicode__(self):
return self.user.email
Which works nicely along with AUTH_PROFILE_MODULE = 'accounts.UserProfile' set in settings.py.
However, I have two different kinds of users in my website, Individuals and Corporate, each having their own unique attributes. For instance, I would want my Individual users to have a single user only, hence having user = models.OneToOneField(User), and for Corporate I would want them to have multiple users related to the same profile, so I would have user = models.ForeignKey(User) instead.
So I thought about segregating the model into two different models, IndivProfile and CorpProfile, both inheriting from UserProfile while moving the model-specific attributes into the relevant sub-models. Seems like a good idea to me and would probably work, however I would not be able to specify AUTH_PROFILE_MODULE this way since I'm having two user profiles that would be different for different users.
I also thought about doing it the other way around, having UserProfile inherit from multiple classes (models), something like this:
class UserProfile(IndivProfile, CorpProfile):
# some field
def __unicode__(self):
return self.user.email
This way I would set AUTH_PROFILE_MODULE = 'accounts.UserProfile' and solve its problem. But that doesn't look like it's going to work, since inheritance in python works from left to right and all the variables in IndivProfile will be dominant.
Sure I can always have one single model with IndivProfile and CorpProfile variables all mixed in together and then I would use the required ones where necessary. But that is just doesn't look clean to me, I would rather have them segregated and use the appropriate model in the appropriate place.
Any suggestions of a clean way of doing this?
You can do this in following way. Have a profile which will contains common fields which are necessary in both profiles. And you have already done this by creating class UserProfile.
class UserProfile(models.Model):
user = models.ForeignKey(User)
# Some common fields here, which are shared among both corporate and individual profiles
class CorporateUser(models.Model):
profile = models.ForeignKey(UserProfile)
# Corporate fields here
class Meta:
db_table = 'corporate_user'
class IndividualUser(models.Model):
profile = models.ForeignKey(UserProfile)
# Individual user fields here
class Meta:
db_table = 'individual_user'
There is no rocket science involved here. Just have a keyword which will distinguish between corporate profile or individual profile. E.g. Consider that the user is signing up. Then have a field on form which will differentiate whether the user is signing up for corporate or not. And Use that keyword(request parameter) to save the user in respective model.
Then later on when ever you want to check that the profile of user is corporate or individual you can check it by writing a small function.
def is_corporate_profile(profile):
try:
profile.corporate_user
return True
except CorporateUser.DoesNotExist:
return False
# If there is no corporate profile is associated with main profile then it will raise `DoesNotExist` exception and it means its individual profile
# You can use this function as a template function also to use in template
{% if profile|is_corporate_profile %}
Hope this will lead you some where. Thanks!
I have done it this way.
PROFILE_TYPES = (
(u'INDV', 'Individual'),
(u'CORP', 'Corporate'),
)
# used just to define the relation between User and Profile
class UserProfile(models.Model):
user = models.ForeignKey(User)
profile = models.ForeignKey('Profile')
type = models.CharField(choices=PROFILE_TYPES, max_length=16)
# common fields reside here
class Profile(models.Model):
verified = models.BooleanField(default=False)
I ended up using an intermediate table to reflect the relation between two abstract models, User which is already defined in Django, and my Profile model. In case of having attributes that are not common, I will create a new model and relate it to Profile.
Could be worth to try using a through field. The idea behind it is to use the UserProfile model as through model for the CorpProfile or IndivProfile models. That way it is being created as soon as a Corp or Indiv Profile is linked to a user:
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.ForeignKey(User)
profile = models.ForeignKey(Profile, related_name='special_profile')
class Profile(models.Model):
common_property=something
class CorpProfile(Profile):
user=models.ForeignKey(User, through=UserProfile)
corp_property1=someproperty1
corp_property2=someproperty2
class IndivProfile(Profile):
user=models.ForeignKey(User, through=UserProfile, unique=true)
indiv_property1=something
indiv_property2=something
I think that way it should be possible to set AUTH_PROFILE_MODULE = 'accounts.UserProfile', and every time you create either a CorpProfile or a IndivProfile that is linked to a real user a unique UserProfile model is created. You can then access that with db queries or whatever you want.
I haven't tested this, so no guarantees. It may be a little bit hacky, but on the other side i find the idea quite appealing. :)
I am having trouble getting my model manager to behave correctly when using the Admin interface. Basically, I have two models:
class Employee(models.Model):
objects = models.EmployeeManager()
username = models.CharField(max_length=45, primary_key=True)
. . .
class Eotm(models.Model): #Employee of the Month
date = models.DateField()
employee = models.ForeignKey(Employee)
. . .
And I have an EmployeeManager class that overrides the get() method, something like this:
class EmployeeManager(models.Manager):
use_for_related_fields = True
def get(self, *arguments, **keywords):
try:
return super(EmployeeManager, self).get(*arguments, **keywords)
except self.model.DoesNotExist:
#If there is no Employee matching query, try an LDAP lookup and create
#a model instance for the result, if there is one.
Basically, the idea is to have Employee objects automatically created from the information in Active Directory if they don't already exist in the database. This works well from my application code, but when I tried to create a Django admin page for the Eotm model, things weren't so nice. I replaced the default widget for ForeignKey fields with a TextInput widget so users could type a username (since username is the primary key). In theory, this should call EmployeeManager.get(username='whatever'), which would either return an Employee just like the default manager or create one and return it if one didn't already exist. The problem is, my manager is not being used.
I can't find anything in the Django documentation about using custom Manager classes and the Admin site, aside from the generic manager documentation. I did find a blog entry that talked about specifying a custom manager for ModelAdmin classes, but that doesn't really help because I don't want to change the model represented by a ModelAdmin class, but one to which it is related.
I may not be understanding what you're trying to do here, but you could use a custom Form for your Eotm model:
#admin.py
from forms import EotmAdminForm
class EotmAdmin(models.ModelAdmin):
form = EotmAdminForm
#forms.py
from django import forms
from models import Eotm, Employee
class EotmAdminForm(forms.ModelForm)
class Meta:
model = Eotm
def clean_employee(self):
username = self.cleaned_data['employee']
return Employee.get(username=username)
That, in theory, should work. I haven't tested it.