My database was something like this :
| id | customer_account | -few more fields - | is_renewed |
| 25 | asd111 | - some values - | 0 |
| 26 | asd222 | - some values - | 1 |
| 27 | asd333 | - some values - | 1 |
| 28 | asd444 | - some values - | 0 |
in my models, I have :
class Policy(models.Model):
customer_account = models.ForeignKey(CustomerAccount, on_delete=models.CASCADE)
--few more fields--
is_renewed = models.BooleanField(default = False)
def use_updated_id(self):
if self.is_renewed:
new_id = str("R") + str(self.id)
else:
new_id = self.id
return new_id
in my template, I have :
{% for policy in policy_list % }
<p> Policy Number : {{policy.id}} </p>
{% endfor %}
which gives me output as
Policy Number : 25
Policy Number : 26
Policy Number : 27
Policy Number : 28
I understand that I can define a method in model and use that instead of id as below to meet my requirement
{% for policy in policy_list % }
<p> Policy Number : {{policy.use_updated_id}} </p>
{% endfor %}
Policy Number : 25
Policy Number : R26
Policy Number : R27
Policy Number : 28
My only challenge is that if use model method as above, i will have to replace updated multiple templates.
I'm looking for a better solution where in i only have to make changes in models file instead of updating multiple templates to achieve the desired result.
So you have {{ policy.id }} in multiple templates and want to change its behavior by making changes to models.py?
AFAIK you cannot achieve that, since you haven't correctly encapsulated the display beforehand. That's a pain, but you'll have to change it everywhere, since you're accessing a particular attribute on your models. Adding your use_updated_id is a great idea, since it encapsulates the display logic in one function and, in the future, if you need to change the display all you have to do is to change your new function.
So go on, make those hundreds of file edits but be sure that now you've made a great progress and facilitated your project maintainability.
I'm trying to use the twint module to get some information from twitter, in particular the bio. The code example works just fine:
import twint
c = twint.Config()
c.Username = "twitter"
twint.run.Lookup(c)
yields
783214 | Twitter | #Twitter | Private: 0 | Verified: 1 | Bio: What’s happening?! | Location: Everywhere | Url: https://about.twitter.com/ | Joined: 20 Feb 2007 6:35 AM | Tweets: 10816 | Following: 140 | Followers: 56328970 | Likes: 5960 | Media: 1932 | Avatar: https://pbs.twimg.com/profile_images/1111729635610382336/_65QFl7B_400x400.png
Thing is, I only need the bio data. According to the site, you can use
c.Format = 'bio: {bio}'
Unfortunately, this yields
CRITICAL:root:twint.get:User:replace() argument 2 must be str, not None
I think this may be due to the following code line (from here):
output += output.replace("{bio}", u.bio)
Where the u.bio value is assigned here:
u.bio = card(ur, "bio")
The card function does the following when our type is "bio":
if _type == "bio":
try:
ret = ur.find("p", "ProfileHeaderCard-bio u-dir").text.replace("\n", " ")
except:
ret = None
I think the problem may lie in the second part, where a value is assigned to u.bio, either not even being called or returning None for some reason. Unfortunately, I do not know how to fix that or call the function.
I've had a similar problem before with a different function, twint.run.Following(c), but was able to solve it by not setting c.User_full = true
Could anyone help me out?
The format should be of the form
c.Format = "{bio}"
If you wanted multiple fields
c.Format = "{bio} | {name}"
I find you get a rate limit of 250 items before a blocker drops down and you need to wait for a few minutes for it to lift.
I am trying to create a simple charting web app using pygal and flask to chart some financial data I have stored in a mysql database. The data in the DB is hierarchical, and I want the app to start at the top of the hierarchy and allow the user to drill down by simply clicking on the relevant parts of the chart.
I am using flask to display the dynamically generated pygal charts.
Sample DB data:
guid | name | value | parentGuid | Description
------------------------------------------------
1234 | cat1 | 1 | null | Blah, blah
4567 | cat2 | 55 | null | asfdsa
8901 | cat3 | 22 | 1234 | asfdsa
5435 | cat4 | 3 | 8901 | afdsa
etc...
I have no problem drilling down the hierarchy using python + sql, but where I'm stumped is how I drill down using links in my pygal chart.
#app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
chart = graph_sub(request.form['guid'])
return render_template('Graph3.html', chart=chart)
else:
chart = graph_main()
return render_template('Graph3.html', chart=chart)
def graph_main():
""" render svg graph """
line_chart = pygal.HorizontalBar()
line_chart.title = 'Root Accounts'
RootAccts = GetRootAccounts() # Returns a list of lists containing accounts and account data.
for Acct in RootAccts:
line_chart.add({
'title': Acct[1], # Acct Name
'tooltip': Acct[4], # Acct description
'xlink': {'href': '/'} # Hyperlink that I want to pass POST data back to the form.
}, [{
'value': Acct[2]), # Acct Value
'label': Acct[4], # Acct Description
'xlink': {'href': '/'} # Hyperlink that I want to pass POST data back to the form.
}])
return line_chart.render()
def graph_sub(parentGuid):
### This works fine if I pass a parent GUID to it
### Now the question is how do I pass the guid to it from my pygal chart?
return line_chart.render()
So when I click on the links embedded in the pygal chart
'xlink': {'href': '/'}
How can I make it redirect back to the same page and pass the GUID of the selected account as POST data? Or is there another way to do this that doesn't involve POST?
The page reloading every time they click something so I'm hoping to keep this as simple as possible without having to involve ajax/java/etc... though if there are no other options I am open to it.
I don't have it coded yet, but there will also be some additional form controls added to the page that will allow the user to set date ranges to control how much data is displayed. I was planning to use POST to pass user input around, but before I get too far down that road, I need to figure out how I can manage this base functionality.
Thoughts?
I'm currently trying to parse recursive templates with pyparsing. A template can look like this:
{{Attribute
| name=attr1
| description=First attribute.}}
The template has a name (Attribute) and defines some variables (name = attr1, description = First attribute.). However, there are also templates which can contain zero or more templates:
{{Enum
| name=MyEnum
| description=Just a test enum.
| example=Not given...
| attributes={{Attribute
| name=attr1
| description=First attribute.}}
{{Attribute
| name=attr2
| description=Second attribute.}}}}
To parse these templates I came up with the following:
template = Forward()
lb = '{{'
rb = '}}'
template_name = Word(alphas)
variable = Word(alphas)
value = CharsNotIn('|{}=') | Group(ZeroOrMore(template))
member = Group(Suppress('|') + variable + Suppress('=') + value)
members = Group(OneOrMore(member))
template << Suppress(lb) + Group(template_name + members) + Suppress(rb)
This works quite well, but it does not allow me to use "|{}=" within a value which is problematic if I want to use them. E.g.:
{{Enum
| name=MyEnum
| description=Just a test enum.
| example=<python>x = 1</python>
| attributes=}}
So, how can I change my code so that it allows these characters, too? Unforunately, I have no idea how I can archieve this.
I hope someone can give me some tips!
I found what I was looking for: https://github.com/earwig/mwparserfromhell
I've got a question which I'll ask two ways: short & generic, so future generations of StackOverflow readers will benefit, and Long & Detailed, so I can get my work done without screwing anything up.
Short & Generic Version:
How do I make Django generate a table-like form where some info in the table is from the database, and the user fills in the rest? On form submission, each row in the table should become a record in the database (after it's validated, of course).
What's the cleanest way to do this? What's this mode of interaction cannonically called?
Example Form
|=============================================================|
| QueriedValue | CalculatedValue | User_data | More_User_data |
|_____________________________________________________________|
| Foo 1 | Bar 1 | | |
| Foo 2 | Bar 2 | | |
| Foo 3 | Bar 3 | | |
... ... ... ... |
| Foo n | Bar n | | |
|=============================================================|
++++++++++
| Submit |
++++++++++
Resulting Database Records
TimeStamp + fk_Foo = natural primary key for this table
________________
/ \
|===========================================================|
| TimeStamp | fk_Foo | User_data | More_User_data |
|___________________________________________________________|
| submit_time | Foo 1 | Datum 1 | AnotherDatum 1 |
| submit_time | Foo 2 | Datum 2 | AnotherDatum 2 |
| submit_time | Foo 3 | Datum 3 | AnotherDatum 3 |
|... ... ... ... |
| submit_time | Foo n | Datum n | AnotherDatum n |
|===========================================================|
Long Version
I'm writing a web app to track gas cylinder usage at my company. We have a bunch of gas plumbing in our building, and we need to know which gas cylinder was hooked up to which gas line at what time.
I'd like two forms for the technicians to fill out:
Daily Inventory: Every morning, the stockroom guy needs to look at each gas line and record the line's pressure, and the reference number of the bottle. This generates bunch of 4-tuple records (time, line, bottle, psi); one for each line, every morning.
As-Needed Bottle Change: After doing the daily inventory, if a bottle is almost out it needs to be changed, and that change needs to be logged. This should add another entry to the table of bottles for the new bottle, and another 4-tuple with the new (time, line, bottle, psi) info for the new connection. This happens to a random line a few times a week, but not every day.
So to keep track of this I'm writing a Django application. I've got the following models:
# models.py
class GasFarm(models.Model):
"""
Represents a gas farm -- a collection of lines that are grouped together and managed as a unit.
"""
name = models.CharField(max_length=30, unique=True)
def __unicode__(self):
return self.name
class Bottle(models.Model):
"""
Represents a gas bottle -- the physical cylinder -- that contains a mixture of gases.
"""
# Options
get_latest_by = 'date_added'
# Fields
BACKGROUND_TYPES = (
('h2/n2', "H2/N2"),
('h2/air', "H2/Air"),
('h2', "H2"),
('n2', "N2"),
('other', "Other"),
)
ppm = models.FloatField()
mix = models.CharField(max_length=50, choices=BACKGROUND_TYPES, default='n2')
ref = models.CharField(max_length=50, unique=True) # Every bottle has a unique ref or somebody fucked up.
cert_date = models.DateTimeField()
date_added = models.DateTimeField(default=timezone.now())
def pct(self):
return float(self.ppm)/10**4
def __unicode__(self):
return "{} ({}% {})".format(self.ref, self.pct(), self.mix,)
class Line(models.Model):
"""
Represents a gas line -- the physical plumbing -- that delivers gas from the bottles to the test stations.
It is assumed that a gas line can have zero or one gas bottles attached to it at any given time. The Line model
maps bottle objects and time-sensitive Reading objects to test stations.
"""
# Fields
gasfarm = models.ForeignKey(GasFarm)
number = models.CharField(max_length=10, unique=True)
bottles = models.ManyToManyField(Bottle, through='Reading')
# Calculated fields. "current" is definitely not optional -- that's a super common query. The others? I'm not so
# sure...
def current(self):
"""
Returns the most recently recorded Reading object associated with the line
"""
return self.reading_set.latest(field_name='time')
current.short_description = "latest reading"
def last_checked(self):
"""
Returns the date & time at which the most recent Reading object associated with this line was logged
"""
return self.current().time
last_checked.short_description = "last updated"
def has_recent_reading(self):
"""
Boolean flag for whether the reading is probably valid, or if someone needs to go out and take a new one.
"""
latest_reading = self.current().time
return timezone.now() - latest_reading < datetime.timedelta(days=3)
has_recent_reading.boolean = True
has_recent_reading.short_description = "Is data current?"
def __unicode__(self):
return self.number
class Reading(models.Model):
"""
A Reading links a Bottle to a Line at a given time, and provides a snapshot of the pressure at that time.
"""
# Options
get_latest_by = 'time'
# Fields
line = models.ForeignKey(Line)
bottle = models.ForeignKey(Bottle)
time = models.DateTimeField()
psi = models.IntegerField(validators=[MaxValueValidator(2500)])
def ref(self):
"""
The reference number of the bottle listed in the reading
"""
return self.bottle.ref
def ppm(self):
"""
The PPM concentration of the bottle listed in the reading
"""
return self.bottle.ppm
def pct(self):
"""
The % concentration of the bottle listed in the reading
"""
return self.bottle.pct()
def mix(self):
"""
The gas mix (e.g. H2/N2) of the associated bottle
"""
return self.bottle.mix
def __unicode__(self):
# Example:
# A0: 327.3 PPM H2/N2 2300 psi
return "{}, {}: {} PPM {} {} psi".format(self.line, self.time, self.ppm(), self.mix(), self.psi)
I've populated the database with our back-log of data using some scripts, and I've written a few views to pull data out of the databse; I'm happy with them so far, and the results look very promising -- at least for displaying stored data.
But I'm not sure how to cleanly populate the database using HTML forms. I'd like the forms to be basically two separate "worksheets" -- like the kind the DMV gives you, with nice clear instructions #justkidding.
Form 1: Daily Inventory
The form would list all the lines in a given farm, display what bottle should be on each line (based on previous readings/updates), and then prompt the user to enter a value. This would require that the technician update the pressure of every bottle on every line each time they submit the form -- we want a global snapshot of the whole gas system. In a perfect world, the form would pre-fill the current time and each line's most recent pressure reading into the Reading Time and Pressure fields to ease data entry.
# Cells with brackets [] are system-supplied, non-editable data displayed in the table.
# Cells without brackets are pre-filled with sensible defaults, but are user editable.
| [Line] | [Current Bottle] | Reading Time | Pressure (psi) |
===============================================================
| [A0] | [15-1478334] | 2014-7-14 9:34 | 2400 |
| [A1] | [15-1458661] | 2014-7-14 9:34 | 500 |
| [A2] | [15-4851148] | 2014-7-14 9:34 | 1850 |
| [A3] | [15-1365195] | 2014-7-14 9:34 | 700 |
...
...
| [C18] | [15-9555813] | 2014-7-14 9:34 | 2350 |
|=====================================================================|
After reading through the Django docs on Forms, ModelForms, and Formsets, I've written some code that does almost everything I want -- but the Line and Bottle information are editable form fields, and I need them to be static guideposts for filling in the rest of the form. They do need to be present in the generated database records, though.
I am dimly aware of the readonly and disabled attributes, and of what appear to be kludgy solutions to clean data from the POST variable in the response when you want to have read-only stuff in forms, but I'm still not clear on how those work or why they're necessary. I'm wondering if there's a cleaner way to get what I"m after? Perhaps forms with programmatically generated headings, or annotations? That's all I really want: an auto-generated guide to filling out the form.
# Forms.py
class PressureReadingUpdate(forms.ModelForm):
class Meta:
model = models.Reading
PsiReadingFormset = formset_factory(PressureReadingUpdate, extra=0)
# views.py
def update_pressure(request):
if request.method == 'POST':
formset = forms.PsiReadingFormset(request.POST)
if formset.is_valid():
cd = formset.cleaned_data
# do something? I'm not here yet...
else:
lines = models.Line.objects.all()
now = datetime.datetime.now()
initial = [{'line': l,
'psi': l.current().psi,
"bottle": l.current().bottle,
'time': now} for l in lines]
formset = forms.PsiReadingFormset(initial=initial,)
return render(request, 'gas_tracking/gasfarm_form_psi_reading.html', {'formset': formset})
Form 2: Change a Gas Bottle
I'd like a list of all the gas lines, with the current bottle & pressure (easy-- this is done elsewhere), and then a button that makes a pop-up window where you can submit a new bottle, much like you find in the admin interface. How do I make pop-up windows? How do I make buttons? I'm not even sure where to start with this one yet
I'm still very new to Django, and I've searched high and low, but haven't found anything that answers my question -- maybe I'm just not using the right keywords?
Thanks for your help.
-Matt
Dynamically generating Forms using FormSets
So I figured this out (after much googling and swearing and gnashing of teeth). Malcolm Tredinnick made a blog post about exactly what I wanted to do, which a kind soul preserved on Django Snippets
Using Malcom's code as a model, I solved my problem and it works like a charm
class PressureReadingUpdate(forms.Form):
"""
Form that asks for the pressure of a line given some attributes of that line.
"""
psi = forms.IntegerField(widget=forms.NumberInput)
def __init__(self, *args, **kwargs):
self.line = kwargs.pop('line')
kwargs['auto_id'] = "%s".format(self.line.number)
super(PressureReadingUpdate, self).__init__(*args, **kwargs)
class BasePsiReadingFormset(BaseFormSet):
"""
Formset that constructs a group of PressureReadingUpdate forms by taking a queryset
of Line objects and passing each one in turn to a PressureReadingUpdate form as it
gets constructed
"""
def __init__(self, *args, **kwargs):
self.lines = kwargs.pop('lines')
super(BasePsiReadingFormset, self).__init__(*args, **kwargs)
self.extra = len(self.lines)
self.max_num = len(self.lines)
def _construct_form(self, i, **kwargs):
kwargs['line'] = self.lines[i]
form = super(BasePsiReadingFormset, self)._construct_form(i, **kwargs)
return form
PsiReadingFormset = formset_factory(form=PressureReadingUpdate, formset=BasePsiReadingFormset)
This gives you a Formset with an extra kwarg you can pass down the chain of constructors. You can use it in a view (along with a more typical initial= kwarg) with:
formset = PsiReadingFormset(lines=lines,
initial=[{'psi': l.current().psi} for l in lines],
So here's the best explanation I can think of:
Any kwargs passed to a FormSet like (which gets made by the formset_factory function using a non-default 'BaseFormSet' as a blueprint) get passed along -- mostly unaltered -- to the __init__ method of whatever BaseFormSet the FormSet is based on.
This means you can define custom behavior in BaseFormSet.__init__, and you can relay runtime data to the BaseFormSet.__init__ method by passing it as a keyword argument to FormSet (that's the lines= kwarg in my example above). I use it to set an attribute on on formset (an instance of a FormSet based on 'BasePsiReadingFormset').
Confused yet? I was too at first.
But the real magic is understanding how _construct_forms works: A FormSet calls this function each time it wants to make a new Form in the set. It will relay any unrecognized kwargs to to the constructor of the Form it is supposed to manage a set of.
So you just need to overload your custom BaseFormSet's ._construct_forms to wrap the original _construct_forms of the superclass and inject a new kwarg. This kwarg will then be passed through to the constructor of your custom Form class, and shape the new Form instance according to the Form's initialization function.
And that, ladies and gentlemen, is how you can have a FormSet that has a bunch of similarly-defined but dynamically-generated-and-slightly different forms in it.
After understanding this, I can see the elegance of it. However, it uses some intermediate-to-advanced python, and is neither immediately obvious nor well documented. If you are struggling with this like I did, feel free to message me.