Most Pythonic double dispatch for extracting View information from Model - python

I'm coding a desktop app with Python and Qt, using PySide. I need to display a tree view in which top-level items are objects of different type than their children. Specifically, a top-level item is a Git repository, whereas its children are directories in the work tree.
For a repository, I want to show its path and currently checked-out branch. For a directory, I just want to show its name.
Right now, I do this by having my QAbstractItemModel descendant use isinstance on the underlying model object (retrieved from internalPointer() method) and decide how to format the resulting string.
I was wondering whether there was a more Pythonic (or just less clunky) way of doing this kind of double dispatch.
What I don't want to do is define a method for this purpose in my model classes for Git repo and work tree file, because I feel this would violate SRP.
Any thoughts or ideas are most welcome. Also, if anyone can think of a less clunky title for this question, let me know ;)

If you were ok with each Model class having a function containing View code, then you could just call those functions. To separate the Model/View code without using isinstance, this sounds like a case for the Visitor pattern, as described in this SO answer, and as used in the ast module.
Basically, each Model class has an accept() method that takes a Visitor object. The accept() method for a repository calls the visit_repository() method of that Visitor object, passing self (which is the Model instance). Similarly, the accept() method for a directory calls the visit_directory() method of that Visitor object, passing self. The visit_repository() or visit_directory() method then has access to the Model instance and knows its type and can show the appropriate view. This separates the View code (in the Visitor object) from the Model code (in the Model class).
*Note: instead of using different function names (visit_repository() vs visit_directory()), you can use multimethods, e.g., this SO answer about multimethods in Python.

Related

What methods should a model contain

When I have a model Car where users can upload a single picture to, I can create a property ImageFile in Django to achieve that. Now I would also like to get the metadata from this file and save them to the database.
Now I'm very unsure where I should place this method a how I should design it. It would be obvious, to have a method like _set_exifdata() or _update_exifdata() that is called every time I set an Image to the model.
Or a method get_exifdata(imagefile) that returns a dict of exifdatas. But should this method be part of the Car model? Actually, I won't need it anywhere else, so it does not make sense to put it in a general helper class. But on the other hand, I would prefer to split methods in "retrieving data" and "setting data", so _update_exif() for example would do both of it in once, and maybe that's OK in design ways, but maybe its not and there is some rules of model design I should know and respect here.
I hope someone can help me with some guidelines for model design (especially for django) and what methods should be part of methods and which should not.
if you using only for the car then you can put that value in the model save method,
which will get call every time whenever you will update the data.

Get Django to include the model id in the string representation of all model instances for debugging

Django's model Model class defines a __repr__ method that combines the model class name with the string representation of the instance, so that a typical object will show up in the shell or in debugging tools in the following format:
<MyClass: string description of instance>
What I want is for all of my objects instances to show up with their ids in their __repr__, e.g.
<MyClass 123: string description of instance>
This is for debugging convenience.
Now, it would be easy enough (in principle) to override my __unicode__ methods (which generate the string description of instances) to include the ids, or for that matter to override my __repr__ methods (or to have all my model classes derive from a base class that does so).
However, I'm working with an existing code base and want to avoid changing all the existing model class definitions for this. The quick-and-dirty way to change things is to edit the source code for __repr__ in Django's Model class. But that creates deployment issues as my project always deploys third-party libraries like Django from pip.
So: how can I get Django to include the id in the repr for all object instances without either changing the Django source code or my project model class definitions?
NOTE: I'm thinking some kind of monkey patch to Model.__repr__ should do the trick, but I'm not sure if that would work and if so where in my Django project to do it.
Monkeypatching Model.__repr__ should work. Something like:
def debug_repr(self):
return "<{} {}: {}>".format(self.__class__.__name__, self.pk, self)
Model.__repr__ = debug_repr
This is based on the implementation in the source code.
Where you do this depends on your debugging setup. If you're working in the console you can just type this in directly. If you want to put it in code but not interfere with other deployments, you should probably create a new settings file for your debugging environment and then trigger the monkeypatch that way.

sphinx autosummary and dynamic methods

