django forms add blank choice for a IntegerField - django

I am trying to add a "null" choice to my form choices, since the field is not required.
Now for char fields I could go for a blank and work around that later, but this wont work for an integer field.
My question, how can I add a Null choice for both my CharField and IntegerField
My choices:
LIGHT = 0
MEDIUM = 1
HEAVY = 2
ARMORTYPES = (
(LIGHT, 'Light'),
(MEDIUM, 'Medium'),
(HEAVY, 'Heavy'),
)
my model:
class Item(models.Model):
name = models.CharField(max_length=63, unique=True)
flavor = models.TextField()
price = models.IntegerField()
weight = models.FloatField()
armor_proficiency = models.IntegerField(choices=ARMORTYPES, null=True)
(some more fields)
form:
class ItemForm(forms.ModelForm):
name = forms.CharField(help_text="name of the item")
flavor = forms.CharField(widget = forms.Textarea, help_text="short description")
price = forms.IntegerField(help_text="its market price")
weight = forms.FloatField(help_text="weight of the item")
armor_proficiency = forms.ChoiceField(choices=BLANK_CHOICE + ARMORTYPES, required=False, help_text="Some help text")
any idea how i could fix this?

Related

How to import a object of another model (A) inside model (B) in Django?

I want to create a new object in ModelB when specific condition are met in ModelA. I am new to Django so that I am unable to figure out how exactly I can achieve this.
For example I have two models(Product and ProductVariant), when specific condition on ProductVariant is met then I want to calculate new object value in Product model.
My Product model is like this:
PRODUCT_TYPE = (
('s', 'simple'),
('v', 'varaible')
)
class Products(models.Model):
name = models.CharField(max_length=250,null=True, blank=True,)
slug = models.SlugField(max_length=200, unique=True,null=True)
short_description = HTMLField()
description = HTMLField()
category = models.ForeignKey(Categories, related_name="products",on_delete=models.SET_NULL,null=True,blank=True,)
brand = models.ForeignKey(Brands,on_delete=models.CASCADE, default=None, null=True, blank=True,)
warranty_support = HTMLField()
product_type = models.CharField(choices=PRODUCT_TYPE, default='simple', max_length=50)
And my Product Attribute Model is like this:
class ProductVariant(models.Model):
product = models.ForeignKey(Products,on_delete=models.CASCADE)
variant = models.ForeignKey(ProductAttribute,on_delete=models.CASCADE, null = True, default=None)
managed_stock = models.IntegerField(choices=STOCK_MANAGED, default=0)
stock = models.IntegerField(default=None)
stock_threshold = models.IntegerField()
price = models.DecimalField(max_digits=10, decimal_places=2)
sku = models.CharField(max_length= 250, default=None)
sale_price = models.DecimalField(max_digits=10, decimal_places=2)
sale_start_date=models.DateField(auto_now_add=False, auto_now=False, default=None)
sale_end_date=models.DateField(auto_now_add=False, auto_now=False,default=None)
I am trying to create regular_price and sale_price on Product model if product_type is variable and if sale_end_date is greater than today. I want to set the price from the variant which has the lowest price.
I tried doing like this on Product model:
def clean(self):
if self.product_type == 'varaible' and ProductVariant.objects.filter(product=self, variant_count__gt = 1):
self.min_price = ProductVariant.objects.filter(product=self).Min('price')
self.max_price = ProductVariant.objects.filter(product=self).Max('price')
but I am not able to achieve what I want,
How can I do this?
After some research and analysis I found solution to my problem, I am posting the solution here so that someone with similar problem could be benefited.
#property
def get_price(self):
result = dict()
variants = ProductVariant.objects.filter(product=self)
count = variants.count()
if count > 1:
min_variant = variants.order_by('price').first()
max_variant = variants.order_by('-price').first()
result['min_price'] = min_variant.price
result['max_price'] = max_variant.price
elif count == 1:
variant = variants.first()
if variant.sale_price:
result['price'] = variant.price
result['sale_price'] = variant.sale_price
sale_variant = variants.order_by('sale_price').first()
result['lowest_sale_price'] = sale_variant.sale_price
result['regular_price'] = sale_variant.price
today = datetime.date.today()
if variant.sale_start_date <= today and variant.sale_end_date >= today:
result['sale_end_date'] = variant.sale_end_date
else:
result['price'] = variant.price

How do I modify the ManyToMany submission form from "hold ctrl to select multiple"

