Testing a many to many intermediate model with mock - django

I have two tables that are joined through a custom intermediary table:
class Foo(models.Model):
title = models.CharField(max_length=255)
class Bar(models.Model):
title = models.CharField(max_length=255)
foos = models.ManyToManyField(Foo, through="FooBar")
class FooBar(models.Model):
some_attr = models.BooleanField(default=True)
foo = models.ForeignKey(Foo)
bar = models.ForeignKey(Bar)
When it comes to testing the save functionality of these models, I'm at a bit of a loss. saving Foo and Bar instances on their own are fine, but how do I test that I can add and save many to many relationships with FooBar using mocking? Should the many to many addition test happen on the FooBar model or the Bar model? I guess I'm just looking for a bit of direction in testing these kinds of models using mocking rather than fixtures.

I ended up using factory-boy for this, it provides an easy way to set up instances for testing while being far more flexible than using fixtures.
Other options include model-mommy which does a similar thing, and people say the syntax is easier to work with.

Related

How to make one to many relationship that uses many diffrent models in Django?

I'm writing one of first Django apps and
I have recipe model like this:
class Recipe(models.Model):
name = models.CharField(max_length=64)
and also many other models for steps in recipe:
class BaseStep(models.Model):
recipe = models.ForeignKey('recipe.Recipe', on_delete=models.CASCADE)
class TextStep(BaseStep):
text = models.CharField(max_lengh=4096)
class ListStep(BaseStep):
list_elements = models.CharField(max_length=2048)
class TimerStep(BaseStep):
time = models.PositiveIntegerField()
above models are simplified, what makes them pointless but I need them this way. I know that normally I would specify ForeignKey in BaseStep so that I have some reference, like this:
recipe = models.ForeignKey('recipe.Recipe', related_name='steps', on_delete=models.CASCADE)
but this simply doesn't work, because it's inherited by child models, with is not OK because related_name needs to be unique. In the end I need to have field steps in Recipe that will return array or queryset of all the steps. I know that Proxy Models can do something like that but using it here is stupid. Now that I'm thinking, is making a #property function in Recipe, that will query all steps and return python array out of them class a good idea? I need to serialize it in the end, for rest endpoint.
Take a look at https://django-polymorphic.readthedocs.io/en/stable. This offers tools to easily work with model inheritage.

Is there an alternative to using generic foreign keys to handle similar model trees?

My scenario: I'm trying to build a database to track production schedules for different types of shows. I've mapped that out with the following model structure.
class Studio(models.Model):
...
class Series(models.Model):
studio = models.ForeignKey(Studio)
...
class Season(models.Model):
series = models.ForeignKey(Series)
...
class Episode(models.Model):
season = models.ForeignKey(Season)
...
class Production(models.Model):
episode = models.ForeignKey(Episode)
But I'm now interested in tracking production of movies as well. This presents a challenge though, because movies don't have the same tree structure as TV. Something like this would be more fitting:
class Studio(models.Model):
...
class Movie(models.Model):
studio = models.ForeignKey(Studio)
...
class Production(models.Model):
movie = models.ForeignKey(Movie)
The problem here is that Production and Studio are exactly the same for both movies and TV (at least in this scenario), so I'm hesitant to have totally separate trees, because this would necessitate duplicating Production. One for TV and one for Movies, when the only difference is the foreign key.
Does it make sense to use a GenericForeignKey here? Where a production can either point at an Episode or Movie? I'm hesitant to do so because it sounds like the consensus is to avoid generic foreign keys, but I'm not sure how else to do so.
I faced a similar issue a while back, and I came to the conclusion that it would be more efficient (and less trouble later on) with 2 foreign keys, and 2 boolean variables informing the type in these tables.
Also from your code I see no reason to duplicate the Studio model as it is identical, and contains no unique foreign key field. Production model however can be written like this
class Production(models.Model):
movie = models.ForeignKey(Movie, null=True)
episode = models.ForeignKey(Episode, null=True)
is_movie = models.BooleanField(null=False)
is_episode = models.BooleanField(null=False)
What you choose to identify the foreignkey field up to you but boolean is known for its small size in the database.

Django 1.8 - Intermediary Many-to-Many-Through Relationship - What is the consequence of where 'ManytoManyField' is used?

