Django error "add a non-nullable field" - python

i am getting error django model like this when i try to makemigrations:
You are trying to add a non-nullable field 'person' to owner without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows)
2) Quit, and let me add a default in models.py
i use django 1.8 and this is my model:
class Person(models.Model):
user = models.OneToOneField(User)
alphanumeric = RegexValidator(r'^[0-9a-zA-Z]*$', message='hanya yang mengandung karakter alphanumeric')
email = models.EmailField(verbose_name='email address', unique=True, max_length=244)
username = models.CharField(unique=True, max_length=20, validators=[alphanumeric])
first_name = models.CharField(max_length=30, null=True, blank=True)
last_name = models.CharField(max_length=30, null=True, blank=True)
date_of_birth = models.DateTimeField()
date_joined = models.DateTimeField(auto_now_add=True)
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email']
def get_full_name(self):
fullname = self.first_name+" "+self.last_name
return self.fullname
def get_short_name(self):
return self.username
def list_operator(self):
return self.operators.all()
def __str__(self):
return self.email
class Operator(models.Model):
person = models.ForeignKey(Person, related_name="operators", null=True)
alphanumeric = RegexValidator(r'^[0-9a-zA-Z]*$', message='hanya yang mengandung karakter alphanumeric')
email = models.EmailField(verbose_name='email address', unique=True, max_length=244)
username = models.CharField(unique=True, max_length=20, validators=[alphanumeric])
first_name = models.CharField(max_length=30, null=True, blank=True)
last_name = models.CharField(max_length=30, null=True, blank=True)
date_of_birth = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.username;
i want to know where my code is wrong.
can you help me solved this problem?

Your code isn't wrong. Just follow the instructions provided by the message...
The person field within your Operator model can't be null (because null=True isn't set). You must already have Operators in your database, so Django doesn't know what to do with those.
You need to either: (a) provide a default value in your model, (b) provide a default during the migration process, or (c) enable null values for that field.

Related

How to get logged in user in django from custom users model

I want to get username from custom users model
My Custom Users model:
class Account(AbstractBaseUser, PermissionsMixin):
nickname = models.CharField(max_length=150, unique=True)
name = models.CharField(max_length=150)
last_name = models.CharField(max_length=150)
phone = models.CharField(max_length=50, unique=True)
date_of_birth = models.DateField(blank=True, null=True)
picture = models.ImageField(blank=True, null=True)
is_staff = models.BooleanField(default=True)
is_active = models.BooleanField(default=True)
date_joined = models.DateTimeField(default=timezone.now)
last_login = models.DateTimeField(null=True)
admin_of_company = models.ForeignKey('companies.company', on_delete=models.CASCADE, default=None, blank=True,
null=True)
objects = AccountManager()
USERNAME_FIELD = 'nickname'
REQUIRED_FIELDS = ['name', 'last_name', 'phone']
def get_full_name(self):
return self.name, self.last_name
def get_short_name(self):
return self.name.split()[0]
and products model:
class products(models.Model):
name = models.CharField(max_length=150)
about = models.TextField()
price = models.IntegerField()
picture = models.ImageField(default=None)
admin = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, blank=True, null=True)
in products.admin I want to set default logged in user
but I don't know how to get this data from custom users model
If you would like to get a current account in your view use this
current_user_id = self.request.user.id
current_account = Account.objects.get(pk=current_user_id)
current_account_nickname = current_account.nickname
Your model Account doesn't have "username" field.
You have to add it if you would like to use "username".
class Account(AbstractBaseUser, PermissionsMixin):
username = models.CharField(max_length=150, unique=True)

In Django models, how does the foreign key field know which field to match with in the other model?