I'm making a medication tracking site in Django and am having trouble assigning multiple times to a medication. Currently I have a model for the Medication:
class Medication(models.Model):
UNDEFINED = ''
MILIGRAMS = 'mg'
MILIEQUIVILENT = 'MEQ'
MILILITERS = 'ml'
MEASUREMENT_CHOICES = [
(UNDEFINED, ' '),
(MILIGRAMS, 'mg'),
(MILIEQUIVILENT, 'MEQ'),
(MILILITERS, 'ml'),
]
ORAL = 'orally'
OPTICALLY = 'optically'
NASALLY = 'nasally'
OTTICALLY = 'per ear'
SUBLINGUAL = 'sublingual'
SUBCUTANEOUS = 'subcutaneous'
PER_RECTUM = 'per rectum'
TOPICAL = 'topical'
INHALATION = 'inhalation'
ROUTE_CHOICES = [
(ORAL, 'orally'),
(OPTICALLY, 'optically'),
(NASALLY, 'nasally'),
(OTTICALLY, 'per ear'),
(SUBLINGUAL, 'sublingual'),
(SUBCUTANEOUS, 'subcutaneous'),
(PER_RECTUM, 'per rectum'),
(TOPICAL, 'topical'),
(INHALATION, 'inhalation'),
]
AS_NEEDED = "PRN"
EVERY = "every"
EVERY_TWO = "every two"
EVERY_THREE = "every three"
EVERY_FOUR = "every four"
EVERY_FIVE = "every five"
EVERY_SIX = "six"
EVERY_SEVEN = "seven"
EVERY_EIGHT = "eight"
EVERY_NINE = "nine"
FREQUENCY_NUM = [
(AS_NEEDED, "PRN"),
(EVERY, "every"),
(EVERY_TWO, "every two"),
(EVERY_THREE, "every three"),
(EVERY_FOUR, "every four"),
(EVERY_FIVE, "every five"),
(EVERY_SIX, "six"),
(EVERY_SEVEN, "seven"),
(EVERY_EIGHT, "eight"),
(EVERY_NINE, "nine"),
]
MINUTE = 'minute'
HOUR = "hour"
DAY = "day"
WEEK = 'week'
MONTH = "month"
FREQUENCY_MEASUREMENT = [
(MINUTE, 'minute'),
(HOUR, "hour"),
(DAY, "day"),
(WEEK, 'week'),
(MONTH, "month"),
]
ONE_TAB = 'tab'
MULTIPLE_TABS = 'tabs'
HALF_TAB = 'half of a tab'
THIRD_TAB = 'third of a tab'
QUARTER_TAB = 'quarter of a tab'
ONE_DROP = 'drop'
MULTIPLE_DROPS = 'drops'
FORM_FACTORS = [
(ONE_TAB, 'tab'),
(MULTIPLE_TABS, 'tabs'),
(HALF_TAB, 'half of a tab'),
(THIRD_TAB, 'third of a tab'),
(QUARTER_TAB, 'quarter of a tab'),
(ONE_DROP, 'drop'),
(MULTIPLE_DROPS, 'drops')
]
client = models.ForeignKey(
Client_Medlist,
blank=True,
default=None,
on_delete=models.CASCADE)
name = models.CharField(max_length=255)
drug_class = models.CharField(max_length=255)
dosage = models.FloatField(default=10)
measurement = models.CharField(
max_length=3,
choices=MEASUREMENT_CHOICES,
default=MILIGRAMS,)
number_of_form = models.IntegerField(default=1)
drug_form_factor = models.CharField(
max_length=255,
choices=FORM_FACTORS,
default=ONE_TAB,
)
route = models.CharField(
max_length=255,
choices=ROUTE_CHOICES,
default=ORAL,)
frequency_num = models.CharField(
max_length=255,
choices=FREQUENCY_NUM,
default=EVERY,)
frequency_measurement = models.CharField(
max_length=255,
choices=FREQUENCY_MEASUREMENT,
default=DAY,)
times_taken = models.ManyToManyField(Medication_Times)
start_date = models.DateField(default=timezone.now)
is_med_active = models.BooleanField(default=True)
transcription_author = models.ForeignKey(User, on_delete=models.PROTECT)
transcription_date = models.DateField(default=timezone.now)
def __str__(self):
return self.name
This model has a 'ManyToMany' relation to the medication times model:
class Medication_Times(models.Model):
times_taken = models.TimeField(default=timezone.now, auto_now=False, auto_now_add=False)
display_name = models.CharField(default='Scheduled Time', max_length=255)
def __str__(self):
return self.times_taken.strftime('%I:%M %p')
For the view leading to this page I am using LoginRequiredMixin and CreateView:
class MedicationNew(LoginRequiredMixin, CreateView):
model = Medication
template_name = 'client_profile/new_med.html'
context_object_name = 'posts'
fields = ['client', 'name', 'start_date', 'drug_class', 'dosage', 'measurement', 'route', 'frequency_num', 'frequency_measurement', 'times_taken']
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
This all works well, but where the maximum value between times is fifteen minutes, when the user is creating a new medication to add to a client's chart, the times are displayed in a long scrolling list with only ctrl+click to select multiple.
Where this needs to be as user friendly as possible, I was thinking that selecting a time, then adding it to a box displayed below the scrolling selection might be a better approach. This way if a user selects the wrong thing, it would be in the box for easy removal, and would be easy to scroll back and select the correct time(s). Then after the correct time(s) are chosen, the whole form could be submitted.
Is there a straightforward way to do this in Django? I have been looking everywhere for a manner to do so, but have yet to come up with anything. Any help would be greatly appreciated.

