Updating User when submitting form - python

The scenario is that I'm building an app for users to submit payment and gain or renew "Member" status to the site. If an anonymous person wants to create an account all that's required is an email and a password but for membership we're going to want the User.firstname and User.lastname to be filled in as well. I'm not sure how best to incorporate this requirement in the "enrolment" form. Any guidance on approach or best practices welcome.
Here is the code I'm working with
class MembershipType(models.Model):
"""The represents the type of membership that may be offered."""
active = models.BooleanField(default=True)
long_name = models.CharField(max_length=255)
period = models.PositiveIntegerField() # The number of days the membership is good for
accounts = models.PositiveSmallIntegerField() # The number of accounts that it supports
price = models.DecimalField(max_digits=5,
decimal_places=2)
def __unicode__(self):
return self.long_name
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')
# 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()
#property
def is_active(self):
return self.end_date >= datetime.date.today()
class MembershipUser(models.Model):
"""Simple relationship that associates a single user to a membership object"""
user = models.OneToOneField(User)
membership = models.ForeignKey(Membership)
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
if (self.membership.membership_type.accounts ==
MembershipUser.objects.filter(membership=self.membership).count()):
raise NotImplementedError("The Membership %s, already has it's "
"maximum number of accounts associated "
"with it." % self.membership.id)
Also, as you may see from that code I have to support to idea of a single user purchasing membership that may be used for for than one user. A use case here is a "Couple's" membership.

The way I implemented it is this. It seems to handle everything jsut fine and will prepoluate the user's info. I feel like I should be able to reference the user object and not have to pass it back in but it works.
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})

Related

Django saving data in model through model form and foreign key

I have a model named Doctor and a model named Appoint which have doctor as a foreign key. and I have a model form to take input for the Appoint model but not for the foreign key in it. I am able to link the Doctor model through url but I am not able to save doctor(foreign key) in Appoint model.
here are the 2 models:-
``` class Doctor(models.Model):
docid = models.IntegerField(null=True, default=1001)
name = models.CharField(max_length=40)
phone = models.IntegerField()
add = models.TextField()
email = models.EmailField()
category = models.CharField(choices=doc_cat,max_length=20)
price = models.IntegerField()
def __str__(self):
return self.name
class Appoint(models.Model):
f_name = models.CharField(max_length=12)
l_name = models.CharField(max_length=12)
phone1 = models.IntegerField()
phone2 = models.IntegerField()
add = models.CharField(max_length=100)
city = models.CharField(max_length=20)
state = models.CharField(max_length=30)
pincode = models.IntegerField()
doctor = models.ForeignKey(Doctor,null=True, on_delete=models.CASCADE)
day = models.CharField(max_length=30)
timeslot = models.CharField(max_length=30)
symptom = models.CharField(max_length=200)
email = models.EmailField()
date = models.DateField(auto_now=True)
def __str__(self):
return self.f_name + self.l_name```
here is the view method:-
``` def takeappointment(request, docid):
doctor = Doctor.objects.get(docid = docid)
if request.method == 'POST':
form = Appointform(request.POST)
if form.is_valid():
form.save()
f_name = request.POST['f_name']
l_name = request.POST['l_name']
day = request.POST['day']
timeslot = request.POST['timeslot']
email = request.POST['email']
return render(request, 'submit.html', {
'f_name' : f_name,
'l_name' : l_name,
'day' : day,
'timeslot' : timeslot,
'email' : email,
})
form = Appointform()
return render(request, 'takeappointment.html', {'form': form, 'doctor': doctor})
```
how can save the foreign key from Doctor model along with form data in Appoint model?
you can do it this way:
add doctor parameter to your Appointform
class Appointform(forms.ModelForm):
class Meta:
model = Appoint
def __init__(self, *args, **kwargs):
self.from_doctor = kwargs.pop("from_doctor", None)
super().__init__(*args, **kwargs)
def clean(self):
cleaned_data = super().clean()
cleaned_data["doctor"] = self.from_doctor
return cleaned_data
and in your takeappointment view add this parameter when create form
def takeappointment(request, docid):
doctor = Doctor.objects.get(docid = docid)
if request.method == 'POST':
form = Appointform(request.POST, from_doctor=doctor)
if form.is_valid():
form.save()
f_name = request.POST['f_name']
l_name = request.POST['l_name']
day = request.POST['day']
timeslot = request.POST['timeslot']
email = request.POST['email']
return render(request, 'submit.html', {
'f_name' : f_name,
'l_name' : l_name,
'day' : day,
'timeslot' : timeslot,
'email' : email,
})
form = Appointform(from_doctor=doctor)
return render(request, 'takeappointment.html', {'form': form, 'doctor': doctor})
you also need to change definition of Appoint model, add blank=True to your doctor field
doctor = models.ForeignKey(Doctor, null=True, blank=True, on_delete=models.CASCADE)
you can do it other way.
class Appointform(forms.ModelForm):
class Meta:
model = Appoint
exclude = ("doctor", )
def __init__(self, *args, **kwargs):
self.from_doctor = kwargs.pop("from_doctor", None)
super().__init__(*args, **kwargs)
def save(self, *args, **kwargs):
self.instance.doctor = self.from_doctor
return super().save(*args, **kwargs)

