Matt McCarthy
Matt McCarthy

Reputation: 484

'NoneType' object has no attribute '_meta' while changing models

I am attempting to restructure my database models to include more data than django.contrib.auth.models.User. However, making the changes to models.py and views.py, then running python manage.py makemigrations doesn't properly update my migrations. Apparently, Django still thinks I'm using a proxy model.

I had to change users/migrations/0001_initial.py to avoid a dependency error, then I ran python manage.py makemigrations and got No changes detected.

users/migrations/0001_initial.py (before changes)

# Generated by Django 2.2 on 2019-05-01 03:13

from django.db import migrations
import users.managers


class Migration(migrations.Migration):

    initial = True

    dependencies = [
        ('auth', '0011_update_proxy_permissions'),
    ]

    operations = [
        migrations.CreateModel(
            name='Person',
            fields=[
            ],
            options={
                'proxy': True,
                'constraints': [],
                'indexes': [],
            },
            bases=('auth.user',),
            managers=[
                ('objects', users.managers.PersonManager()),
            ],
        ),
    ]

users/migrations/0001_initial.py (after changes)

# Generated by Django 2.2 on 2019-05-01 03:13

from django.db import migrations
import users.managers


class Migration(migrations.Migration):

    initial = True

    dependencies = []

    operations = []


users/models.py (before changes)

from django.db import models
from django.contrib.auth.models import User
from . import managers

class Person(User):
    objects = managers.PersonManager()

    class Meta:
        proxy = True

users/models.py (after changes)

from django.db import models
from django.contrib.auth.models import User
from users import managers

class Profile:
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    phone = models.CharField(max_length=30)
    objects = managers.ProfileManager()

users/views.py

from django.shortcuts import render, redirect
from django.contrib.auth.models import User
from users.models import Profile

def index(request):
    profile = Profile.objects.get(user_pk=request.session['id']) \
        if 'id' in request.session else None

    return render(request, 'users/index.html', {
        'profile': profile,
    })


def login(request):
    valid, response = Profile.objects.login_register(request, 'login')

    if not valid:
        for error in response:
            messages.error(request, error)
        return redirect('users:index')

    profile = Profile.objects.get(pk=response)
    messages.success(request, 'Welcome back, %s!' % profile.user.first_name)
    request.session['id'] = response
    return redirect('users:index')


def register(request):
    valid, response = Profile.objects.login_register(request, 'register')

    if not valid:
        for error in response:
            messages.error(request, error)
        return redirect('users:index')

    messages.success(request, 'You have successfully created an account.')
    request.session['id'] = response
    return redirect('users:index')


def logout(request):
    del request.session['id']

    messages.success(request, 'You have successfully logged out.')
    return redirect('users:index')

When I try to login or register, I expect the page to reload with the login/registration form changed to the user's profile page.

Error message

Internal Server Error: /profile/
Traceback (most recent call last):
  File "/home/matt/Repositories/pharmasseuse/env/lib/python3.5/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/home/matt/Repositories/pharmasseuse/env/lib/python3.5/site-packages/django/core/handlers/base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/home/matt/Repositories/pharmasseuse/env/lib/python3.5/site-packages/django/core/handlers/base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/matt/Repositories/pharmasseuse/users/views.py", line 12, in index
    if 'id' in request.session else None
  File "/home/matt/Repositories/pharmasseuse/env/lib/python3.5/site-packages/django/db/models/manager.py", line 82, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/home/matt/Repositories/pharmasseuse/env/lib/python3.5/site-packages/django/db/models/query.py", line 399, in get
    clone = self.filter(*args, **kwargs)
  File "/home/matt/Repositories/pharmasseuse/env/lib/python3.5/site-packages/django/db/models/query.py", line 892, in filter
    return self._filter_or_exclude(False, *args, **kwargs)
  File "/home/matt/Repositories/pharmasseuse/env/lib/python3.5/site-packages/django/db/models/query.py", line 910, in _filter_or_exclude
    clone.query.add_q(Q(*args, **kwargs))
  File "/home/matt/Repositories/pharmasseuse/env/lib/python3.5/site-packages/django/db/models/sql/query.py", line 1290, in add_q
    clause, _ = self._add_q(q_object, self.used_aliases)
  File "/home/matt/Repositories/pharmasseuse/env/lib/python3.5/site-packages/django/db/models/sql/query.py", line 1318, in _add_q
    split_subq=split_subq, simple_col=simple_col,
  File "/home/matt/Repositories/pharmasseuse/env/lib/python3.5/site-packages/django/db/models/sql/query.py", line 1190, in build_filter
    lookups, parts, reffed_expression = self.solve_lookup_type(arg)
  File "/home/matt/Repositories/pharmasseuse/env/lib/python3.5/site-packages/django/db/models/sql/query.py", line 1049, in solve_lookup_type
    _, field, _, lookup_parts = self.names_to_path(lookup_splitted, self.get_meta())
  File "/home/matt/Repositories/pharmasseuse/env/lib/python3.5/site-packages/django/db/models/sql/query.py", line 297, in get_meta
    return self.model._meta
AttributeError: 'NoneType' object has no attribute '_meta'

Any help is appreciated.

Upvotes: 0

Views: 266

Answers (1)

ruddra
ruddra

Reputation: 51948

I don't think its a good idea to change in migrations files. You can do the changes in model directly, and after changing the model, run ./manage.py makemigrations to generate new migration files.

Also, you need to subclass the model class from models.Model:

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    phone = models.CharField(max_length=30)
    objects = managers.ProfileManager()

Update

(from comments) As your manager has been changed, I think you can proceed with either one of the following solutions:

  1. Keep both ProfileManager and PersonManager in users.manager, then run makemigrations.
  2. Update the migration file like this(remove managers attribute from dictionary):
# Generated by Django 2.2 on 2019-05-01 03:13

from django.db import migrations
import users.managers


class Migration(migrations.Migration):

    initial = True

    dependencies = [
        ('auth', '0011_update_proxy_permissions'),
    ]

    operations = [
        migrations.CreateModel(
            name='Person',
            fields=[
            ],
            options={
                'proxy': True,
                'constraints': [],
                'indexes': [],
            },
            bases=('auth.user',),
            # managers=[
            #     ('objects', users.managers.PersonManager()),
            # ],
        ),
    ]

Upvotes: 1

Related Questions