I'm using Django 1.5 on Python 3.2.3.
When I run python3 manage.py syncdb, it builds the DB tables, & asks for my email (defined as the unique instead of a username), and then when I enter that, I get this error --
AttributeError: 'Manager' object has no attribute 'get_by_natural_key'
Oddly, it creates the tables anyway, but now, I'm confused 'cause I really don't get what I'm supposed to do. The documentation says I should create a Custom User Manager, but that's all it really says. It doesn't give me a clue where to create it or how. I looked through the docs on Managers, but that really didn't help me figure anything out. It's all too vague. I keep Googling trying to find some clue as to what I need to do, but I'm just going crazy with more and more questions instead of any answer. Here's my models.py file:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser
class MyUsr(AbstractBaseUser):
email = models.EmailField(unique=True,db_index=True)
fname = models.CharField(max_length=255,blank=True, null=True)
surname = models.CharField(max_length=255,blank=True, null=True)
pwd_try_count = models.PositiveSmallIntegerField(blank=True, null=True)
pwd_last_try = models.DateTimeField(blank=True, null=True)
resetid = models.CharField(max_length=100,blank=True, null=True)
last_reset = models.DateTimeField(blank=True, null=True)
activation_code = models.CharField(max_length=100,blank=True, null=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['fname','activation_code']
How do I write a Custom User Manager? Do I put it in the MyUsr model as a method? Or is that even what I'm supposed to do? Should I be doing something totally different? I'm not sure of anything at this point. I just don't understand. The documentation on this doesn't seem clear to me, leaving a lot open for interpretation. I'm pretty new to Django, but I've been into Python for several months.
You define a custom manager by sub-classing BaseUserManager and assigning it in your Model to the objects attribute.
from django.contrib.auth.models import AbstractUser, BaseUserManager
class MyMgr(BaseUserManager):
def create_user(...):
...
def create_superuser(...):
...
class MyUsr(AbstractBaseUser):
objects = MyMgr()
email = models.EmailField(unique=True, db_index=True)
fname = models.CharField(max_length=255, blank=True, null=True)
...
You must define the create_user and create_superuser methods for your BaseUserManager. See the docs.
Depending on your case all you might need to fix this error will be to assign the objects variable in the CustomUser class, to inherit form BaseUserManager() instead of models.Manager() which some would have initially set
from django.db import models
from django.contrib.auth.models import AbstractUser, BaseUserManager
class CustomUser(AbstractUser):
name = models.CharField(null=True, blank=True, max_length=100)
......
# model managers
# objects = models.Manager()
objects = BaseUserManager()
Related
I'm new to Django, and I'm trying to create a "game" model with two attributes:
A many-to-one field where multiple instances of the game model are associated with an instance of a custom user model.
A many-to-many field where instances of the game model are connected with multiple instances of words, and instances of the word model are connected with multiple instances of the game model
Top of my models.py model:
from django.db import models
from users.models import CustomUser
from django.contrib.postgres.fields import ArrayField
Game model:
class SortingGame(models.Model):
user_current_player = models.ForeignKey(CustomUser, on_delete=models.CASCADE, null=True, blank=True)
field_words = models.ManyToManyField(Word, related_name="field_sorting_games")
Word model:
class Word(models.Model):
str_word = models.CharField(max_length=50,null=True)
int_grade_level = models.IntegerField()
arrint_phonemes = ArrayField(models.CharField(max_length=50),null=True)
arrstr_graphemes = ArrayField(models.CharField(max_length=50),null=True)
int_num_syllables = models.IntegerField()
arrstr_syllables = ArrayField(models.CharField(max_length=50),null=True)
User model:
class CustomUser(AbstractBaseUser):
# must have the following fields for django
email = models.EmailField(verbose_name="email",max_length = 100,unique=True)
username = models.CharField(max_length = 30, unique = True)
date_joined = models.DateTimeField(verbose_name = "date_joined",auto_now_add=True)
last_login = models.DateTimeField(verbose_name = "last_login",auto_now = True)
is_admin = models.BooleanField(default=False)
is_superuser = models.BooleanField(default = False)
is_staff = models.BooleanField(default = False)
is_active = models.BooleanField(default = True)
first_name = models.CharField(max_length=15, blank=True)
last_name = models.CharField(max_length=30, blank=True)
spelling_level = models.IntegerField(default=1, unique=False)
time_played = models.IntegerField(default=0, unique=False)
percent_correct = models.IntegerField(default=0, unique=False)
admin.py:
from django.contrib import admin
from .models import Word, SortingGame
admin.site.register(SortingGame)
When I run python3 manage.py makemigrations and python3 manage.py migrate, it doesn't complain, but when I go to the admin page of my django site it says psycopg2.errors.UndefinedColumn: column "user_current_player_id" of relation "game_sortinggame" does not exist.
This makes me think the issue is with user_current_player in SortingGame (it worked fine before I added that attribute), but I've looked around on different forums to see what might be going wrong and I can't seem to figure it out. I tried starting from scratch with a new database, and it's still throwing the same exception. Any ideas would be appreciated—thanks!
Nathan!
First thing would be make sure that you have the app where CustomUser model is created in your settings.py file, at INSTALLED_APPS.
If so, please have a look at this folder (app) where you have CustomUser defined to verify if there is in deed a migrations folder there.
I suspect that Django in not aware of this app (not under INSTALLED_APPS) and therefore did not migrated it. So, your database is not finding the User Model connection.
That said, I would suggested you to keep your account model as defined by Django User and create another model with a direct relationship to it to deal with profile/game fields such as spelling level, percentage_correct and so on.
This would keep your Model "concerns" more organized later on.
if you did make a migrations before try to use (python manage.py makemigrations -appname)
Also after That you need to Add the module in your admin.py
from django.contrib import admin
from .models import *
admin.site.register(SortingGame)
... all other modules
I am new to django management commands! I am trying to write a commands to populate author...
My models.py is:
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=50)
email = models.EmailField(unique=True, blank=False, null=False)
class Book(models.Model):
book_name = models.CharField(max_length=10)
summery = models.TextField()
author = models.ForeignKey(Author, on_delete=models.CASCADE)
and i am tried to write a command but i failed..
this is my blog/management/commands/populate_author.py below:
from django.core.management.base import BaseCommand, CommandError
from blog.models import Author, Book
class Command(BaseCommand):
help = 'Populate author'
def handle(self, *args, **options):
Author.objects.create()
Author.save()
Can anyone please help me to make it happen?
You're trying to create an Author without giving any data for the fields. If you've managed to create one Author with a blank value for the required email field, then the next Author you try to create will have a blank email field and that is what causes the non-unique error. Do this to create an Author:
Author.objects.create(name='Author Name', email='authoremail#domain.com')
I have the following model:
from django.db import models
from django.contrib.auth import get_user_model
User = get_user_model()
class CalEvents(models.Model):
user = models.ForeignKey(User)
activity = models.CharField(max_length=256, unique=False, blank=True)
activity_type = models.CharField(max_length=30, unique=False, blank=True)
activity_code = models.CharField(max_length=30, unique=False, blank=True)
def __str__(self):
return "Activity, type and code for the calendar events of #{}".format(self.user.username)
What I would like to know is how can I dynamically add instances of that model with forms. I'm imagining something like having a form for the first instance (with fields "activity", "activity_type" and "activity_code") and then, if the user clicks a "plus sign" (or whatever), (s)he can add a second, third...Nth instance to the database.
You can achieve this functionality using Django's inline formsets.
https://docs.djangoproject.com/en/1.11/topics/forms/modelforms/#inline-formsets
It will allow you to declare a form which can be used dynamically to add multiple instances of a model.
I'm writing some models with constraints like unique=True and blank=False and null=False. I'm trying to write tests for the models with nose. However, if I write a test like this:
from job_sites.models import Site, SiteType
#raises(IntegrityError)
def test_empty_site():
s = Site()
s.save()
#raises(IntegrityError)
def test_empty_site_type():
st = SiteType()
st.save()
I get a DatabaseError like this:
DatabaseError: current transaction is aborted, commands ignored until end of transaction block after it runs the first test.
What is the correct way to run DJango model tests when I'm expecting errors?
For reference, the models look like this:
class SiteType(models.Model):
site_type_id = models.AutoField(primary_key=True)
site_type = models.CharField(max_length=32, unique=True, blank=False, null=False, default=None)
site_type_abbrev = models.CharField(max_length=32, blank=True)
class Meta:
db_table = u'site_types'
class Site(models.Model):
site_id = models.AutoField(primary_key=True, blank=False, null=False, db_index=True)
site_name = models.CharField(max_length=128, blank=False, null=False, db_index=True)
site_type = models.ForeignKey(SiteType, blank=True, null=True)
date_entered = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = u'sites'
My constraints and defaults look like this:
ALTER TABLE site_types ADD CONSTRAINT site_types_site_type_name_minlen CHECK (char_length(site_type) > 0);
ALTER TABLE sites ALTER COLUMN date_entered SET DEFAULT now();
ALTER TABLE sites ADD CONSTRAINT sites_site_name_minlen CHECK (char_length(site_name) > 0);
Instead of using nose's terse test definitions, you should create your tests as sub-classes of Django's TestCase. That way, your database etc will be set up and configured for you at runtime and all the transaction stuff will be magically taken care of.
There's an overview of how to write tests for Django projects at: https://docs.djangoproject.com/en/dev/topics/testing/overview/
The equivalent of what you're trying to do would look something like:
from django.db import IntegrityError
from django.utils import unittest
from job_sites.models import Site, SiteType
class TestMyStuff(unittest.TestCase):
def test_empty_site(self):
s = Site()
assertRaises(IntegrityError, s.save())
def test_empty_site_type(self):
st = SiteType()
assertRaises(IntegrityError, st.save())
(Disclaimer: I have not actually run this code so it might not work.)
However, it's probably a waste of time to test for this kind of thing. The only logic that's being tested here is internal to Django, so you're not learning anything about your application by testing it.
Let's say I'm using the default auth.models.User plus my custom Profile and Address models which look like this:
class Profile(models.Model):
user = models.OneToOneField(User)
primary_phone = models.CharField(max_length=20)
address = models.ForeignKey("Address")
class Address(models.Model):
country = CountryField(default='CA')
province = CAProvinceField(default='BC')
city = models.CharField(max_length=80)
postal_code = models.CharField(max_length=6)
street1 = models.CharField(max_length=80)
street2 = models.CharField(max_length=80, blank=True, null=True)
street3 = models.CharField(max_length=80, blank=True, null=True)
Now I want to create a registration form. I could create a ModelForm based on User but that won't include fields for the Profile and Address (which are required). So what's the best way to go about building this form? Should I even use ModelForm at all?
Furthermore, how would I use the same form for editing the complex object? I could easily pass an instance of Profile back to it, which holds references to the necessary Address and Profile objects, but how do I get it to fill in the fields for me?
What about using 3 separate ModelForm. One for Address, one for User, and one for Profile but with :
class ProfileForm(ModelForm):
class Meta:
model = Profile
exclude = ('user', 'address',)
Then, process these 3 forms separately in your views. Specifically, for the ProfileForm use save with commit=False to update user and address field on the instance :
# ...
profile_form = ProfileForm(request.POST)
if profile_form.is_valid():
profile = profile_form.save(commit=False)
# `user` and `address` have been created previously
# by saving the other forms
profile.user = user
profile.address = address
Don't hesitate to use transactions here to be sure rows get inserted only when the 3 forms are valid.
You should look into the officially recommended way to extend the User model first, as seen in the docs, which I believe comes directly from the project manager's personal blog about the subject. (The actual blog article is rather old, now)
As for your actual issue with forms, have a look at the project manager's own reusable django-profiles app and see if perusing the code solves your issue. Specifically these functions and the views in which they are utilized.
Edited to Add:
I've looked into it a bit (as I needed to do so myself). It seems something like so would be sufficient:
# apps.profiles.models
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
...
birth_date = models.DateField(blank=True, null=True)
joined = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = 'user profile'
verbose_name_plural = 'user profiles'
db_table = 'user_profiles'
class Address(models.Model):
user = models.ForeignKey(UserProfile)
...
# apps.profiles.forms
from django import forms
from django.forms import ModelForm
from django.forms.models import inlineformset_factory
from django.contrib.auth.models import User
from apps.profiles.models import UserProfile, Address
class UserForm(ModelForm):
class Meta:
model = User
...
class UserProfileForm(ModelForm):
class Meta:
model = UserProfile
...
AddressFormSet = inlineformset_factory(UserProfile, Address)
I was using "..." to snip content in the code above. I have not yet tested this out but from looking through examples and the documentation on forms I believe this to be correct.
Note I put the FK from the Address model to the UserProfile and not the other way around, as in your question. I believe the inline formsets need this to work correctly.
Then of course in your views and templates you will end up treating UserForm, UserProfileForm, and AddressFormSet separately but they can all be inserted into the same form.
I think your are looking for inline formsets with model forms. This helps you to deal with multiple forms on one page and also takes care of foreign key relations.
Update:
Maybe this question helps you too: Django: multiple models in one template using forms