Access RelatedManager for a model created by multi-table inheritance - django

Summary: Is it possible to access a model sub-classed via multi-table inheritance via a relatedmanager on a related model instance?
Details:
Assuming the following model definitions..
class City(models.Model):
...
class Place(models.Model):
city = models.ForeignKey(City)
class Restaurant(Place):
...
I'd like to be able to access all restaurants in the city of Portland like this:
portland = City.objects.get(id=1)
portland.restaurant_set.all()
However restaurant_set or similiar doesn't seem to be an exposed RelatedManager on City, only place_set is exposed.
Is there a way to expose restaurant_set, restaurants, or similar as a related manager when accessing a model instance of City?
I've also tried created a custom manager for Restaurant, like this:
class RestaurantManager(models.Manager):
use_for_related_fields = True
class Restaurant(Place):
objects = RestaurantManager()
However it doesn't seem to get me any closer to what I want.
Apologies in advance as this is just pseudo-code, not the actual models I'm using in my project/app. It's possible I've introduced an error here not in my actual code base, and will happily clarify and update if so.
Also, if it's possible to accomplish this without the use of a 3rd party package (like django-polymorphice etc) I'd prefer that, but if the only reasonable way is to use one of these packages, I will accept that as the answer.
Finally, I'm on Django 1.8 and cannot upgrade for the time being.

Related

How to adapt java POJO generator for Django model with custom methods?

I am done with this tutorial which shows how to use textX to write a java POJO.
I am thinking of adapting this to write Django model classes.
The issue is when I have to add custom model methods to the Django model class.
And then if I subsequently change the DSL, the generated model class will definitely remove the custom model methods.
How to I cater for custom model methods if using textX to generate Django model classes?
Well, you could use a diff/merge tool to merge the existing and newly-generated code but that will certainly require manual interventions to solve eventual merge conflicts.
FWIW, writing your model classes manually won't take much more time than writing them using a DSL (I slightly changed the DSL version to account for database-specific needs like charfields length):
entity Person {
name : string(128)
address: Address
age: integer
}
vs
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=128)
address = models.ForeignKey(Address)
age = models.IntegerField()
so I really don't think you'll gain anything with code generation here.
NB: if your problem is to generate "boostrap" models code from an existing DB schema, Django already knows how to do this without the need for a DSL.

How to deal with model changes in Django Rest Framework?

This is not a question for a particular use case, but for something I noticed in my experience doing APIs, specifically with using Django and Django Rest Framework.
Months ago I had a problem with the API I maintain for a client's project.
Let's say we have the following model:
class Person:
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
Then, the corresponding serializer:
class PersonSerializer(serializers.ModelSerializer):
class Meta:
model = Person
fields = '__all__'
Of course, its corresponding ViewSet and route pointing to it:
http://localhost:8000/api/v1/persons/
Note this is the 1st version of my API.
Everything OK at this point, right?
Now, my client asked that we need to receive person's fullname instead of first and last name separately...
As supposed, I'll have to change my model to be:
class Person:
full_name = models.CharField(max_length=200)
There are 3 different clients (mobile apps) using this version of the API. Obviously I don't want to change my API, instead I will want to put the new approach in a new version.
BUT the 1st version's Serializer is coupled with the Model, so at this point the 1st version of the API already changed
What I expect to read in answers below is how you guys deal with this problem in Django and what is the way I should take for my next projects using the same stack.
Edit: My question's objetive is to understand if is better to decouple API from Models. I've put a very very basic example, but there are cases where things get much more complicated. For example I needed to modify a M2M relation to use the through option in order to add more fields to the intermediate table.
It's type of question that could been flagged as "Recommend smth", but whatever.
First of all you need to extend your model with full_name field. If you need to be able to write to model provided full_name from your api then you need to extend with field otherwise you can deal property
#property
def full_name(self):
return '{} {}'.format(self.first_name, self.last_name)
Then you can also include field in serializer
class PersonSerializer(serializers.ModelSerializer):
full_name = serializers.CharField() # if you have property
class Meta:
model = Person
fields = '__all__'
Since you class field name and serializer field name would match you don't need to worry.
So having additional field won't break your clients and satisfy your big client.
It's been a while since you asked this, but it's an interesting question I've been contemplating on recently with the different versions of the OCPI protocol. What you describe here is basically one of the trickier situations, where a data structure needs to be refactored while retaining existing endpoints.
Copying shamelessly parts of the response from #vishes_shell, I would suggest you hide your changing data, provide properties to access it, and split your corresponding serializers and endpoints into two distinct versions.
#property
def full_name(self):
return self._full_name or '{} {}'.format(self._first_name, self._last_name)
#property
def first_name(self):
return self._first_name or self.parse_first_name(self._full_name)
#property
def last_name(self):
return self._last_name or self.parse_last_name(self._full_name)
class PersonV1Serializer(serializers.Serializer):
first_name = serializers.CharField(max_length=100)
last_name = serializers.CharField(max_length=100)
class PersonV2Serializer(serializers.Serializer):
full_name = serializers.CharField(max_length=200)
Create separate views:
http://localhost:8000/api/v1/persons/
http://localhost:8000/api/v2/persons/
This way you have your original and new endpoints working while using shared data. If you wish, you can migrate the data for first_name and last_name into full_name, and use a simpler logic for v1. That might be good for performance if you assume all clients are migrating eventually to v2, but I don't see a big difference here.
You can also find multiple different schemes for endpoint versioning in Django Rest at https://www.django-rest-framework.org/api-guide/versioning/.
Please note that self.parse_first_name() and self.parse_last_name() (which I leave as an exercise for the reader) need to be able to handle missing names. The ModelSerializer is no longer used, since it cannot determine the data types for properties, so we need to provide them explicitly.
Hope this helps all who are battling with API versioning.
we are adding api folder in django app folder, where each file like version_1_1_1.py and version_1_2_2.py represent different versions. I think other guys already suggested to use different Serializers this is right approach. I think that Your question is related to business requirements, You need to create software specification I briefly explained here https://www.itstartechs.com/software-specification which cover all features needed and update it if client request sth new.
Another approach maybe to start using SOA Service Oriented Architecture, if You are able to define problem domains of Your project that You see You can easily decoupled this is a good sign. After You have microservices solving problem domain A and B, You create fastapi or django rest service that cover api. Each api has it's own interface and needs, different things needed by mobile app and admin management app. This is very nice article explaining about api gateways https://microservices.io/patterns/apigateway.html.
Good thing to have is to design open api specification https://swagger.io/specification/, maybe is a good way for You to start with if You don't have software specification.