Django query for multiple fields with list values

I have below Django model
class Post(models.Model):
author = models.ForeignKey(CustomUser,on_delete=models.CASCADE,)
title = models.CharField(max_length=200,null=True)
text = models.TextField()
post_url = models.URLField(max_length = 200, blank = True)
post_tier = models.ForeignKey(Tiers, on_delete=models.CASCADE, null= True)
post_tier_value = models.IntegerField(default=0)
slug = models.SlugField(unique=True, blank=True)
I have author_list = [author1#gmail.com, author2#gmail.com] and tier_value_list = [2000,3000]. I want to query in the above model for (author = author1#gmail.com and post_tier_value <= 2000) or (author = author2#gmail.com and post_tier_value <= 3000).
Can someone help me how to make query for this?
Use Q() operator
from django.db.models import Q
author_list = ['author1#gmail.com', 'author2#gmail.com']
tier_value_list = [2000, 3000]
query = Q()
for author, value in zip(author_list, tier_value_list):
query = query | Q(author=author, post_tier_value__lte=value)
Post.objects.filter(query)
Note: I have used author__email which is a nested lookup since the author_list contain the email_ids

Django: Form save method

I have a form, working off different models and using a through (intermediate) model:
class CourseBooking(BaseModel):
'''Intermediary model linking a person on a course with the related booking'''
course = ForeignKey('ScheduledCourse')
customer = ForeignKey('Customer')
booking = ForeignKey('GroupBooking', blank=True, null=True)
The form is using a basic form instead of Model form, with the fields added in manually:
class CourseBookingForm(Form):
course = ModelChoiceField(queryset=ScheduledCourse.objects.all())
title = CharField(
max_length=255,
widget=Select(choices=TITLE_CHOICES),
required=False
)
gender = CharField(
max_length=255,
widget=Select(choices=GENDER_CHOICES),
required=False
)
first_name = CharField(max_length=255)
surname = CharField( max_length=255)
dob = DateField(required=False)
medical = CharField(required=False, widget = forms.Textarea(attrs={'rows': '4'}))
# miscellaneous notes
notes = CharField(required=False, widget = forms.Textarea(attrs={'rows': '4'}))
email = EmailField(required=False)
phone = CharField(required=False)
address = CharField(
max_length=8188,
widget=Textarea(attrs={'rows':'4', 'cols':'50'}),
required=False)
city = CharField(max_length=255, required=False)
county = CharField(
max_length=255, widget=Select(choices=COUNTY_CHOICES))
postcode = CharField(max_length=255, required=False)
country = CharField(
max_length=255,
widget=Select(choices=COUNTRIES), required=False)
I want to create a save method in the forms.py which will save to the database. What I have at the moment (which is wrong) is and gives the error: IntegrityError: null value in column "customer_id" violates not-null constraint
def save(self):
data = self.cleaned_data
if self.cleaned_data['course']:
crs = self.cleaned_data['course']
course_booking = CourseBooking(course=crs)
course_booking.save()
course = CourseBooking.objects.create(course=data['course'])
course.save()
cust = Customer.objects.create(title=data['title'],
gender=data['gender'],
first_name=data['first_name'],
surname=data['surname'],
dob=data['dob'],
notes=data['notes'],
medical=data['medical'],
content_object=cust,
)
cust.save()
address = Address.objects.create(address=data['address'],
city=data['city'],
county=data['county'],
postcode =data['postcode'],
country=data['country'],
content_object=address,
)
address.save()
email = Email.objects.create(email=data['email'],
content_object=email)
email.save()
phone = Phone.objects.create(number=data['phone'],
content_object=phone)
phone.save()
Just call the code for creation of the course object after creating the customer object.
The issue is, the ForeignKey customer in Course model is required, and you have not set that field while creating the object.
You have a couple of other minor issues which I have fixed in the code. .
def save(self):
data = self.cleaned_data
course_booking = None
if self.cleaned_data['course']:
crs = self.cleaned_data['course']
course_booking = CourseBooking(course=crs)
course_booking.save()
cust = Customer.objects.create(title=data['title'],
gender=data['gender'],
first_name=data['first_name'],
surname=data['surname'],
dob=data['dob'],
notes=data['notes'],
medical=data['medical'],
content_object=cust,
)
#cust.save()
course = CourseBooking.objects.create(course=data['course'], customer = cust)
if course_booking:
course.booking = course_booking
#course.save()
address = Address.objects.create(address=data['address'],
city=data['city'],
county=data['county'],
postcode =data['postcode'],
country=data['country'],
content_object=address,
)
#address.save()
email = Email.objects.create(email=data['email'],
content_object=email)
#email.save()
phone = Phone.objects.create(number=data['phone'],
content_object=phone)
#phone.save()
On another note, I would put this object creation logic in the view, rather than the model_form's save method.

Cannot assign "u''": "Company.parent" must be a "Company" instance

I am getting this at every attempt.
Cannot assign "u''": "Company.parent" must be a "Company" instance.
I do not know what else to do.
The view code is still half baked, sorry for that.
Am I passing wrong parameters to the form?
I have the following model:
models.py
class Company(AL_Node):
parent = models.ForeignKey('self',
related_name='children_set',
null=True,
db_index=True)
node_order_by = ['id', 'company_name']
id = models.AutoField(primary_key=True)
company_name = models.CharField(max_length=100L, db_column='company_name') # Field name made lowercase.
next_billing_date = models.DateTimeField()
last_billing_date = models.DateTimeField(null=True)
weekly = 'we'
twice_a_month = '2m'
every_two_weeks = '2w'
monthly = 'mo'
billing_period_choices = (
(weekly, 'Weekly'),
(every_two_weeks, 'Every two weeks'),
(twice_a_month, 'Every two weeks'),
(monthly, 'Monthly'),
)
billing_period = models.CharField(max_length=2,
choices=billing_period_choices,
default=weekly)
objects = CompanyManager()
The following forms.py:
class newCompany(ModelForm):
company_name = forms.CharField(label='Company Name',
widget=forms.TextInput(attrs={'class': 'oversize expand input-text'}))
billing_period = forms.ModelChoiceField
next_billing_date = forms.CharField(widget=forms.TextInput(attrs={'class': 'input-text small', 'id': 'datepicker'}))
parent = forms.CharField(widget=forms.HiddenInput(), required=False)
class Meta:
model = Company
fields = ["company_name", "parent", "billing_period", "next_billing_date"]
The following view:
def create_company(request):
userid = User.objects.get(username=request.user).id
my_company_id = CompanyUsers.objects.get(user_id=userid).company_id
my_company_name = Company.objects.get(id=my_company_id).company_name
machines = Title.objects.raw(
'select machines.id, title.name, machines.moneyin, machines.moneyout, moneyin - moneyout as profit, machines.lastmoneyinoutupdate, (select auth_user.username from auth_user where machines.operator = auth_user.id) as operator, (select auth_user.username from auth_user where machines.readers = auth_user.id) as readers from machines, title where machines.title = title.id and machines.company_id =%s',
[my_company_id])
if request.method == 'POST':
form_company = newCompany(request.POST)
if form_company.is_valid():
new_company = form_company.save(commit=False)
new_company.parent = my_company_id
if request.POST.get('select_machine'):
selected_machine = request.POST.getlist('select_machine')
percentage = request.POST.get('percentage')
if not Beneficiary.objects.check_assign_machine(my_company_id, selected_machine, percentage):
target_company_name = new_company.company_name
target_company_id = Company.objects.get(company_name=target_company_name).id
new_company.save()
Machines.objects.assign_machine(target_company_id, selected_machine)
Beneficiary.objects.create_beneficiary(percentage, target_company_name, my_company_id, selected_machine)
else:
invalid_machines = Beneficiary.objects.check_assign_machine(my_company_id, selected_machine, percentage)
return render(request, 'lhmes/createcompany.html',
{'form_company': form_company, 'machines': machines, 'my_company_name': my_company_name, 'invalid_machines' : invalid_machines})
else:
new_company.save()
else:
form_company = newCompany()
return render(request, 'lhmes/createcompany.html',
{'form_company': form_company, 'machines': machines, 'my_company_name': my_company_name})
The error message says you are trying to set a relationship with a string but Django expects the value to be an instance of the Company model. You should assign the foreign key fields with a real model instance instead of only the primary key.
I've spotted a few places in the code where you are assigning a PK:
new_company.parent = my_company_id
Where the model expects it to be an instance:
new_company.parent = Company.objects.get(id=my_company_id)
I really don't remember if this works, but you can try:
new_company.parent_id = int(my_company_id)
This would spare a trip to the database.