How to format a part of a string in python? - python

What I want to do is:
property = "name"
formatter = "my %s is %s" % property
print formatter % "wong2" // "my name is wong2"
but the first line gives "not enough arguments for format string" error.

>>> property = "name"
>>> formatter = "my %s is %%s" % property
>>> print formatter % "wong2"
my name is wong2

A double-percent will create a single-percent sign after formatting:
formatter = "my %s is %%s"

You can escape a formatter by doubling it
formatter = "my %s is %%s" % property
You can also do all substitutions at the same time using by-name instead of positional formatting:
formatter = "my %(property)s is %(name)s"
print formatter % { "property": "name",
"name": "wong2" }
This forms allows for a variable number of substitutions (i.e. not all keys in the dictionary needs to be used and they may be used more than once). This is important if for example the format string is read from a configuration file.

Here's a fun way to do it with a helper class
>>> property = "name"
>>> class D(dict):
... def __missing__(self, key):
... return "%("+key+")s"
...
>>> formatter = "my %(property)s is %(value)s"%D(property=property)
>>> formatter%D(value="wong2")
'my name is wong2'

I personally don't like the % formatting syntax, so I'll suggest quite the same as previous answers but using the format syntax:
property = 'name'
formatter = "my {} is {{}}".format(property) #=> "my name is {}"
print formatter.format('wong')

Related

how to convert json to model in python3

i am trying convert json string to model
then it is easy to get value with .
i have checked another question
but different, my json sting looks like,
{
"id":"123",
"name":"name",
"key":{
"id":"345",
"des":"des"
},
}
i prefer to use 2 class like,
class A:
id = ''
name = ''
key = new B()
class B:
id = ''
des = ''
There are few libraries that might help:
marshmallow is nice
colander from Pylons
schematics
For easier cases you can also use something from standard library like
named tuples and one from collections which is available also in py2
SimpleNamespace
In order to do that you should provide your custom callback as an object_hook argument to the json.loads function.
object_hook is an optional function that will be called with the
result of any object literal decode (a dict). The return value of
object_hook will be used instead of the dict. This feature
can be used to implement custom decoders (e.g. JSON-RPC class hinting).
Consider using collections.namestuple subclasses:
json_str = '''
{
"id":"123",
"name":"name",
"key":{
"id":"345",
"des":"des"
}
}'''
B = collections.namedtuple('B', 'id des')
A = collections.namedtuple('A', 'id name key')
def make_models(o):
if 'key' in o:
return A(o['id'], o['name'], B(id=o['key']['id'], des=o['key']['des']))
else:
return o
result = json.loads(json_str, object_hook=make_models)
print(type(result)) # outputs: <class '__main__.A'>
print(result.id) # outputs: 123
print(result.key.id) # outputs: 345

Line breaks Django string

Is there a way to display line breaks in a rendered Django string?
contact_message = "Name: %s | Email: %s" % (
form_name,
form_email,
)
For example, the code above currently prints as:
Name: <rendered name> | Email: <rendered email>
Is there a way to make it print like this:
Name: <rendered name>
Email: <rendered email>
I will be using the send_mail function, so I am hoping to make the readability more visually appealing.
Thank you!
When sending mail, a simple \n should be enough:
contact_message = "Name: %s\nEmail: %s" % (
form_name,
form_email,
)
This won't work in HTML, there you need HTML tags and then you have to mark the string as safe: https://docs.djangoproject.com/en/1.8/ref/utils/#module-django.utils.safestring
if you want just to have a new line you can just do it with:
contact_message = "Name: %s \n Email: %s" % (
form_name,
form_email,
)
\n is the way to go in django!

serialize a datetime as an integer timestamp

