ollysmall
ollysmall

Reputation: 663

Need help getting correct instance for form_valid in a generic view

I can't work out how to get the correct instance for the form_valid part of my generic view. I am trying to allow a user to post on their project wall(bit like Facebook). I need the post to be related to an individual project(a user can have more than one project). Should the instance be a pk or the project title? Any example code or help would be very appreciated! I struggle understanding how when you create a new post, it knows which project to associate itself with.

views

class NewPost(CreateView):
    model = ProjectPost
    form_class = ProjectPostForm
    template_name = 'howdidu/new_post.html'

    def form_valid(self, form):
        newpost = form.save(commit=False)
        form.instance.user = self.request.user
        newpost.save()
        self.object = newpost
        return super(NewPost, self).form_valid(form)

    def get_success_url(self):
        project_username = self.request.user.username
        project_slug = self.object.slug
        return reverse('user_project', kwargs={'username':project_username, 'slug': project_slug})

models

class UserProject(models.Model):
    user = models.ForeignKey(User)
    title = models.CharField(max_length=100)
    project_overview = models.CharField(max_length=1000)
    project_picture = models.ImageField(upload_to='project_images', blank=True)
    date_created = models.DateTimeField(auto_now_add=True)
    project_views = models.IntegerField(default=0)
    project_likes = models.IntegerField(default=0)
    project_followers = models.IntegerField(default=0)
    slug = models.SlugField(max_length=100, unique=True) #should this be unique or not?

    def save(self, *args, **kwargs):
        self.slug = slugify(self.title)
        super(UserProject, self).save(*args, **kwargs)

    def __unicode__(self):
        return self.title

class ProjectPost(models.Model):
    project = models.ForeignKey(UserProject)
    title = models.CharField(max_length=100)
    post_overview = models.CharField(max_length=1000)
    date_created = models.DateTimeField(auto_now_add=True)
    post_views = models.IntegerField(default=0)
    post_likes = models.IntegerField(default=0)

forms

#form to add project details
class UserProjectForm(forms.ModelForm):

    class Meta:
        model = UserProject
        fields = ('title', 'project_picture', 'project_overview')

#form to create a post
class ProjectPostForm(forms.ModelForm):

    class Meta:
        model = ProjectPost
        fields = ('title', 'post_overview')

Upvotes: 2

Views: 1307

Answers (1)

dkarchmer
dkarchmer

Reputation: 5604

Ok, in that case, I would recommend a URL something like

url(r'^(?P<pk>\d+)/post/add/$', views.NewPostCreateView.as_view(), name='...'),

and then a view like

class NewPost(CreateView):
   model = ProjectPost
   form_class = ProjectPostForm
   template_name = 'howdidu/new_post.html'

   def form_valid(self, form):
      self.object = form.save(commit=False)

      # Find project by using the 'pk' in the URL
      project = get_object_or_404(UserProject, pk=self.kwargs['pk'])

      # Then just set the project on the newPost and save()
      self.object.project = project
      self.object.save()

      return super(NewPost, self).form_valid(form)

   def get_success_url(self):
      # Unchanged ...

I see in your code that you were trying to do something with the user but I don't understand why your Post does not have a user field (you may want to add a created_by) and the UserProject should already have a user set.

I am also assuming the user got to the his/her project first, so you know by definition that the project he is adding a post to is his. If that is not the case, then just change the logic to get the UserProject through a regular query. e.g. maybe with `UserProject.objects.get(user = self.request.user) if there is one project per user (again, just as an example).

Anyway, I am making some assumptions here, but hopefully the main question was how to set the project on the newPost and that is answered in my example.

Upvotes: 2

Related Questions