Question

I've implemented a form where I require fields in the User object to be populated (firstname, lastname, email) as well as fill out a new membership object. I've implemented this with a Function Based View (FBV) but I feel like I should be able to do this with a Class Based View (CBV). The heart of the problem seems to be referencing the current user in a form without passing in the user object. In FBV it's easy to do but I can't find any examples using CBV. I'm thinking that I must be missing something here.

Here is my code

models.py

class Membership(models.Model):

    """Represents an active membership of a user. Both the start_date and
    end_date parameters are inclusive."""

    DEFAULT_DURATION = 365  # the default number of days a membership is active

    start_date = models.DateField(auto_created=True)
    end_date = models.DateField(null=True)
    membership_type = models.ForeignKey(MembershipType)
    referral = models.ForeignKey(User, related_name='membership_referral', null=True)

    # Contact Info
    phone = PhoneNumberField()

    # Address Fields
    address_1 = models.CharField(max_length=255)
    address_2 = models.CharField(max_length=255, blank=True)

    city = models.CharField(max_length=64)
    state = USStateField()
    zip_code = USPostalCodeField()

    def save(self, force_insert=False, force_update=False, using=None,
         update_fields=None):
    """Overload the save function to set the start and end date."""
    self.start_date = datetime.date.today()
    self.end_date = (self.start_date +
                     datetime.timedelta(days=self.membership_type.period))
    super().save()

    @property
    def is_active(self):
    return self.end_date >= datetime.date.today()

forms.py

class MembershipForm(ModelForm):
    """The Form shown to users when enrolling or renewing for membership."""

    def __init__(self, *args, **kwargs):
    self.user = kwargs.pop("user", None)

    _fields = ('first_name', 'last_name', 'email',)
    _initial = model_to_dict(self.user, _fields) if self.user is not None else {}

    super(MembershipForm, self).__init__(initial=_initial, *args, **kwargs)
    self.fields.update(fields_for_model(User, _fields))
    self.fields['referral'].required = False

    class Meta:
    model = Membership
    fields = ['membership_type', 'referral', 'phone', 'address_1',
              'address_2', 'city', 'state']

    zip_code = USZipCodeField(max_length=5, required=True)

    def save(self, *args, **kwargs):
    self.user.first_name = self.cleaned_data['first_name']
    self.user.last_name = self.cleaned_data['last_name']
    self.user.email = self.cleaned_data['email']
    self.user.save()
    profile = super(MembershipForm, self).save(*args, **kwargs)
    return profile

views.py

@login_required
def enroll(request):
    template_name = 'enroll.html'

    if request.method == 'POST':
    form = MembershipForm(request.POST, user=request.user)

    if form.is_valid():
        form.save()
        return redirect('/')
    else:
    form = MembershipForm(user=request.user)

    return render(request, template_name, {'form': form})
Was it helpful?

Solution

You can access current user in class based view by self.request.user. It can be set in FormView by redefining validate method like this:

class YourView(CreateView)
    ...

    def form_valid(self, form):
        form.instance.user = self.request.user
        return super(YourView, self).form_valid(form)

I have used CreateView instead of FormView in example because for edit you should check current instance's user in additional for security purposes.

OTHER TIPS

Although your question mentions CBV, yet in the code you are using FBV.

In FBV you have access to request variable being passed. You can use request.user in this case.

In case of CBVs, Django allows you to access request object as self.request. In the implementation of default 'django.views.generic.base.View' class of CBV, they do this as first thing.

Check 4th line of def view as part of as_view in this code - https://github.com/django/django/blob/master/django/views/generic/base.py

All the objects, including user as part of request can be accessed as self.request.user.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top