I understand what Foreign Keys do but I'm having trouble understanding why this is working in Django.
I have the Project model in 'app1/models.py' file. This model has a ForeignKey named 'owner' that links to the Profile model in my 'app2/models.py' file.
How does the 'owner' field in the Project model know it should be linking to the 'user' field in the Profile model if I'm only passing the model name to the 'owner' field? I feel like I should be passing the Profile.field or something like this in the Project model:
owner = models.ForeignKey(Profile.user, null=True, blank=True ... )
Full model code from Dennis Ivy's tutorial:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True)
name = models.CharField(max_length=200, blank=True, null=True)
email = models.EmailField(max_length=500, blank=True, null=True)
username = models.CharField(max_length=200, blank=True, null=True)
location = models.CharField(max_length=200, blank=True, null=True)
short_intro = models.CharField(max_length=200, blank=True, null=True)
bio = models.TextField(blank=True, null=True)
profile_image = models.ImageField(
null=True, blank=True, upload_to='profiles/', default='profiles/user-default.png')
social_github = models.CharField(max_length=200, blank=True, null=True)
social_twitter = models.CharField(max_length=200, blank=True, null=True)
social_linkedin = models.CharField(max_length=200, blank=True, null=True)
social_youtube = models.CharField(max_length=200, blank=True, null=True)
social_website = models.CharField(max_length=200, blank=True, null=True)
created = models.DateTimeField(auto_now_add=True)
id = models.UUIDField(default=uuid.uuid4, unique=True,
primary_key=True, editable=False)
class Project(models.Model):
owner = models.ForeignKey(Profile, null=True, blank=True, on_delete=models.SET_NULL)
title = models.CharField(max_length=200) #null is default=False and is required
description = models.TextField(null=True, blank=True) #for a bigger field, allows null(for db)/blank(for Django get/post)
featured_image = models.ImageField(null=True, blank=True, default='default.jpg')
demo_link = models.CharField(max_length=2000)
source_link = models.CharField(max_length=2000, null=True, blank=True) #can be blank in db
tags = models.ManyToManyField('Tag', blank=True) #quotes will ref other class after this one
vote_total = models.IntegerField(default=0, null=True, blank=True)
vote_ratio = models.IntegerField(default=0, null=True, blank=True)
created = models.DateTimeField(auto_now_add=True) #generate when model instance is created
id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False)
Foreign key fields do not match with another field in another model. it matches with the model itself.Let's say you want to assign a profile with the name 'victor' to new project model object, it would go like this:
from app_name.model import Project, Profile
profile1=Profile.objects.filter(name='victor').first()
new_project=Project(title='project 1',demolink='demo link',owner=profile1)
here, we assigned a user object to the owner property of the project and not a field.
The Profile.User field isn't necessary.
if you want to create a customUser, i suggest you should look that up or you'll be giving yourself many problems with authentication. You'll have to create a model manager for it after which you can begin to customise. It should look like this:
from django.db import models
from django.contrib.auth.models import User, AbstractUser
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.base_user import BaseUserManager
class CustomUserManager(BaseUserManager):
"""
Custom user model manager where email is the unique identifiers
for authentication instead of usernames.
"""
def create_user(self, username, password, **extra_fields):
"""
Create and save a User with the given username and password.
"""
if not username:
raise ValueError(_('The Username must be set'))
user = self.model(username=username, **extra_fields)
user.set_password(password)
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', False)
extra_fields.setdefault('is_active', True)
user.save()
return user
def create_superuser(self, username, password, **extra_fields):
"""
Create and save a SuperUser with the given username and password.
"""
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_active', True)
if extra_fields.get('is_staff') is not True:
raise ValueError(_('Superuser must have is_staff=True.'))
if extra_fields.get('is_superuser') is not True:
raise ValueError(_('Superuser must have is_superuser=True.'))
return self.create_user(username, password, **extra_fields)
class Profile(AbstractUser):
objects = CustomUserManager()
name = models.CharField(max_length=200, blank=True, null=True)
email = models.EmailField(max_length=500, blank=True, null=True)
location = models.CharField(max_length=200, blank=True, null=True)
short_intro = models.CharField(max_length=200, blank=True, null=True)
bio = models.TextField(blank=True, null=True)
profile_image = models.ImageField(
null=True, blank=True, upload_to='profiles/', default='profiles/user-default.png')
social_github = models.CharField(max_length=200, blank=True, null=True)
social_twitter = models.CharField(max_length=200, blank=True, null=True)
social_linkedin = models.CharField(max_length=200, blank=True, null=True)
social_youtube = models.CharField(max_length=200, blank=True, null=True)
social_website = models.CharField(max_length=200, blank=True, null=True)
created = models.DateTimeField(auto_now_add=True)
id = models.UUIDField(default=uuid.uuid4, unique=True,
primary_key=True, editable=False)
The field which has primary key is referenced by default if only setting a model name to "models.ForeignKey()" as mentioned in ForeignKey.to_field:
ForeignKey.to_field
...
By default, Django uses the primary key of the related object.
...
This is the full explanation of ForeignKey.to_field:
ForeignKey.to_field
The field on the related object that the relation
is to. By default, Django uses the primary key of the related object.
If you reference a different field, that field must have unique=True.
Thanks, Viq. I have solved my confusion now. The ForeignKey specifies a model but it always connects to that model's Primary Key which is why I don't have to specify Project.title or Project.id. Then when the Review model with the ForeignKey is output it calls the Project model's str method which lists out the title. I didn't realize the str method was being called.
I didn't include the str method in my code example because i didn't think that it had anything to do with my issue but I now understand that the str method is why I am seeing Project.title instead of Project.id.
def str(self): return self.title
This is the piece of the puzzle i was missing.
https://docs.djangoproject.com/en/3.2/ref/models/fields/#django.db.models.ForeignKey.to_field
ForeignKey.to_field
The field on the related object that the relation is to. By default, Django uses the primary key of the related object. If you reference a different field, that field must have unique=True.

