
A couple of years ago I was lucky to have a WordPress blog. To this day, a blog, like the entire base of posts, unfortunately did not live to see me, but I don’t want to tell about the blog itself, but about how all the information was published. At that time, Microsoft recently launched Windows 7, and with it the Windows Live application package. So I decided to take a look - why is this package delicious? Most of all I liked the Windows Live Writer application - a program that allows you to type and format texts and publish them to a blog. Convenient interface, many formatting tools, the ability to store drafts locally, and much more - I fell in love. Some time later, I didn’t even submit my blog without Windows Live Writer.

Passed a couple of years. As already mentioned, that blog was gone, and I got into programming in Python, and then Django. In the process of learning the framework, there was a desire to start a new blog, but this time - the program part to write yourself, the benefit with Django is simple and fun. And now the main page with news, several sections, support for comments, etc., has appeared, but something was missing - convenient editing and publication of texts. This is where I remembered Windows Live Writer. Can I use it to post to my blog? As it turned out - I can, everything is quite simple. By default, the application only supports publishing to a few popular blog services, but nothing prevents you from adding a new one — it’s enough that the blog supports publishing based on the MetaWeblog API. I will not talk about the standard itself - the
Wiki will do it better than me. We will focus on how to implement the server side of MetaWeblog on a site with Django. The process itself is quite simple, but as it turned out, there is not that much information in Russian on the topic, and basically this is PHP, or .NET code. This text does not in any way pretend to be complete - my goal is more likely to simply send the same beginners as I did along the right path, in order to understand further it was not difficult.
And so, what do we need? To begin with, an
XML-RPC server (based on XML-RPC, the MetaWeblog API functions). The default delivery of Python includes xmlrpclib which could be enough, but it seemed to me that having a server interacting directly with Django is more convenient. After some time the search was found
django-xmlrpc - convenient server - handler for XML-RPC requests. Here we will use it. Installation is simple and should not cause questions. At the end of the installation at
http: // domain / xmlrpc / you can see the list of registered methods. The basic setting is the variable
XMLRPC_METHODS, the definition of which must be placed somewhere in setting.py, and it represents the map of the cards, which contain the path to the function - the processor, and the name of the method. For example:
')
XMLRPC_METHODS = (('myproject.myapp.views.get_users_blogs', 'blogger.getUsersBlogs'),)
Thus, we registered a method called blogger.getUsersBlogs, the handler for which is a function. Because we will need a method with exactly this name in the future - I suggest registering it with you.
Now let's go directly to the function at the specified address. By default, Meta Weblog API has several methods that need to be implemented, and specifically:
- metaWeblog.newPost ()
- metaWeblog.getPost ()
- metaWeblog.editPost ()
- metaWeblog.getCategories ()
- metaWeblog.getRecentPosts ()
- metaWeblog.newMediaObject ()
More details about the received and returned data methods can be found, for example,
here . However, we also need methods:
- blogger.getUsersBlogs ()
- blogger.deletePost ()
- blogger.getUserInfo ()
But if the last two are needed, and still optional, then without the first Windows Live Writer, it’s simply not possible to register your website with you. It is for this reason that we’ll start with blogger.getUsersBlogs (). And so - here is the handler function code:
from django_xmlrpc.decorators import xmlrpc_func @xmlrpc_func(returns='string', args=['string', 'string', 'string',]) def get_users_blogs(appKey, username, password): user = u_authenticate(username, password) return [{'isAdmin': user.is_superuser, 'url': 'http://127.0.0.1:8000/', 'blogid': '1', 'blogName': 'MyWebBlog'}]
The code is simple, and yet requires comment. The first thing that catches your eye is the xmlrpc_func decorator. As we can see, it has two parameters, and the first is responsible for the type of data returned by the method, and the second is responsible for the type of data received. Why is this decorator needed? It adds an XML-RPC signature to our method. In general, strictly speaking, we can freely do without it, but applications - clients can read this signature to get the necessary information about the method. Well, we add that we feel sorry for what?
The function itself takes 3 parameters:
- appKey is a unique key of the client application, we will not use it.
- username - username in the service
- password - user password, respectively.
The u_authenticate function returns the user from the database, if there is one in the database, and the password is correct. You can write such a function yourself, depending on your verification requirements, but you can use the one that I have:
from xmlrpclib import Fault def u_authenticate(username, password): try: user = User.objects.get(username__exact=username) except User.DoesNotExist: raise Fault('1', 'Username is incorrect.') if not user.check_password(password): raise Fault('1', 'Password is invalid.') if not user.is_staff or not user.is_active: raise Fault('2', 'User account unavailable.') return user
Fault generates XML-RPC Error, the first parameter of which is the error code (arbitrary, at your discretion), and its textual representation. It is this code and the text will show the application - the client in case of problems.
Let's return to our function get_users_blogs, and the data returned to it. As we see this list, it contains a dictionary with the following elements:
- isAdmin - indicates whether the user is an administrator.
- url - directly the address of your blog in the network
- blogid - unique ID of your blog in the service. Needed in case there are several blogs on your site. If you have only one, then any number is enough, for example, zero.
- blogName - the name of your blog will be used as a title in client applications.
Please note that the url in the code, as well as the name of the site are strictly specified, which is not quite right at all - in case of changing the address or the name of the site, you will have to change the code of the set of functions. For good, it is desirable to store such things in separate variables somewhere in the settings, but then I left everything in this form to simplify understanding.
In fact, that's all. You can already try to add a blog in Windows Live Writer, specifying something like
http://127.0.0.1:8000/xmlrpc/ as an address for interaction, and Meta Weblog API as an interface. If everything is done correctly, Windows Live Writer will register the blog at home, and will also offer to download the visual blog theme (html, css) for the preview function before publication, but now we have to refuse - to determine the theme Windows Live Writer publishes a temporary record, while the method for posting metaWeblog.newPost () records is not yet implemented. So what are we waiting for?
In the same way, first of all, add the method to XMLRPC_METHODS:
('myproject.myapp.views.new_post', 'metaWeblog.newPost')
Now let's get to the handler function:
from datetime import datetime @xmlrpc_func(returns='string', args=['string', 'string', 'string', 'struct', 'boolean']) def new_post(blog_id, username, password, post, publish): user = u_authenticate(username, password) item = News() item.title = post['title'] item.text_news = post['description'] if post.get('dateCreated'): item.date = datetime.strptime(str(post['dateCreated']), '%Y%m%dT%H:%M:%S') else: item.date = datetime.now() item.author = user item.public = publish item.save() return item.pk
The code is also very simple, but I will comment on just in case:
The first three accepted values should be clear, I will focus on the remaining two:
- post - directly published content. It is a dictionary that can contain a lot of things ... By default, this is of course the title - the title of the record, description - the main text, dateCreated - the date the record was created, and categories - the tags for the record. However, this is only a small part of the possible data provided by the client, and dateCreated, for example, may be absent altogether if the Windows Live Writer user forgot to specify a date. Of course, all this should be taken into account and used depending on your goals / desires, but I will not list all the possible keys that may appear in the post, they are easier to see for yourself. In the end, it's up to you to decide which of the obtained data to use for yourself.
- publish is a variable of type Boolean, equal to True if the entry should be published immediately, and False if it is worth placing in drafts.
The rest of the code is pretty simple. First we check the user for authenticity. Then an item object is created on the basis of the simplest News () news model, and is filled with the received data. Stop probably worth only item.date. The fact is that the key dateCreated contains the date and time of publication of the record, which is obvious in text format. That is why the line will have to be broken down into components, and converted into a date object. If the dateCreated key did not come at all, then we indicate the current time and date as the date and time of creation. I repeat - this is the simplest model of news, and in reality there may be much more data in your project. For example, there is no handling of the key categories, since Specifically, this news model does not contain them at all, but if you need to - no one forbids using it.
When the item object is completed, it is stored in the database, and the function returns item.pk. Here it is also worth staying in more detail. The newPost () method is required to return a unique identifier of the published record to the client in order to be able to find this record for possible editing / deleting. You can use pk as a unique identifier for item, but in general this is again not very good. The fact is that pk is essentially the ordinal number of the record in the database at the time of publication. Now think about what will happen if you publish a record through Windows Live Writer, then delete it in the Django admin panel, post a new one from it, and then try to publish the deleted record again through Windows Live Writer? A simple thing will happen: Windows Live Writer has no idea that the post has already been deleted since its publication, and another appeared in its place, but with the same as the previous pk. Thus, a post published through the admin panel will be trivially overwritten by the one that will be published from the Windows Live Writer. It is clear that in life this situation is not exactly what you encounter every day, but nevertheless, it seems like it is worth returning something more unique than pk. Nevertheless, to demonstrate the pk we have enough for the eyes.
That's all, you can go to Windows Live Writer, and enjoy the opportunity to publish new entries :).
Below is also an implementation of the methods metaWeblog.editPost (), and blogger.deletePost (). The code does not contain anything specific, so I will not dwell on it in detail.
@xmlrpc_func(returns='boolean', args=['string', 'string', 'string', 'struct', 'boolean']) def edit_post(post_id, username, password, post, publish): user = u_authenticate(username, password) item = News.objects.get(id=post_id, author=user) item.title = post['title'] item.text_news = post['description'] if post.get('dateCreated'): item.date = datetime.strptime(str(post['dateCreated']), '%Y%m%dT%H:%M:%S') else: item.date = datetime.now().date() item.author = user item.public = publish item.save() return True @xmlrpc_func(returns='boolean', args=['string', 'string', 'string', 'string', 'string']) def delete_post(apikey, post_id, username, password, publish): print post_id user = u_authenticate(username, password) News.objects.get(id=post_id, author=user).delete() return True
Both functions simply return True if successful. Now we can easily try to download the theme of our blog in Windows Live Writer - these methods are enough.
I will not give the implementation of all the other methods. The above information is quite enough to understand how the Meta Weblog API works, and it’s easy to implement the methods you need. That's all, now everything is exactly :). Simple enough, but I was somewhat surprised by the lack of Russian-language information on the topic in Python, and of any server libraries, I hope in this article to fill the gap somewhat. Personally, I am pleased that I can now publish news to my future blog through a familiar and convenient program, and you may be attracted by another client with Meta Weblog API support - the light on the Windows Live Writer is not strange. Thanks for attention.