django multi-table inheritance, access method from child from instance of parent

I am using Multi-Table inheritance (aka Concrete Inheritance), where I have a non-abstract model + DB Table called Clients, which is concerned with common details concerning all the clients.
But a client can be an Individual, Partnership or Company, for which I have created inheriting models and tables. An Individual has first name + last name, and company has other specific particulars, etc.
I want to be able to access the names of clients (derived from the columns from the child tables) when I want a list of all clients.
After lot of searching, I found that this tutorial, works successfully.
Basically, it involves inserting a column on the Client table, which will store the name of the Child model. Then using that name, the appropriate child model is identified and appropriate child method is accessed.
But it seems to be a slightly cumbersome way to implement polymorphism in Multi-Table inheritance.
I want to know whether since 2012, Django has introduced any better way to deal with the issue, or is this still the only way?
Please let me know if my code sample is required, but the link provided has a beautiful example already.
There is django-model-utils application with Inheritance Manager. It will cast automatically your parent class to children instances. Example from docs:
from model_utils.managers import InheritanceManager
class Place(models.Model):
# ...
objects = InheritanceManager()
class Restaurant(Place):
# ...
class Bar(Place):
# ...
nearby_places = Place.objects.filter(location='here').select_subclasses()
for place in nearby_places:
# "place" will automatically be an instance of Place, Restaurant, or Bar
Also check this question for generic solution with ContentType.
And also check awesome article by Jeff Elmore about this topic. Quite old, but still great.

Purpose of using a custom manager to create objects with django?

I see in the Django documentation :
Model Instance reference : Creating objects
You may be tempted to customize the model by overriding the __init__ method. If you do so, however, take care not to change the calling signature as any change may prevent the model instance from being saved.
Rather than overriding __init__, try using one of these approaches:
Add a classmethod on the model class.
Add a method on a custom manager (usually preferred)
Why is the second solution "usually preferred" ?
In a situation where I have a model B which extends a model A through a OneToOne relation, and I want to create a method generating a B object which generates the corresponding A object as well, how is it "better" to use a custom manager as suggested, given I'll probably not use this manager for anything other than what is provided by default manager ?
I think it is preferred because it looks cleaner in code. You might also be reading into the emphasizes a bit too much, as the benefit or difference isn't that big. That said, when implementing things myself I do use the proposed approach.
Consider the following model (purely for illustrative purposes):
class Vehicle(models.Model):
wheels = models.IntegerField()
color = models.CharField(max_length=100)
In your application, the need often arises to get all cars, or all motorcycles, or whatever type of vehicle. To keep things DRY, you want some standard form of retrieving this data. By using class methods, you'd get the following:
class Vehicle(models.Model):
#(...)
#classmethod
def cars(cls):
return Vehicle.objects.filter(wheels=4)
cars = Vehicle.cars()
green_cars = Vehicle.cars().filter(color='green')
If you create a manager, you'll get something like this:
class CarManager(models.Manager):
def get_query_set(self):
return super(CarManager, self).get_query_set().filter(wheels=4)
class Vehicle(models.Model):
#(...)
car_objects = CarManager()
cars = Vehicle.car_objects.all()
green_cars = Vehicle.car_objects.filter(color='green')
In my opinion, the latter looks cleaner, especially when things get more complex. It keeps the clutter out of your model definitions, and keeps things similar to using the default objects manager.

Is There a Good Way to Forbid Templates Accessing Related Managers Through Model Instances

I need an elegant way of disabling or authorizing related field traversal in Django templates.
Imagine following setup for models.py:
class Person(models.Model):
pass
class Secret(models.Model):
owner = models.ForeignKey(Person, related_name="secrets")
Now imagine this simple view that gives the template QuerySet of all Person instances in the system just so the template could put them in a list.
def show_people(request):
render_to_response("people.html", {people=Person.objects.all()})
Now my problem is that I would not provide the templates myself in this imaginary system and I don't fully trust those who make the templates. The show_people view gives the people.html template the secrets of the Person instances through the related_name="secrets". This example is quite silly but in reality I have model structures where template providers could access all kind of vulnerable data through related managers.
The obvious solution would be not to give models to templates but to convert them in to some more secure data objects. But that would be pain in my case because the system is already quite big and it's up and running.
I think a cool solution to this would be somehow preventing related field traversal in templates. Another solution would be to have such custom related managers that could have access to the request object and filter the initial query set according to the request.user.
A possible solution could be to use a custom model.Manager with your related models.
Set use_for_related_fields = True to force Django to use it instead of the plain manager. modify the manager to filter the data as needed.
also have a look at this:
Django: using managers for related object access (use_for_related_fields docs)
stackoverflow: use_for_related_fields howto, very good explanation here.