Django Inner Join on Derived Query

I have two models shown as follows. I want to be able to execute this query through the django ORM, essentially giving me the CustomUser class alongside two derived fields: max(message.sent_at) and max(case when read_at is null then 1 else 0 end). Those two fields would enable me to sort threads of messages by usernames and latest activity.
Here are my classes:
class CustomUser(AbstractBaseUser, PermissionsMixin):
username_validator = UnicodeUsernameValidator()
username = models.CharField(_('username'), max_length=150, unique=True, help_text=_('Required. 150 characters or fewer. Letters, digits and #/./+/-/_ only.'), validators=[username_validator], error_messages={'unique': _('A user with that username already exists.'),},)
email = models.EmailField(_('email address'), blank=True)
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=150, blank=True)
is_staff = models.BooleanField(_('staff status'), default=False, help_text=_('Designates whether the user can log into this admin site.'),)
is_active = models.BooleanField(_('active'), default=True, help_text=_('Designates whether this user should be treated as active. Unselect this instead of deleting accounts.'),)
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
bio = models.TextField(max_length=500, null=True, blank=True)
location = models.CharField(max_length=30, null=True, blank=True)
birth_date = models.DateField(null=True, blank=True)
phone_number = PhoneNumberField(default='+10000000000')
gender = models.CharField(max_length=32, choices=[(tag.name, tag.value) for tag in GenderChoice], default=GenderChoice.UNSPECIFIED.value)
objects = UserManager()
EMAIL_FIELD = 'email'
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email']
class Meta:
ordering = ['username']
verbose_name = _('user')
verbose_name_plural = _('users')
and
class Message(AbstractIP):
subject = models.CharField(_('Subject'), max_length=120, blank=True)
body = models.TextField(_('Body')) # Do we want to cap length or enforce non-blank?
sender = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='sender_messages', verbose_name=_('Sender'), on_delete=models.CASCADE)
recipient = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='receiver_messages', verbose_name=_('Recipient'), blank=True, on_delete=models.CASCADE)
parent_msg = models.ForeignKey('self', related_name='next_messages', null=True, blank=True, verbose_name=_('Parent message'), on_delete=models.CASCADE)
sent_at = models.DateTimeField(_('sent at'), null=True, blank=True)
read_at = models.DateTimeField(_('read at'), null=True, blank=True)
replied_at = models.DateTimeField(_('replied at'), null=True, blank=True)
sender_deleted_at = models.DateTimeField(_('Sender deleted at'), null=True, blank=True)
recipient_deleted_at = models.DateTimeField(_('Recipient deleted at'), null=True, blank=True)
ip = models.GenericIPAddressField(verbose_name=_('IP'), null=True, blank=True)
user_agent = models.CharField(verbose_name=_('User Agent'), blank=True, max_length=255)
objects = MessageManager() # Manager for Message queries
def new(self):
"""Returns whether the recipient has read the message or not"""
if self.read_at is not None:
return False
return True
def replied(self):
"""Returns whether the recipient has written a reply to this message"""
if self.replied_at is not None:
return True
return False
def __str__(self):
if self.subject is not None:
return self.subject
if self.body is not None:
return self.body[:40]
return None
def get_absolute_url(self):
return reverse('messages_detail', args=[self.id])
def save(self, **kwargs):
if not self.id:
self.sent_at = timezone.now()
super(Message, self).save(**kwargs)
class Meta:
ordering = ['-sent_at']
verbose_name = _('Message')
verbose_name_plural = _('Messages')
The query I want to be able to perform equates to this, but I cannot figure out how to do it in the ORM, where %s is a placeholder for the CustomUser.id (pk) field of a given user.
SELECT webrtc_customuser.*
,MAX(webrtc_message.sent_at) AS sent_at
,MAX(CASE WHEN webrtc_message.read_at IS NULL AND webrtc_customuser.id <> webrtc_message.sender_id THEN 1 ELSE 0 END) AS has_unread
FROM webrtc_customuser
INNER JOIN webrtc_message
ON (
webrtc_customuser.id = webrtc_message.sender_id
AND webrtc_message.sender_id = %s
AND webrtc_message.sender_deleted_at IS NULL
) OR (
webrtc_customuser.id = webrtc_message.recipient_id
AND webrtc_message.recipient_id = %s
AND webrtc_message.recipient_deleted_at IS NULL
)
I managed to get the correct user_id and derived fields with the following queries but cannot figure out how to get the CustomUser properties joined alongside them.
messages = self.values(
user_fk=Case(When(sender=user, then='recipient'), default='sender', output_field=models.IntegerField())
).exclude(
sender=user, recipient=user
).filter(
Q(sender=user, sender_deleted_at__isnull=True) |
Q(recipient=user, recipient_deleted_at__isnull=True)
).annotate(
max_sent_at=Max('sent_at'),
has_unread=Max(Case(When(~Q(sender=user) & Q(read_at__isnull=True), then=1), default=0, output_field=models.IntegerField()))
).order_by()
Thank you in advance for your time!
Edit: updated ORM query
You need to specify the desired user properties individually:
messages = self.values(
user_email=Case(When(sender=user, then='recipient__email'), default='sender__email'),
user_username=Case(When(sender=user, then='recipient__username'), default='sender__username'),
)
Not very pretty, particularly as you have to repeat the CASE statement for every column and may even need to specify an output_field for every one.
To get around that, ie. to get all user properties without selecting them one by one, you'd either need to a) select from CustomUser.object (figuring out how to select the relevant users and get the relevant annotations), or b) select full message objects rather than just a values() dictionary. Then you can access the full user objects via message.senderand message.recipient. But here again, the challenge would be how to filter and annotate the messages queryset using subqueries, since just omitting values() will bust the aggregates in your annotations as every message object will then be unique.