I have found much use of using setattr() to make dynamically generated class methods and attributes. I have also been using sphinx to create documentation, which is fantastic.
The problem is that i cannot use the autosummary feature of sphinx if the attributes and methods are dynamic. Is there a clever way to do this? The dynamic methods and attributes are created upon initialization.
Try this (it's a little wacky):
Create an instance of your class in your conf.py file.
Use the autodoc-process-docstring event to fire a handler (which you will need to write) to copy the __doc__ elements for the various dynamic methods from the instance you created in 1) into the output for the class.
It's not a simple solution, nor easy, and heck, maybe not even possible, but it Just Might Work if you can figure out how to get things to happen at thw right time.

Is adding attributes dynamically frowned upon in Python?

In Python, you can assign an arbitrary attribute from outside the defining class:
class Profile(models.Model):
user = models.OneToOneField(User)
name = models.CharField(max_length=140)
p = Profile()
p.age = 42
The underlying mechanism here is __dict__ attribute that maintains a dictionary of all attributes.
We were all told not to expose our inner workings to the client code, but attaching new data doesn't have to do with encapsulation at all, right? Is this idiom common for Python code?
Just What I Mean…
Each Tweet has standard fields, like id, text, owner.
When returning tweet list for a user, you want to display if a tweet is “favorited” by this user.
Obviously, to obtain is_favorite you need to query many-to-many relationship for this user.
Would it be OK to pre-fill Tweet objects with is_favorite corresponding to current user?
Sure I could expose a method is_favorite_for(user) but I'm hitting Django template language limitations that doesn't allow to call methods with arguments from inside the template. Also, I believe a template should not be calling methods at all.
I know this will work fine, but I wonder if doing something like that in an open source project would get other developers to look on me with contempt.
Sidenote:
I come from C#/.NET background where dynamic types were introduced very recently and aren't adapted widely except for some niche areas (interoperability, IoC frameworks, REST client frameworks, etc).
My view is that it is a bad practice.
The object doesn't know that you're messing with its attributes. Consider, for example, what would happen if Profile were later expanded to have an attribute called age, unrelated to p.age in your code.
If you want to add attributes, why not subclass Profile, or have an external mapping of Profiles to an object with your custom attributes?
I think the answer is: It depends. First, if you really want to prevent it you can by defining __slots__ in the class. And it is not generally a good practice to add attributes not actually defined in the class, as it can be confusing to someone reading
the code and is rarely useful.
But at certain times, it is useful to be able to do this and Python documentation discusses this as a way to get something similar to a C struct or Pascal Record (see http://docs.python.org/tutorial/classes.html under section 9.7 Odds and Ends.)
If the attribute is only there sometimes, you risk getting an AttributeError out of nowhere for one object while the code worked fine for another object of the same class (yes, exact types aren't that important when duck-typing, but objects of the same class are frequently assumed to be of the same "duck type"). Even if it doesn't happen, you can't be sure just by looking at part of the code, and it's much harder to check in any case. So, doing this only makes your code less reliable.
Then there's the option of providing a default attribute as class attribute or property, only assigning an object attribute when it differs from the default. But for stuff that is expected to vary per object, the clarity of having every attribute ever listed in __init__ usually outweights any potential advantages of delaying instance attribute access.
That is not to say it's not acceptable, but you'd have to make a compelling argument for it to be considered a good idea.

Django: Chicken or Egg question

I am building an application that will send an API call and save the resulting information after processing the information in a APIRecord(models.Model) class.
1) Should I build a separate class in such a way that the class does the API call, processes the information (including checking against business rules) and then creates an instance of my APIRecord() class?
Or
2) Should I build a separate class with the appropriate methods for processing, and calling the API, and then in my model, override the APIRecord.save() method to call the separate class's API methods and then save the results?
Or
3) Should I build my model class with the appropriate methods for calling the API and processing the response (including checking for certain values and other business rules)?
I tried # 2 and ran into problems with flexibility (but am still open to suggestion). I'm leaning towards # 1, but I'm not sure of all the negatives yet?
it is design decision.
it depends to your design and programming interests.
i used the combination of three methods you said. if i need to some informations that can be build from other fields then i will create an internal function in model class. if i need other records of database to do something i will create an function outside of model class. and other unusual needs will be computed everywhere i need them.

Categories

Resources