Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot assign must be a instance. Django

Ive been trying to create a django project that has users and those users can add titles of books they have created. But each time I enter a book title (not on the admin page) I get this error

Cannot assign "u'Hello Wold'": "Scripter.title" must be a "Book" instance.

models.py

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

class Book(models.Model):
    script_title = models.CharField(max_length=100)

    def __unicode__(self):
        return self.script_title

class Scripter(models.Model):
    user = models.OneToOneField(User)
    name = models.CharField(max_length=30)
    title = models.ForeignKey(Book, null=True, blank=True, default=None)

    def __unicode__(self):
        return self.name

forms.py

from django import forms
from django.contrib.auth.models import User
from django.forms import ModelForm
from scripters.models import Scripter#, Book

class RegistrationForm(ModelForm):
    username = forms.CharField(label=(u'User Name'))
    email = forms.EmailField(label=(u'Email Address'))
    password = forms.CharField(label=(u'Password'), widget=forms.PasswordInput(render_value=False))
    password1 = forms.CharField(label=(u'Verify Password'), widget=forms.PasswordInput(render_value=False))

    class Meta:
        model = Scripter
        exclude = ('user','title')

    def clean_username(self):
        username = self.cleaned_data['username']
        try:
            User.objects.get(username=username)
        except User.DoesNotExist:
            return username
        raise forms.ValidationError("User Name has been taken!")

    def clean(self):
        if self.cleaned_data['password'] != self.cleaned_data['password1']:
            raise forms.ValidationError("The passwords did not match")
        else:
            return self.cleaned_data

class LoginForm(forms.Form):
    username = forms.CharField(label=(u'Username'))
    password = forms.CharField(label=(u'Password'), widget=forms.PasswordInput(render_value=False))

class CreateScript(ModelForm):
    title = forms.CharField(label=(u'Script Title'))

    class Meta:
        model = Scripter
        exclude = ('user','name',)

    def clean_title(self):
        title = self.cleaned_data['title']
        return title

views.py

from django.http import HttpResponseRedirect
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
from django.shortcuts import render_to_response
from django.template import RequestContext
from scripters.forms import RegistrationForm, LoginForm, CreateScript
from scripters.models import Scripter, Book
from django.contrib.auth import authenticate, login, logout

def ScripterRegistration(request):
    if request.user.is_authenticated():
        return HttpResponseRedirect('/profile/')
    if request.method =='POST':
        form = RegistrationForm(request.POST)
        if form.is_valid():
            user = User.objects.create_user(username=form.cleaned_data['username'],
                email = form.cleaned_data['email'],
                password = form.cleaned_data['password']
            )
            user.save()
            scripter = Scripter(user=user, name=form.cleaned_data['name'])
            scripter.save()

            return HttpResponseRedirect('/profile/')
        else:
            return render_to_response('index.html', {'form': form}, context_instance=RequestContext(request))
    else:
        form = RegistrationForm()
        context = {'form': form}
        return render_to_response('index.html', context, context_instance=RequestContext(request))

@login_required
def Profile(request):
    if not request.user.is_authenticated():
        return HttpResponseRedirect('/login/')
    Scripter = request.user.get_profile()

    context = {'Scripter': Scripter, 'Book': Book}
    return render_to_response('profile.html', context, context_instance=RequestContext(request))

def LoginRequest(request):
    if request.user.is_authenticated():
        return HttpResponseRedirect('/profile/')
    if request.method == 'POST':
        submit = LoginForm(request.POST)
        if submit.is_valid():
            username = submit.cleaned_data['username']
            password = submit.cleaned_data['password']
            scripter = authenticate(username=username, password=password)
            if scripter is not None:
                login(request, scripter)
                return HttpResponseRedirect('/profile/')
            else:
                return HttpResponseRedirect('/login/')
    else:
        submit = LoginForm()
        context = {'submit': submit}
        return render_to_response('login.html',context, context_instance=RequestContext(request))

def LogoutRequest(request):
    logout(request)
    return HttpResponseRedirect('/login/')

@login_required
def NewScript(request):
    if not request.user.is_authenticated():
        return HttpResponseRedirect('/login/')
    if request.method =='POST':
        title_form = CreateScript(request.POST)
        if title_form.is_valid():
            new_script = Book.objects.get_or_create(
                script_title = title_form.cleaned_data['title']
            )
            new_script.save()
            script = Book(script_title=title_form.cleaned_data['title'])
            script.save()
            return HttpResponseRedirect('/edit/')
        else:
            return render_to_response('NewScript.html', {'title_form': title_form}, context_instance=RequestContext(request))
    else:
        title_form = CreateScript()
        context = {'title_form': title_form}
        return render_to_response('NewScript.html', context, context_instance=RequestContext(request))
like image 291
joshua Avatar asked May 10 '12 13:05

joshua


2 Answers

First, while this is not your question, i believe you missed something. If I understand correctly, you wish Scripters to have MULTIPLE books. Now, with your models, they can only have one book. If I'm correct as of what you are trying to achieve, your model should rather look like this:

class Book(models.Model):
  script_title = models.CharField(max_length=100)
  scripter = models.ForeignKey(Scripter)#A book "remembers" who wrote it

  def __unicode__(self):
    return self.script_title

class Scripter(models.Model):
  user = models.OneToOneField(User)
  name = models.CharField(max_length=30)
  #Scripter can write multiple books, can't he? So the next line is removed,
  #replaced by an extra line in Book class

  # title = models.ForeignKey(Book, null=True, blank=True, default=None)

Then you would access Scripter's books like this:

scripter = Scripter.objects.get(name="joshua")
books = scripter.book_set.all() #all books written by joshua

As for your question, in current form, you would need to do something like this:

book = Book.objects.get(script_title="some_title")
scripter.title = book

But as I said before, you need to change your model structure, so you will be rather doing:

scripter = Scripter.objects.get(name="joshua")
book = Book.objects.Create(script_title="some title",scripter=scripter)
like image 118
Marcin Kulus Avatar answered Oct 20 '22 09:10

Marcin Kulus


Of course. Not sure where the confusion here is. Scripter.title is a foreign key to Book, so you must give it an actual Book, not a string.

like image 30
Chris Pratt Avatar answered Oct 20 '22 08:10

Chris Pratt