Is a self-join on a model in a django app an acceptable pattern?

Apologies if this question is too subjective.
If you are planning to close this question: please comment with a suggestion for a more appropriate place to post.
I'm super new to django and python, and I'm building a test app that keeps track of employees and who their managers are.
I would like to set up the domain model so that there there is only one list of employees, any of which can be managers, and all of which can be managed by any other employee who is designated a manager.
To achieve this, I did a self-join on the Employee model and have an "is_manager" flag to keep track of who is a manager and who isn't (see model below).
Is an acceptable pattern?
I'm worried it violates a design principle I'm not considering and there's some hairy trap that I'm walking into as a noob.
Thank you very much for your time.
models.py for the app:
class OrganizationTitle(models.Model):
def __str__(self):
return "{}".format(self.organization_title_name)
organization_title_name = models.CharField(max_length=150, unique=True)
class ClassificationTitle(models.Model):
def __str__(self):
return "{}".format(self.classification_title_name)
classification_title_name = models.CharField(max_length=150, unique=True)
class WorkingTitle(models.Model):
def __str__(self):
return "{}".format(self.working_title_name)
working_title_name = models.CharField(max_length=150, unique=True)
class Category(models.Model):
def __str__(self):
return "{}".format(self.category_name)
category_name = models.CharField(max_length=150, unique=True)
class Department(models.Model):
def __str__(self):
return "{}".format(self.department_name)
department_name = models.CharField(max_length=150, unique=True)
class Employee(models.Model):
first_name = models.CharField(max_length=150)
last_name = models.CharField(max_length=150)
org_title = models.ForeignKey(OrganizationTitle, blank=True, null=True, on_delete=models.SET_NULL)
manager = models.ForeignKey('self', null=True, blank=True, on_delete=models.SET_NULL)
manager_email = models.EmailField(max_length=50, blank=True, null=True)
hire_date = models.DateField(blank=True, null=True)
classification_title = models.ForeignKey(ClassificationTitle, blank=True, null=True, on_delete=models.SET_NULL)
working_title = models.ForeignKey(WorkingTitle, blank=True, null=True, on_delete=models.SET_NULL)
email_address = models.EmailField(max_length=250, blank=False, unique=True,
error_messages={'unique': 'An account with this email exist.',
'required': 'Please provide an email address.'})
category = models.ForeignKey(Category, blank=True, null=True, on_delete=models.SET_NULL)
is_substitute = models.BooleanField(default=False)
department = models.ForeignKey(Department, blank=True, null=True, on_delete=models.SET_NULL)
is_active = models.BooleanField(default=True)
is_manager = models.BooleanField(default=False)
class Meta:
ordering = ('is_active', 'last_name',)
def __str__(self):
return "{}".format(self.first_name + ' ' + self.last_name)
That's perfectly fine.
I would recommend you to specify the related_name to keep your code more explicit:
manager = models.ForeignKey(..., related_name="managed_employees")
so then you can do something like:
bob.managed_employees.all()
Also, there are 2 things I would change (not your question but still regarding the models):
1.The manager_email field is redundant. I would remove it. You already have that information at tom.manager.email_address for example.
2.There are many fields that I would simply rename to name. For example:
class OrganizationTitle(models.Model):
def __str__(self):
return u"{}".format(self.name)
name = models.CharField(max_length=150, unique=True)
No need to call it organization_title_name. That's consistent with the first_name field (not employee_first_name).
Yes, this is an acceptable pattern. This is called a "recursive relationship", or "self referential foreign keys" and is a very common usecase in realworld applications.
Here is django's example supporting this usecase

