Django. Using variable in a Queryset - django

I have a query
variable3 = "Field3"
variable_gte = "flowrate__gte"
x = mytable.objects.filter(Q((variable_gte, variable2))).order_by(variable3)[0:5]
z = x[0].Field3
How can I call this last value z using variable3, something similar to z = x[0].variable3
If it is impossible, I will need to use if/else condition:
if variable3 = "Field3":
z = x[0].Field3
else:
....
Thank you.

You can make use of getattr(…) [Django-doc]:
variable3 = 'Field3'
variable_gte = 'flowrate__gte'
x = mytable.objects.filter(
Q((variable_gte, variable2))
).order_by(variable3)[0:5]
z = getattr(x[0], variable3)
If you write getattr(x, 'y'), this is equivalent to x.y, so you can pass a string with the name of the attribute and obtain the attribute of that name.
It however does not make much sense to first slice, and then obtain the first item. You can remove the …[0:5] part.

Related

Django: Modify model object and save as new

My question is very similar to this question: How to modify a queryset and save it as new objects?
Say my models has following fields:
class myModel(models.Model):
articleId = models.ForeignKey(otherModel)
myCounter = models.IntegerField
Now, say keeping the articleId as constant, I want to save multiple rows by varying myCounter. This is what I am trying to do:
for x in range(1, 5):
m = myModel()
m.articleId = otherModel.objects.get(pid="some constant")
m.myCounter = x
m.save()
m.id = None
As suggested by the above post (and similar others), I tried setting both 'id' and 'pk' as None. But nothing is helping.
This code is writing just one row in the database and is updating the value of myCounter. How do I commit 4 different rows?
You could use bulk_create for this:
an_article_object = otherModel.objects.create(name="Some Constant")
myModel.objects.bulk_create([
myModel(articleId=an_article_object, myCounter=x) for x in range(1, 5)
])
EDIT:
To fix your issue in a loop:
article = otherModel.objects.create(name="SomeConst")
#or fetch the article object
m = myModel(articleId = article)
for x in range(1, 5):
m.myCounter = x
m.pk = None
m.save()
Model -
myCounter = models.AutoField(primary_key=True)
#myCounter = models.AutoField(primary_key=False)
#you use primary_key = True if you do not want to use default field "id" given by django to your model
Code -
for x in range(1, 5):
m = myModel()
m.articleId = "some constant"
m.save()
If you want to change the same object you could try this:
m = myModel()
for x in range(1, 5):
m.articleId = otherModel.objects.get(pid="some constant")
m.myCounter = x
m.save()
You can use the force_insert parameter to force an INSERT statement. This will raise an error if the insert fails, but it won't silently update an existing object.
m.save(force_insert=True)

Changing values in an list? [duplicate]

I want to remove some words from a list of words. I have a list with a recurring word and I want to get rid of it and I have no idea. I don't know whether I need to use a whole loop or regex.
from xlrd import open_workbook,error_text_from_code
book = open_workbook(inp)
sheet0 = book.sheet_by_index(0)
x = 0
y = 0
countr = sheet0.nrows
countc = sheet0.ncols
names = ''
variables = []
"different variables-----------------"
while x < countr -1:
x = x+1
y = y+1
cell = sheet0.cell(y,0)
names = names+ str(cell)
cell = sheet0.cell(y,1)
variables.append(cell)
country_text = names
countries = ', '.join(re.findall("('.*?')", country_text))
countries = countries.split()
print (variables)
print (countries)
What I get :
[number:150000.0, number:140000.0, number:300000.0]
and I need
[150000, 140000, 300000]
If you use a loop you can access to the value of a cell using this function:
sheet0.cell_value(curr_row, curr_cell)

Getting error while assigning value to a list index

empname = Leave.objects.filter(created_by=self.request.user)[0].emp_id_requested_for
typelist = TypeAssign.objects.filter(emp_id__emp_name=empname)
output = {}
data = Leave.objects.filter(created_by=self.request.user)
for x in data:
output[x.leave_type_id] = [0,0]
for t in data:
output[t.leave_type_id][0] = (t.total_approve_leave + output[t.leave_type_id][0])
for x in typelist:
**output[LeaveType.objects.get(type_name=x)][1] = LeaveType.objects.get(type_name=x).max_duration**
ctx["output"] = output
return ctx
Seems like you mean:
output[LeaveType.objects.get(type_name=x).id][1]
as the keys you've set elsewhere have been IDs, not LeaveType instances.
Generally your code would be clearer if you used intermediate variables rather than doing the calls inside the dict lookups.

Django charts - date&time axis