I would like for django rest to not convert my DateTime model field into a string date represtation when serializing it.
response_date = serializers.DateTimeField(source="updated_at")
I would like this to come out as
1411880508
and not
"2014-09-28T05:01:48.123"
You'll want to write a custom serializer field, like so:
class TimestampField(serializers.Field):
def to_native(self, value):
epoch = datetime.datetime(1970,1,1)
return int((value - epoch).total_seconds())
To support write operations you'd want to inherit from WritableField and also implement from_native().
EDIT for DRF 3.x & Python 3.8:
class TimestampField(serializers.Field):
def to_representation(self, value):
return value.timestamp()
If you want a JavaScript style timestamp:
class JsTimestampField(serializers.Field):
def to_representation(self, value):
return round(value.timestamp()*1000)
REST_FRAMEWORK = {
# if you want with milliseconds or
'DATETIME_FORMAT': '%s.%f',
# only with seconds
'DATETIME_FORMAT': '%s',
}
Result in REST will be string
"1517863184.666435"
"1517863249"
If you want float(or integer) value in API, than you can use monkey patching.
Put the file monkey_patching.py in any of your apps and import it in app's __init__.py file. ie:
app/monkey_patching.py
#app/monkey_patching.py
import six
from rest_framework import ISO_8601
from rest_framework.fields import DateTimeField
from rest_framework.settings import api_settings
def to_representation_ext(self, value):
if not value:
return None
output_format = getattr(self, 'format', api_settings.DATETIME_FORMAT)
if output_format is None or isinstance(value, six.string_types):
return value
if output_format.lower() == ISO_8601:
value = self.enforce_timezone(value)
value = value.isoformat()
if value.endswith('+00:00'):
value = value[:-6] + 'Z'
return value
# FOR INTEGER RESULT 'DATETIME_FORMAT': '%s',
# return int(value.strftime(output_format))
# FOR FLOAT RESULT 'DATETIME_FORMAT': '%s.%f',
return float(value.strftime(output_format))
DateTimeField.to_representation = to_representation_ext
app/init.py
#app/__init__.py
import app.monkey_patching
Tested with Django version 2.0.10 and Python 3.5.9
I was not able to get Tom's example to work and it seemed the values were not being modified. However it gave me a starting point and after some reading I found a way to produce the desired result:
[METHOD 1]
serializers.py
import time
class TimestampField(serializers.Field):
def to_representation(self, value):
return int(time.mktime(value.timetuple()))
class MySerializer(serializers.ModelSerializer):
ts = TimestampField(source="my_fieldname") #Source must be a models.DateTimeField
class Meta:
model = myModel
fields = ('id', 'ts')
JSON output:
[{
"id": 1,
"ts": 1475894303
},
{
"id": 2,
"ts": 1475833070
}]
[METHOD 2]
Tom's explanation and the previous mentioned method are definitely more on track with maintaining standards (as the results are actually of type integer).
However a quick and dirty solution is to specify the format parameter for the DateTimeField and set it to show the value in seconds.
Note this probably won't work correctly on Windows machines!
And may result in a ValueError: Invalid format string
To try it out just include the "format" keyword parameter in your serializer field like so:
serializers.py
class MySerializer(serializers.ModelSerializer):
timestamp = serializers.DateTimeField(format="%s")
class Meta:
model = myModel
fields = ('id', 'ts')
JSON output:
[{
"id": 1,
"ts": "1475890361"
},
{
"id": 2,
"ts": "1475833070"
}]
Additionally you may include microseconds:
timestamp = serializers.DateTimeField(format="%s.%f")
If you want to test the functionality in your own interpreter (to verify your OS supports the %s parameter) just copy over these lines:
import datetime
print datetime.datetime.now().strftime('%s') #datetime formatted as seconds for REST
import time #This is just for confirmation
print time.mktime(datetime.datetime.now().timetuple()) #time object result as float
I feel this method is a little inconsistent with the OPs question because the result is not actually of type integer, instead it is a string representation of an integer/float - and REST will surly add quotes around the value.
Although I prefer the answer given by Tom Christie as it is more robust.
I decided to post my solution for the benefit of the potential readers
response_date = serializers.SerializerMethodField('get_timestamp')
def get_timestamp(self, obj):
#times 1000 for javascript.
return time.mktime(obj.updated_at.timetuple()) * 1000
Global Configuration:
REST_FRAMEWORK = {
'DATETIME_FORMAT': '%s.%f',
}
In python, the timestamp is 10 digit. However, in Javascript, it is 13 digit.
Therefore, if you want to return Javascript format timestamp in global configure, just add '000' after '%s':
JS_TIMESTAMP = '%s000'
REST_FRAMEWORK = {
'DATETIME_FORMAT': JS_TIMESTAMP,
'DATE_FORMAT': JS_TIMESTAMP
}
The result will looks like this: 1567413479000
As mentioned before you can set timestamp format for all datetimes globally by:
REST_FRAMEWORK = {
'DATETIME_FORMAT': '%s',
}
But this doesnt work for regular dates, to make it work for dates you also have to set:
REST_FRAMEWORK = {
'DATE_FORMAT': '%s',
}
Thanks to #megajoe for monkey patch solution. I was developing on windows so was getting invalid format string since windows does not support any "%s" format (http://msdn.microsoft.com/en-us/library/fe06s4ak.aspx).
So I used monkey patch like #megajoe and tweaked the solution a little to return value.timestamp() for "%s.%f" and int(value.timestamp()) for "%s".