Cannot resolve keyword 'article' into field

I know that there are multiple questions about this already but none of them resolves my problem.
I have split my models into multiple files under models folder, viz., models/articles.py, models/core.py etc.
When I try executing
User.objects.annotate(my_count=Count('article'))
django gives me the following error:
FieldError: Cannot resolve keyword 'articles' into field. Choices are: access, cfi_store_item_likes, collaborators, comment, date_joined, documentation, email, emailaddress, first_name, groups, id, images, is_active, is_staff, is_superuser, last_login, last_name, listing, logentry, makey, makey_removed, newproduct, note, password, productdescription, productimage, profile, socialaccount, space_admins, space_members, textdocumentation, tutorial, user_permissions, userflags, username, video
I have the following code in models/abstract.py
class BaseModel(models.Model):
added_time = models.DateTimeField('added time')
is_enabled = models.BooleanField(default=True)
score = models.IntegerField(default=0)
class Meta:
abstract = True
app_label = 'catalog'
I have the following in models/article.py
class Article(BaseModel):
url = models.URLField()
title = models.CharField(max_length=500, null=True, blank=True)
description = models.TextField(null=True, blank=True)
image_url = models.URLField(null=True, blank=True)
rating = models.IntegerField()
recommendation = models.TextField(null=True, blank=True)
user = models.ForeignKey(User, null=True, blank=True)
tags = models.ManyToManyField(ArticleTag, null=True, blank=True)
comments = models.ManyToManyField(Comment, null=True, blank=True)
new_user = models.ForeignKey('NewUser', null=True, blank=True)
class Meta:
app_label = 'catalog'
def __unicode__(self):
return self.title + ' (' + self.url + ')'
I have the following in models/core.py, along with many other models which have been listed as the available options.
class Tutorial(BaseModel):
user = models.ForeignKey(User, null=True, blank=True)
description = models.CharField(max_length=200, null=True, blank=True)
url = models.URLField(max_length=200)
votes = models.IntegerField(default=0)
images = models.ManyToManyField(Image, related_name="tutorialimages",
null=True, blank=True)
class Meta:
app_label = 'catalog'
def __unicode__(self):
return self.url
Why is django not picking up my ForeignKey to User from models from rest of the files? Why is it picking it up only from core.py?
I have posted the models and stacktrace at http://pastebin.com/v6hFdvAC and http://pastebin.com/nxYktwHn.
Because not all users have an article. If you see, your user foreign key in Article Class can be null.
user = models.ForeignKey(User, null=True, blank=True)
then when Django tries to apply the count on null values, it raises an error.
Maybe you can use somehthing like that:
User.objects.objects.filter(article__isnull=False).count()

Categories