I have one model which looks like this:
class Measurement(models.Model):
date = models.DateField('date')
time = models.TimeField('time')
Q = models.DecimalField(max_digits=10, decimal_places=6)
P = models.DecimalField(max_digits=10, decimal_places=6)
f = models.DecimalField(max_digits=10, decimal_places=6)
In my views, I would like to represent it. So I made this function:
def plotMeas(request):
# Count the events
c = Measurement.objects.all()
c = c.count()
# Variables
i = 0
a = [0]
P = a*c
Q = a*c
t = a*c
# Save dP_L1 & dQ_L1 in lists
for i in range(c):
meas = Measurement.objects.get(pk = i+1)
P [i] = meas.P
Q [i] = meas.Q
t [c-1-i] = i*10
if c > 100:
P = P[-100:]
Q = Q[-100:]
t [i] = t[-100:]
# Construct the graph
fig = Figure()
q = fig.add_subplot(211)
q.set_xlabel("time (minutes ago)")
q.set_ylabel("Q (VAR)")
p = fig.add_subplot(212)
p.set_xlabel("time (minutes ago)")
p.set_ylabel("P (W)")
p.plot(t,P, 'go-')
q.plot(t,Q, 'o-')
canvas = FigureCanvas(fig)
response = HttpResponse(content_type='image/png')
canvas.print_png(response)
return response
However, I would like that the horizontal axis would show the date and the time (saved in the model). Does anyone know how to do it?
Have a look at the documentation for plot_date. Conveniently plot_date takes similar arguments to plot. A call might look like:
p.plot_date(sequence_of_datetime_objects, y_axis_values, 'go-')
Using matplotlib.dates you can then customize the format of your x-axis labels.
A simple example:
The following will specify that the x-axis displays only every third month in the format Jan '09 (assuming English-speaking locale).
p.xaxis.set_major_locator(mdates.MonthLocator(interval=3))
p.xaxis.set_major_formatter(mdates.DateFormatter("%b '%y"))
Since you have dates and times stored separately you may either want to
change your model to use a DateTimeField, or
use Python to combine them.
For example:
import datetime as dt
t1 = dt.time(21,0,1,2) # 21:00:01.2
d1 = dt.date.today()
dt1 = dt.datetime.combine(d1,t1)
# result: datetime.datetime(2011, 4, 15, 21, 0, 1, 2)
To iterate over two sequences and combine them you might use zip (code for illustrative purposes only, not necessarily optimized):
sequence_of_datetime_objects = []
for a_date, a_time in zip(sequence_of_date_objects, sequence_of_time_objects):
sequence_of_datetime_objects.append(dt.datetime.combine(a_date, a_time))
Feel free to open another question if you get stuck implementing the specifics.

How to include "None" in lte/gte comparisons?

I've got this complex filtering mechanism...
d = copy(request.GET)
d.setdefault('sort_by', 'created')
d.setdefault('sort_dir', 'desc')
form = FilterShipmentForm(d)
filter = {
'status': ShipmentStatuses.ACTIVE
}
exclude = {}
if not request.user.is_staff:
filter['user__is_staff'] = False
if request.user.is_authenticated():
exclude['user__blocked_by__blocked'] = request.user
if form.is_valid():
d = form.cleaned_data
if d.get('pickup_city'): filter['pickup_address__city__icontains'] = d['pickup_city']
if d.get('dropoff_city'): filter['dropoff_address__city__icontains'] = d['dropoff_city']
if d.get('pickup_province'): filter['pickup_address__province__exact'] = d['pickup_province']
if d.get('dropoff_province'): filter['dropoff_address__province__exact'] = d['dropoff_province']
if d.get('pickup_country'): filter['pickup_address__country__exact'] = d['pickup_country']
if d.get('dropoff_country'): filter['dropoff_address__country__exact'] = d['dropoff_country']
if d.get('min_price'): filter['target_price__gte'] = d['min_price']
if d.get('max_price'): filter['target_price__lte'] = d['max_price']
if d.get('min_distance'): filter['distance__gte'] = d['min_distance'] * 1000
if d.get('max_distance'): filter['distance__lte'] = d['max_distance'] * 1000
if d.get('available_on'): # <--- RELEVANT BIT HERE ---
filter['pickup_earliest__lte'] = d['available_on'] # basically I want "lte OR none"
filter['pickup_latest__gte'] = d['available_on']
if d.get('shipper'): filter['user__username__iexact'] = d['shipper']
order = ife(d['sort_dir'] == 'desc', '-') + d['sort_by']
shipments = Shipment.objects.filter(**filter).exclude(**exclude).order_by(order) \
.annotate(num_bids=Count('bids'), min_bid=Min('bids__amount'), max_bid=Max('bids__amount'))
And now my client tells me he wants pickup/drop-off dates to be 'flexible' as an option. So I've updated the DB to allow dates to be NULL for this purpose, but now the "available for pickup on" filter won't work as expected. It should include NULL/None dates. Is there an easy fix for this?
Flip the logic and use exclude(). What you really want to do is exclude any data that specifies a date that doesn't fit. If pickup_latest and pickup_earliest are NULL it shouldn't match the exclude query and wont be removed. Eg
exclude['pickup_latest__lt'] = d['available_on']
exclude['pickup_earliest__gt'] = d['available_on']
Most database engines don't like relational comparisons with NULL values. Use <field>__isnull to explicitly check if a value is NULL in the database, but you'll need to use Q objects to OR the conditions together.
Don't think that's actually a django-specific question. Variable 'd' is a python dictionary, no? If so, you can use this:
filter['pickup_latest__gte'] = d.get('available_on', None)