what am I doing wrong at the moment to validate my lesson class?

I want to validate if my lesson material belongs to a xyz user with pro right it will show the correct conent, but if not it will display become a member , but however I am getting if I change id membership to pro or vice versa it always true the statement
def get(self, request):
template = loader.get_template(self.template_name)
template_member = loader.get_template(self.template_payment)
#rendering the template in HttpResponse
lesson = Lesson.objects.first()
user_membership = UserMembership.objects.filter(user=self.request.user).first()
user_membership_type = user_membership.membership.membership_type
lesson_allowed_mem_types = lesson.allowed_memberships.all()
if lesson_allowed_mem_types.filter(membership_type=user_membership_type).exists():
return HttpResponse(template.render())
else:
return HttpResponse(template_member.render())
models
class Lesson(models.Model):
allowed_memberships = models.ManyToManyField(Membership)
class Membership(models.Model):
membership_type = models.CharField(
choices=MEMBERSHIP_CHOICES,
default='Free',
max_length=30)
def __str__(self):
return self.membership_type
class UserMembership(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
membership = models.ForeignKey(Membership, on_delete=models.SET_NULL, null=True)
def __str__(self):
return self.user.email
Aren't you just trying to see if the user has a Membership?
if UserMembership.objects.filter(
user=request.user,
membership__membership_type="PAID MEMBER",
).exists():
# user is member
return HttpResponse(template.render())
else:
# user is not a member
return HttpResponse(template_member.render())

get() returned more than one Children -- it returned 2! in django

I have a linked model:
class Children(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
child_name = models.CharField(max_length=150, null=True, blank=True)
slug = AutoSlugField(populate_from='child_name')
blood_group = models.CharField(max_length=5, blank=True)
class Meta:
unique_together = ('slug', 'person')
def get_absolute_url(self):
return self.person.get_absolute_url()
def get_delete_url(self):
return reverse(
'member:children-delete',
kwargs={
'person_slug': self.person.slug,
'children_slug': self.slug})
def get_update_url(self):
return reverse(
'member:children-update',
kwargs={
'person_slug': self.person.slug,
'children_slug': self.slug})
my forms.py:
class ChildrenForm( SlugCleanMixin, forms.ModelForm):
class Meta:
model = Children
exclude = ('person',)
def clean(self):
cleaned_data = super().clean()
slug = cleaned_data.get('slug')
person_obj = self.data.get('person')
exists = (
Children.objects.filter(
slug__iexact=slug,
person=person_obj,
).exists())
if exists:
raise ValidationError(
"Children with this Slug "
"and Person already exists.")
else:
return cleaned_data
def save(self, **kwargs):
instance = super().save(commit=False)
instance.person = (
self.data.get('person'))
instance.save()
self.save_m2m()
return instance
views.py:
class ChildrenCreate( ChildrenFormMixin, ChildrenGetObjectMixin,
PersonContextMixin,CreateView):
template_name = 'member/children_form.html'
model = Children
form_class = ChildrenForm
class ChildrenUpdate(ChildrenFormMixin, ChildrenGetObjectMixin,
PersonContextMixin,UpdateView):
template_name = 'member/children_form.html'
model = Children
form_class = ChildrenForm
slug_url_kwarg = 'children_slug'
class ChildrenDelete(ChildrenFormMixin,ChildrenGetObjectMixin,
PersonContextMixin,DeleteView):
model = Children
slug_url_kwarg = 'children_slug'
def get_success_url(self):
return (self.object.person
.get_absolute_url())
my utils.py:
class ChildrenFormMixin():
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
if self.request.method in ('POST', 'PUT'):
self.person = get_object_or_404(
Person,
slug__iexact=self.kwargs.get(
self.person_slug_url_kwarg))
data = kwargs['data'].copy()
data.update({'person': self.person})
kwargs['data'] = data
return kwargs
class ChildrenGetObjectMixin():
def get_object(self, queryset=None):
person_slug = self.kwargs.get(
self.person_slug_url_kwarg)
children_slug = self.kwargs.get(
self.slug_url_kwarg)
return get_object_or_404(
Children,
slug__iexact=children_slug,
person__slug__iexact=person_slug)
class PersonContextMixin():
person_slug_url_kwarg = 'person_slug'
person_context_object_name = 'person'
def get_context_data(self, **kwargs):
person_slug = self.kwargs.get(
self.person_slug_url_kwarg)
person = get_object_or_404(
Person, slug__iexact=person_slug)
context = {
self.person_context_object_name:
person,
}
context.update(kwargs)
return super().get_context_data(**context)
The children created more than one for same name of same parents. When I tried to edit children it gives "get() returned more than one Children -- it returned 2!" error. In traceback, it said, 'person__slug__iexact=person_slug' is the direct causes of this traceback.
In the form, I added clean method to catch the error and maintain uniqueness of children name of same parents but it not worked. Could I get suggestions where I do wrong?
Edit:
my Person model:
class Person(models.Model):
name = models.CharField(max_length=250)
slug = AutoSlugField(populate_from='name')
birth_date = models.DateField(null=True, blank=True)
blood_group = models.CharField(max_length=5)
present_address = models.CharField(max_length=250, blank=True)
permanent_address = models.CharField(max_length=250, blank=True)
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
related_name='member_persons')
class Meta:
ordering = ['name']
unique_together = ['name', 'birth_date']
I believe you are using AutoSlugField from django-autoslug, and you trying to get by non-unique field. AutoSlugField won't make your field unique by default, from docs:
AutoSlugField can also perform the following tasks on save:
populate itself from another field (using populate_from),
use custom slugify function (using slugify or Settings), and
preserve uniqueness of the value (using unique or unique_with).
None of the tasks is mandatory, i.e. you can have auto-populated non-unique fields, manually entered unique ones (absolutely unique or within a given date) or both.
So quick fix would be slug = AutoSlugField(populate_from='child_name', unique=True)
UPDATE(Since you posted your Person model)
The problem is the same and solution is the same.
Explanation:
For example you have two Person objects:
id name slug birth_date
1 alex alex 10.10.2016
2 alex alex 10.10.2015
This won't violate unique_together = ['name', 'birth_date']
And you got two Children objects:
id name slug person_id
1 john john 1
2 john john 2
And that won't violate unique_together = ('slug', 'person') neither
Then you are making query
get_object_or_404(
Children,
slug__iexact='john',
person__slug__iexact='alex')
Which would match two objects. So you got problem. Quick fix would be to make slug unique=True.

Django filter with ForeignKey not working

I am building ecommerce and having trouble creating dashboard for sellers. No matter how I try to get filter processed orders so I can show sold products to sellers I couldn't make it happen. Some help will be a great relief. Following is my Seller Mixin I am trying to create:
mixins.py
class SellerAccountMixin(LoginRequiredMixin, object):
account = None
products = []
transactions = []
orders = []
def get_account(self):
user = self.request.user
accounts = SellerAccount.objects.filter(user=user)
if accounts.exists() and accounts.count() == 1:
self.account = accounts.first()
return accounts.first()
return None
def get_products(self):
account = self.get_account()
products = Product.objects.filter(seller=account)
self.products = products
return products
def get_all_products(self):
account = self.get_account()
products = Product.objects.all()
self.products = products
return products
def get_sold_products(self):
orders = UserCheckout.objects.get(user_user=self.user)
return orders
seller/views.py:
class SellerDashboard(SellerAccountMixin, FormMixin, View):
form_class = NewSellerForm
success_url = "/seller/"
def post(self, request, *args, **kwargs):
user = self.user
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def get(self, request, *args, **kwargs):
apply_form = self.get_form() #NewSellerForm()
account = self.get_account()
exists = account
active = None
context = {}
if exists:
active = account.active
if not exists and not active:
context["title"] = "Apply for Account"
context["apply_form"] = apply_form
elif exists and not active:
context["title"] = "Account Pending"
elif exists and active:
context["title"] = "Dashboard"
#products = Product.objects.filter(seller=account)
context["products"] = self.get_products()
context["today_sales"] = self.get_today_sales()
context["sold_products"] = self.get_sold_products()
#context["total_profit"] = self.get_total_profit()
else:
pass
return render(request, "sellers/dashboard.html", context)
Above is my seller app and I am bringing the products model with simple features. The problem is that its not letting me get processed orders with UserCheckout model in Orders app. Following is a snapshot of Orders app.
Orders/models.
class UserCheckout(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, null=True, blank=True)
email = models.EmailField(unique=True)
def __unicode__(self):
return self.email
ADDRESS_TYPE = (
('billing', 'Billing'),
('shipping', 'Shipping'),
)
class UserAddress(models.Model):
user = models.ForeignKey(UserCheckout)
type = models.CharField(max_length=120, choices=ADDRESS_TYPE)
street = models.CharField(max_length=120)
city = models.CharField(max_length=120)
state = models.CharField(max_length=120)
zipcode = models.CharField(max_length=120)
def __unicode__(self):
return self.street
def get_address(self):
return "%s, %s, %s, %s" %(self.street, self.city, self.state, self.zipcode)
CHOICES = (
('CreditCard', "CreditCard"),
('Cash On Delivery', 'Cash On Delivery'),
('PayPal', 'PayPal'),
)
ORDER_STATUS_CHOICES={
('created','Created'),
('paid','Paid'),
}
class Order(models.Model):
status = models.CharField(max_length=120, choices=ORDER_STATUS_CHOICES, default='created')
cart = models.ForeignKey(Cart)
user = models.ForeignKey(UserCheckout, null=True)
billing_address = models.ForeignKey(UserAddress, related_name='billing_address', null=True)
shipping_address = models.ForeignKey(UserAddress, related_name='shipping_address', null=True)
shipping_total_price = models.DecimalField(max_digits=50, decimal_places=2, default=5.99)
user_seller = models.ForeignKey(settings.AUTH_USER_MODEL)
order_total = models.DecimalField(max_digits=50, decimal_places=2, )
order_id = models.CharField(max_length=20, null=True, blank=True)
paymethod = models.CharField(max_length=120, choices=CHOICES, default='CreditCard')
seller = models.ForeignKey(SellerAccount, null=True)
def __unicode__(self):
return str(self.cart.id)
I can get multiple products but I need to filter products by seller and orders by seller. After trying multiple times I always get stuck with error:
user has to be a UserCheckout instance:
User "Admin": Must be a "User" instance.
and
'SellerDashboard' object has no attribute 'user'
I need to filter products by seller.
I need filter orders with paid status by the seller.
Seller Account Model:
class SellerAccount(models.Model):
user = models.ForeignKey(User)
managers = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="manager_sellers", blank=True)
#orders = models.ManyToManyField(Order)
active = models.BooleanField(default=False)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
def __unicode__(self):
return str(self.user.username)
def get_absolute_url(self):
return reverse("products:vendor_detail", kwargs={"vendor_name": self.user.username})
I am stuck so bad that I don't have courage to continue with django anymore. Please help.

