0

So, this question has been asked multiple times, but I'm having a hard time applying those solutions to my app.

Models:

    class User(models.Model):
    name = models.CharField(max_length=45)
    alias = models.CharField(max_length=45)
    email = models.EmailField()
    password = models.CharField(max_length=45)
    objects = UserManager()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    def __str__(self):
        return self.name

class Author(models.Model):
    name = models.CharField(max_length=45)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    def __str__(self):
        return self.name

class Book(models.Model):
    title = models.CharField(max_length=45)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)    
    author = models.ForeignKey(Author)
    user = models.ManyToManyField(User, related_name='books')
    def __str__(self):
        return self.title

class Review(models.Model):
    content = models.TextField()
    rating = models.IntegerField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    user = models.ManyToManyField(User, related_name='reviews')
    book = models.ManyToManyField(Book, related_name='reviews'

Views, the error pops up at the first except when trying to create a new author.

def add_book(request):

    if request.method == 'POST':
        user = User.objects.get(pk=request.session['user_id'])

        data = {
            'title':request.POST['title'],
            'content':request.POST['review'],
            'rating':request.POST['rating'],
        }

        #Create new author or add author 
        author_name = request.POST['new_author']
        print 'About to see if a new author was provided'
        if len(author_name) > 0:
            try:
                print ' Trying to get existin author '
                author = Author.objects.get(name=author_name)
            except:
                print 'Trying to create a new author'
                Author.objects.create(name=author_name)
        else:            
            print 'About to set author to existing author '
            author_name = request.POST['author']
            author = Author.objects.get(name=author_name)
        print 'Author is ', author

        #Create book entry
        try:
            book = Book.objects.get(name=data['title'])
        except:
            book = Book.objects.create(name=data['title'], author=author, user=user)
            print 'New book added'



    return redirect('/books')

Error:

IntegrityError at /add_book
book_app_author.book_id may not be NULL
Request Method: POST
Request URL:    http://127.0.0.1:8000/add_book
Django Version: 1.11.1
Exception Type: IntegrityError
Exception Value:    
book_app_author.book_id may not be NULL
Exception Location: C:\Users\kamar\Desktop\DojoAssignments\django\djangoEnv\djangoEnv\lib\site-packages\django\db\backends\sqlite3\base.py in execute, line 328
Python Executable:  C:\Users\kamar\Desktop\DojoAssignments\django\djangoEnv\djangoEnv\Scripts\python.exe
Python Version: 2.7.10
Python Path:    
['C:\\Users\\kamar\\Desktop\\DojoAssignments\\django\\new_belt',
 'C:\\windows\\SYSTEM32\\python27.zip',
 'C:\\Users\\kamar\\Desktop\\DojoAssignments\\django\\djangoEnv\\djangoEnv\\DLLs',
 'C:\\Users\\kamar\\Desktop\\DojoAssignments\\django\\djangoEnv\\djangoEnv\\lib',
 'C:\\Users\\kamar\\Desktop\\DojoAssignments\\django\\djangoEnv\\djangoEnv\\lib\\plat-win',
 'C:\\Users\\kamar\\Desktop\\DojoAssignments\\django\\djangoEnv\\djangoEnv\\lib\\lib-tk',
 'C:\\Users\\kamar\\Desktop\\DojoAssignments\\django\\djangoEnv\\djangoEnv\\Scripts',
 'C:\\Python27\\Lib',
 'C:\\Python27\\DLLs',
 'C:\\Python27\\Lib\\lib-tk',
 'C:\\Users\\kamar\\Desktop\\DojoAssignments\\django\\djangoEnv\\djangoEnv',
 'C:\\Users\\kamar\\Desktop\\DojoAssignments\\django\\djangoEnv\\djangoEnv\\lib\\site-packages']
Server time:    Mon, 29 May 2017 17:08:42 +0000

3 Answers3

0

You should really be doing all of this with two model forms and use the built in is_valid and save() method. Then it's very easy to get past this issue.

Also, to get the current user just use request.user instead of looking it up in the db.

After you changed your view to model forms you can use this approach without any problems

After your comment: Try this:

       if len(author_name) > 0:
            try:
                print ' Trying to get existin author '
                author = Author.objects.get(name=author_name)
            except:
                print 'Trying to create a new author'
                author = Author.objects.create(name=author_name) # you did not set the author here
        else:            
            print 'About to set author to existing author '
            author_name = request.POST['author']
            author = Author.objects.get(name=author_name)
Kritz
  • 7,099
  • 12
  • 43
  • 73
  • Unfortunately, I am not advanced enough to do it the way you propose, and I am working on a boot-camp project. Short of restructuring everything, would you know how to fix what I've built so far? Whatever the case, thanks for your help. – Kamil Wowczuk May 29 '17 at 17:29
  • See the updated answer. If you want to improve your Django skills I suggest you go through the docs/tutorial again. – Kritz May 29 '17 at 17:41
  • Unfortunately, that still didn't help. Still getting the same error. – Kamil Wowczuk May 29 '17 at 18:38
0

Using a model form would make this view much more compact, but having the case I would think about making some changes in your views.

Edit your views like this,

def add_book(request):
    if request.method == 'POST':
        user = request.user
        data = {
            'title':request.POST.get('title'),
            'content':request.POST.get('review'),
            'rating':request.POST.get('rating'),
        }
        author_name = request.POST.get('new_author')
        if author_name:
            author, created = Author.objects.get_or_create(name=author_name)
        else:            
            author_name = request.POST.get('author')
            author = Author.objects.get(name=author_name)
        try:
            book = Book.objects.get(title=data['title'])
        except:
            book = Book.objects.create(title=data['title'], author=author)
        book.user.add(user)
        book.save()
    return redirect('/books')
zaidfazil
  • 9,017
  • 2
  • 24
  • 47
0

I have tested your code. I think you have an outdated sqlite database.

Please try followings,

  • Deleting your sqlite db
  • re-generate migrations via python manage.py makemigrations,
  • Update db by python manage.py migrate

There are some parts of the code needs to be fixed.

First, Book model do not have name field.

So, this line needs to be fixed.

book = Book.objects.create(name=data['title'], author=author, user=user)

This will be,

book = Book.objects.create(title=data['title'], author=author)

2nd, You can't assign many to many field user like this,

book = Book.objects.create(name=data['title'], author=author, user=user)

Correct format would be,

book = Book.objects.create(title=data['title'], author=author)

book.user.add(user)

For you convenience, I have uploaded a fixed version of the app.

https://github.com/ibrahim12/stackoverflow_question_solve

Ibrahim
  • 584
  • 6
  • 15