Regexp: match quotes, that are not in substitution

My template engine translates
"some data #{substitution_expression} some other data"
into
"some data" + (substitution_expression) + "some other data"
But if "some data" or "some other data" would have double quotes inside, the evalution fails.
I have to add slashes before these quotes, but I can not come up with the right regular expression for that.
Any help?
UPDATE:
This is how the template engine works:
It gets a template string, e.g.
template = 'template string "quoted text" #{expression}'
It changes the template string by a simple regexp to:
template = '"%s"' % re.compile(r'\#{(.*)}').match(r'" + (\1) + "', template)
# template == "template string "quoted text"" + (expression) + ""
# here is a problem with a "quoted text" - it needs \ before quotes`
This string is being inserted into lambda, and the result code string is being evaled:
return eval("lambda tpl_args: %s" % modified_template_string)
The lambda is being called later at the program with some tpl_args to generate a result string.
Have you tried the re.DOTALL flag?
re.compile(r'\#{(.*)}', re.DOTALL)

Find a way to add a string to a tuple

y="Peter Email: peter#rp.com Phone: 91291212"
z="Alan Email: alan#rp.com Phone: 98884444"
w="John Email: john#rp.com Phone: 93335555"
add_book=str(y) ,"" + str(z) ,"" + str(w)
**I am trying to add a contact into my address book but I am not sure how to add the string "details" into the add_book. I also found that I cannot use append because its a tuple.
details = raw_input("Enter name in the following format: name Email: Phone:")
print "New contact added"
print details
if details in add_book:
o=add_book+details
print "contact found"
print details
print add_book
address_book = {}
address_book['Alan'] = ['alan#rp.com, 91234567']#this is what I was supposed to do:
#but when I print it out, the output I get is:
{'Alan': ['alan#rp.com, 91234567']} #but I want to remove the '' and {}
I am still an amateur in programming with python so I really need all the help I can get, thanks:)!!
A simple fix would be to use a list instead of a tuple. You can do this by changing your initialization of add_book from:
add_book=str(y) ,"" + str(z) ,"" + str(w)
to:
add_book = [y,z,w]
#No need to call str() every time because your data are already strings
However, wouldn't it make more sense to organize your data as a list of dictionaries? For example:
contacts = ["Peter", "Alan", "John"]
addr_book = [len(contacts)]
for i in range(len(contacts)):
contact = contacts[i]
email= raw_input(contact+"'s email: ")
phone= raw_input(contact+"'s phone: ")
addr_book[i] = {'name':contact, 'email':email, 'phone':phone}
FURTHERMORE:
If I understood your question correctly, you have specific requirements as to how the output of your program should look. If you use the above data format, you can create whatever output you like. for example, this code
def printContact(contact):
print contact['name']+': ['+contact[email]+','+contact[phone]+']'
will output something like:
Alan: [alan#email.com,555-555-5555]
Of course you can change it however you like.
firstly [] is a list. a tuple is (,);
so what you want is
address_book['Alan'] = ('alan#rp.com', '91234567')
But this seems quite odd. What i would do is create a class
class Contact(object):
name = "Contact Name"
email = "Contact Email"
ph_number = "00000000"
def __str__(self):
return "%S: %s, %s" % (self.name, self.email, self.ph_number)
then
address_book = []
contact_alan = Contact()
contact_alan.name = "Alan"
contact_alan.email = "alan#rp.com"
contact_alan.ph_number = "91234567"
print contact
(not next to a machine with python so it might be slightly wrong. Will test it when i can get to one.)
EDIT:- as Paul pointed out in his comment:
class Contact(object):
def __init__(self, name, email, ph_number):
self.name = name
self.email = email
self.ph_number = ph_number
contact_alan = Contact(name="Alan", email = "alan#rp.com", ph_number="91234567")

Categories

Resources