Django admin view limiting the selection of items from foreign key according to user

I am writing code in Django for Engineering College:
1) College has Engineering Branches like Computer Engg, Mech Engg, Chemical Engg.
2) Now each Branch will have different classes like for Frst year enginnering in computer has to classes say, FYCO1 and FYCO2
3) I have created different users for each head of the department(HOD) and following models:
class M_Branch(models.Model):
Branch_ID = models.CharField(max_length=20)
Branch_Name= models.CharField(max_length=50)
def __str__(self):
return self.Branch_Name
class M_Academic_year(models.Model):
Academic_year = models.CharField(max_length=20)
def __str__(self):
return self.Academic_year
class M_Class(models.Model):
Branch_ID = models.ForeignKey(M_Branch)
Academic_Year = models.ForeignKey(M_Academic_year)
Class_ID = models.CharField(max_length=20)
Class_Name = models.CharField(max_length=20)
def __str__(self):
return self.Class_Name
4) Now each HOD (user) must be able to add a class for only his own department(branch),HOW TO ACHIEVE THIS FUNCTIONALITY???
Note: I have not written any views,(and don't want to do so). I am using Django's default admin
view
To read only branch of HOD in M_ClassAdmin first make a relation between HOD and Branch For this, make changes In Model.py as
from django.contrib.auth.models import User
Add Hod Field as
HOD = models.ForeignKey(User)
to store HOD and Branch relation
Now Model.py willbe...
class M_Branch(models.Model):
HOD = models.ForeignKey(User)
Branch_ID = models.CharField(max_length=20)
Branch_Name= models.CharField(max_length=50)
def __str__(self):
return self.Branch_Name
class M_Academic_year(models.Model):
Academic_year = models.CharField(max_length=20)
def __str__(self):
return self.Academic_year
class M_Class(models.Model):
Branch_ID = models.ForeignKey(M_Branch)
Academic_Year = models.ForeignKey(M_Academic_year)
Class_ID = models.CharField(max_length=20)
Class_Name = models.CharField(max_length=20)
def __str__(self):
return self.Class_Name
Then in admin.py Override get_queryset and formfield_for_foreignkey
class M_ClassAdmin(admin.ModelAdmin):
def get_queryset(self, request):
print("Query SET")
qs = super(M_ClassAdmin, self).get_queryset(request)
if request.user.is_superuser:
return qs
user = User.objects.get(username=request.user.username)
branch = M_Branch.objects.get(HOD = user)
print("Branch_ID_id",branch)
return qs.filter(Branch_ID_id=branch)
def formfield_for_foreignkey(self, db_field, request, **kwargs):
print("I am in func::")
if db_field.name == "Branch_ID":
print("db_field.name",db_field.name)
user = User.objects.get(username=request.user.username)
if not user.is_superuser:
print('user=',user)
branch = M_Branch.objects.get(HOD = user)
print('branch = ',branch)
'''if user=='E0711001':
kwargs["queryset"] = M_Branch.objects.filter(Branch_ID='B101')
#elif user=='E0711002':
else:
kwargs["queryset"] = M_Branch.objects.filter(Branch_ID='B102')'''
#kwargs["queryset"] = M_Branch.objects.filter(Branch_ID=user.branch.id)
kwargs["queryset"] = M_Branch.objects.filter(Branch_Name=branch)
return super(M_ClassAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
fields = ['Branch_ID','Academic_Year','Class_Name']
list_filter = ['Academic_Year','Class_Name']
search_fields = ['Branch_ID','Academic_Year','Class_Name']
list_display = ('Class_Name','Branch_ID','Academic_Year')
admin.site.register(M_Class,M_ClassAdmin)

Categories

Resources