2

I have created a function that can save multiple goals per one user and display them in an html file. The issue is once I logout, I cannot log back in with the same user as I get the error User object has no attribute Goals, even though it is saved in the database. My question is what is causing this error, the references to goals in my view maybe, and what is a potential solution? Thank you!

models.py

class Goals(models.Model):
    user = models.ForeignKey(User, null=True, default=None, on_delete=models.CASCADE)
    goal = models.CharField(max_length=2000)
    instrument = models.CharField(max_length=255, choices=instrument_list, blank=True)
    goal_date = models.DateField(auto_now=False, auto_now_add=False)

    def __str__(self):
        return self.Goals


@receiver(post_save, sender=User)
def create_user_goals(sender, instance, created, **kwargs):
    if created:
        Goals.objects.create(user=instance)

@receiver(post_save, sender=User)
def save_user_goals(sender, instance, **kwargs):
    instance.Goals.save()


class GoalsForm(ModelForm):
    class Meta:
        model = Goals
        exclude = ('user',)

views.py

def goal_creation(request):
    form = GoalsForm()
    cur_goals = Goals.objects.filter(user=request.user)

    if request.method == 'POST':
        form = GoalsForm(request.POST)

        if form.is_valid():
            goals = form.save(commit=False)
            goals.user = request.user
            goals.save()
            cur_goals = Goals.objects.filter(user=request.user)
            return redirect('/student/goal-progress')

        else:
            form = GoalsForm()

    context = {'form' : form, 'goals': cur_goals}
    return render(request, 'student/goal_creation.html', context)
Kyle
  • 105
  • 3
  • Your `__str__` is not working, and change `instance.Goals.save()` to `instance.goals.save()` and you don't need to define `cur_goals = Goals.objects.filter(user=request.user)` after `goals.save()` – Bidhan Majhi Jan 30 '19 at 05:48

2 Answers2

3

You have two issues:

  1. You can't access child instances using instance.Goals; you should use instance.goals_set.

  2. You can't save a queryset. You should save Goals instances one by one, i.e.

for goal in instance.goals_set.all():
    goal.save()

That being said, I recommend you to rename your Goals class to Goal as it will create confusion with Django's naming conventions. It also makes sense because each row represents a single goal.

Selcuk
  • 57,004
  • 12
  • 102
  • 110
  • Do i need to change my def __str__ and def create_user_goals because they use the Goals object, instead of goal? Wondering the same thing for the goals items in my views as well –  Jan 30 '19 at 03:46
  • That `__str__` method does not make sense as it already applies to a `Goals` instance anyway, but yes, you should remove that too. `create_user_goals` looks fine as it creates a new model instance using the `Goals` class. – Selcuk Jan 30 '19 at 03:55
  • Also, I am getting the error, 'User' object has no attribute 'goals', when I try to log in. The issue is still present for some reason –  Jan 30 '19 at 04:42
  • 1
    Commerce You should consider accepting the answer if that fix's your problem as I did here: https://stackoverflow.com/questions/54405412/increment-object-count-using-same-form in your previous question. – Ahtisham Jan 30 '19 at 05:37
0

Try adding related_name='goals' to user field definition of Goals class:

user = models.ForeignKey(User, related_name='goals', null=True, default=None, on_delete=models.CASCADE)

Then, you should be able to access this property on the user's object: user_instance.goals.all().

Migration might be required.

Although this is not directly related to the issue, I think that it's better to name the model class in singular form "Goal", it will be consistent with other model's names (model represents one object=one row) and avoid ambiguity in automatic pluralization.

Vitali Kaspler
  • 1,340
  • 10
  • 16