An example Many-to-Many through relationship in Django:
class First(models.Model):
seconds = models.ManyToManyField(Second, through='Middle')
class Middle(models.Model):
first = models.ForeignKey(First)
second = models.ForeignKey(Second)
class Second(models.Model):
Following the documentation on intermediary models, only one model of the pair to be related contains the ManytoManyField, model First in the example above. Is this correct?
If so, which model should contain the ManytoManyField field? Are there any differences in using the relationship from either end depending on where the ManytoManyField is?
Thanks
EDIT (I should have been clearer):
I'm interested in an Intermediary table because I will have additional data to store on the relationship.
When I say usage, I don't mean defining the models, I mean using the relationship (otherwise I'd let Django do it's thing).
If I want all Seconds related to a First, would it be exactly the same as getting all Firsts related to a Second, or would the ManytoManyField make one direction easier to do than the other by introducing any extra functionality?
There shouldn't be a difference from an operational perspective, so the only difference would be in the definition of the model and things that affect it (for instance, Manager classes).
You also don't always need to define a "through" class. Django does that automatically for you, and all that class really does is maintain a third table to track the respective IDs for each related record in the two other tables. You have to decide whether you want to add anything to that third table that is important.
For instance, say you are designing a web app for a conference. They might want to store information about the attendees (both individuals and companies), as well as the speakers and sponsors (also individuals and companies). Part of your models for companies might look like this:
class Company(models.Model):
name = models.CharField(max_length=100)
sponsored_segment = models.ForeignKey(ConferenceSegment, null=True)
class ConferenceSegment(models.Model):
title = models.CharField(max_length=100)
But that gets cumbersome quickly, and you'll have lots of attending companies that have nothing to do with sponsoring. Also, you might want to track their rank/package on the website (after all, bigger sponsors get bigger placement):
class Company(models.Model):
name = models.CharField(max_length=100)
class ConferenceSegment(models.Model):
title = models.CharField(max_length=100)
sponsors = models.ManyToManyField(Company, through=u'Sponsor', related_name=u'sponsored_segments')
class Sponsor(models.Model):
company = models.ForeignKey(Company)
segment = models.ForeignKey(ConferenceSegment)
rank = models.PositiveIntegerField()
Notice also the "related_name" attribute in the ManyToManyField. This means that we can access the ConferenceSegment object via a Company instance by using that name:
c = Company.objects.get(...)
segments = c.sponsored_segments.all()
Hope this helps.
When you add a many to many field to a model a separate table is created in the database that stores the links between two models. If you don't need to store any extra information in this third table then you don't have to define a model for it.
class First(models.Model):
seconds = models.ManyToManyField(Second, related_name='firsts')
class Second(models.Model):
pass
I can't think of any difference between defining the many to many field in the First or Second models:
class First(models.Model):
pass
class Second(models.Model):
firsts = models.ManyToManyField(First, related_name='seconds')
In both cases usage is the same:
firsts = my_second.firsts
seconds = my_first.seconds

django inheritance hurts my brain

I'm making a beer website, and I'm stuck. I need to have a recipe that i can relate to many different ingredients. Is there a way to create a model "Ingredient", and inherit many different models: "Hop", "Grain", etc. I would want to do this so I have my relationship between recipe and ingredient, and i don't have to create 100 different relationships to cover each kind of ingredient.
Is this possible?
Although I would personally advise against it in most cases since table inheritance is a pain (imho) in Django.
You can do it like this:
class Recipe(models.Model):
name = models.CharField()
class Ingredient(models.Model):
name = models.CharField()
recipes = models.ManyToManyField(Recipe, related_name='%(app_label)s_%(class)s')
class Hop(Ingredient):
pass
class Grain(Ingredient):
pass

How to fetch the top two products for each product type?

Let's say I have two models looking like this:
class ProductType(models.Model):
product_type = models.CharField(max_length=100)
class Product(models.Model):
name = models.CharField(max_length=200)
slug = models.SlugField()
product_type = models.ForeignKey(ProductType)
score = models.PositiveIntegerField(default=0)
Now I want to fetch the top two products (the two with highest score) from each ProductType.
So if I have Phones, Computers, TVs as ProductTypes I want the two best Phones, Computers, TVs.
As I don't even know how to do this in MySQL I've tried searching for the MySQL-solution but the ones I find is extremely complex and this doesn't feel like an extremely complex thing to do.
I am leaning towards making an own model for the top products and have a cronjob to fix this, but I'd like to see if there's an easier solution to this.
Well, you could make a method inside of the ProductType class that returns the top two results for its products:
class ProductType(models.Model):
product_type = models.CharField(max_length=100)
def TopTwoProducts(self):
return self.product_set.order_by('-score')[0:2]
Then you would just do something like:
for type in ProductType.objects.all():
type.TopTwoProducts()
While adam's solution is correct, a more django-ish way would be to use a manager.
See Managers versus class methods on James Bennett's blog
Among other advantages :
a manager carries all query-specific code, while avoiding to clutter the model class
the same manager class can be shared among several classes
the manager can be used directly on a model class, or via a one-to-many or m2m relation
Thus, for the above question :
from django.db import models
from django.db.models.manager import Manager
class ProductScoreManager(Manager):
use_for_related_field = True
def top_score(self, limit=2):
return self.get_query_set().order_by('-score')[:limit]
Then add this manager class as default manager for Product :
class Product(models.Model):
...
objects = ProductScoreManager()
...
Now, thanks to objects overriding the default manager, and use_for_related_field allowing its use in relation queries, the top_score method can be used in any model related to products.
myproducttype = ProductType.objects.get(...)
myproducttype.products.top_score() # return top 2 products
This allows a more consistent syntax : the related products is always accessed via products, top_score acting as a filter. Additionally, ProductType class is no more cluttered with Product's query logic.
Just filter out product type from Product model slice them like this -
product_type_list = ProductType.objects.value("id")
for product_type in product_type_list:
Product.objects.filter(
product_type=product_type
).order_by("-score")[0:2]