NightOwl19
NightOwl19

Reputation: 428

updating a model attribute in django using form

I am trying to update a model field in my django app. the application is such that there are two models, Project and Contractor. and their relation is like each project can assign multiple contractors and each contractor can work on multiple projects..and both project and contractor are associated to a Client Model..my models.py:

class UserProfile(models.Model):    ## the client is the user
   user=models.OneToOneField(User)
   def __unicode__(self):
   return self.user.username

class Contractor(models.Model): ##unhired contractors
   name=models.CharField(max_length=128)
   url=models.URLField()
   bill_rate=models.IntegerField(default=0)
   slug=models.SlugField(unique=True)
   def save(self, *args, **kwargs):
   self.slug=slugify(self.name)
   super(Contractor, self).save(*args, **kwargs)
   def __unicode__(self):
        return self.name

class Project(models.Model):
   contractor=models.ManyToManyField(Contractor, null=True)
   client=models.ForeignKey(UserProfile, null=True)
   title=models.CharField(max_length=128)
   slug=models.SlugField(unique=True)
   def save(self, *args, **kwargs):
       self.slug=slugify(self.title)
       super(Project, self).save(*args, **kwargs)
   def __unicode__(self):
       return self.title

and forms.py is:

class ProjectForm(forms.ModelForm):
    title=forms.CharField(max_length=128)
    slug=forms.CharField(widget=forms.HiddenInput(), required=False)
    class Meta:
       model=Project
       fields=('title','contractor')

class ContractorForm(forms.ModelForm): ##the contractor first register itself separately and is later added to the project while a project is been created
    name=forms.CharField(max_length=128, help_text="Please enter your name or your firm's name: ")
    bill_rate=forms.IntegerField(initial=0, help_text="Please enter your Bill rate")
    url=forms.CharField(max_length=128, help_text="Please enter your web-details: ")
    slug=forms.CharField(widget=forms.HiddenInput(), required=False)
    class Meta:
       model=Contractor
       fields=('name','bill_rate','url',)

and here is the view in which i'm trying to update my contractor attribute:

  def addContractorToUnaddedProjects(request):
     if request.method=="POST":
        project=ProjectForm(request.POST)
        if project.is_valid():
           project.save(commit=True)
        else:
           print project.errors
     else: 
       project=ProjectForm()
    return render(request, 'keeper/addContractorToUnaddedProject.html', {'form':update,})

so whenever i try run this code instead of updating only the contractor field, a whole new project is created..to update a new contractor for a project i'm directing the project page which currently have no contractor to "addnewcontractor" page & there i'm using project form but instead of using title and contractor both, i'm getting input only for the contractor field..what am i doing wrong here?

here's the html code i am using to update the contractor for already created project:

{% extends 'base.html' %}
{% load staticfiles %}
{% block title %}Add Contractor{% endblock %}
{% block body_block %}
<h1>Add a Contractor from our available Contractors!!</h1>
<form id="add_contractor_unadded" method="post" action="/keeper/addContractorToUnaddedProject/">
{% csrf_token %}
    <strong><h4>Please select a contractor: {{ form.contractor }}</h4></strong>
<input type="submit" name='submit' value="ADD" />
</form>
<h2><a href="/keeper/dashboard/">Home</a></h2>
{% endblock %}

Upvotes: 0

Views: 1681

Answers (2)

Lutfar Rahman Milu
Lutfar Rahman Milu

Reputation: 121

This line always creates a new instance. It doesn't update anything.

project.save(commit=True)

What you need is doing update with form. here is the hint:

 project = Project.objects.get(pk = id)
 projectform=ProjectForm(request.POST,instance=project)
    if projectform.is_valid():
       projectform.save(commit=True)
    else:
       print projectform.errors

Upvotes: 0

bruno desthuilliers
bruno desthuilliers

Reputation: 77932

You say that "each project can assign multiple contractors" but that not how your model works - it allows a single contractor per project:

class Project(models.Model):
    contractor=models.ForeignKey(Contractor, null=True)

ForeignKey if for one to many relationships - here a Project has zero or one Contractor and a Contractor has zero, one or many Projects.

If you want to have many contractors per project, you have to use a many to many relationship, which in Django is built using a ManyToManyField:

class Project(models.Model):
    contractors = models.ManyToManyField(Contractor, null=True)

Now with your view... Well, how to say... It's a total nonsense.

First, you use a ProjectForm without passing it a Project instance - this is the way to create a new Project (using form.save() which you don't call), but not to edit an existing one. If you want to edit an existing Project, get your Project instance and pass it to the form (as documented for modelforms).

Then you have this quadruple nonsense:

old_contractor = Project.objects.get(contractor='contractor')

This just cannot work... At the very least it should be

old_contractor = Project.objects.get(contractor__name='contractor')

which would still be a triple nonsense :

  1. you name your object 'old_contractor' but it's a Project
  2. for this to work, you have to have a contractor named "contractor" and it has to have one single project (else you get either an ObjectDoesNotExist or a MultipleObjectsReturned error
  3. you then update this project with the contractor selected in your form.

FWIW, there's not a single chance this code creates a new project since you dont call the form's save() method.

So to answer your question ("what am i doing wrong here?"), I'm afraid the answer is along the line of "everything".

Upvotes: 2

Related Questions