django/tests/foreign_object/models/article.py

111 lines
3.2 KiB
Python

from django.db import models
from django.db.models.fields.related import ForwardManyToOneDescriptor
from django.utils.translation import get_language
class ArticleTranslationDescriptor(ForwardManyToOneDescriptor):
"""
The set of articletranslation should not set any local fields.
"""
def __set__(self, instance, value):
if instance is None:
raise AttributeError("%s must be accessed via instance" % self.field.name)
self.field.set_cached_value(instance, value)
if value is not None and not self.field.remote_field.multiple:
self.field.remote_field.set_cached_value(value, instance)
class ColConstraint:
# Anything with as_sql() method works in get_extra_restriction().
def __init__(self, alias, col, value):
self.alias, self.col, self.value = alias, col, value
def as_sql(self, compiler, connection):
qn = compiler.quote_name_unless_alias
return "%s.%s = %%s" % (qn(self.alias), qn(self.col)), [self.value]
class ActiveTranslationField(models.ForeignObject):
"""
This field will allow querying and fetching the currently active translation
for Article from ArticleTranslation.
"""
requires_unique_target = False
def get_extra_restriction(self, alias, related_alias):
return ColConstraint(alias, "lang", get_language())
def get_extra_descriptor_filter(self, instance):
return {"lang": get_language()}
def contribute_to_class(self, cls, name):
super().contribute_to_class(cls, name)
setattr(cls, self.name, ArticleTranslationDescriptor(self))
class ActiveTranslationFieldWithQ(ActiveTranslationField):
def get_extra_descriptor_filter(self, instance):
return models.Q(lang=get_language())
class Article(models.Model):
active_translation = ActiveTranslationField(
"ArticleTranslation",
from_fields=["id"],
to_fields=["article"],
related_name="+",
on_delete=models.CASCADE,
null=True,
)
active_translation_q = ActiveTranslationFieldWithQ(
"ArticleTranslation",
from_fields=["id"],
to_fields=["article"],
related_name="+",
on_delete=models.CASCADE,
null=True,
)
pub_date = models.DateField()
def __str__(self):
try:
return self.active_translation.title
except ArticleTranslation.DoesNotExist:
return "[No translation found]"
class NewsArticle(Article):
pass
class ArticleTranslation(models.Model):
article = models.ForeignKey(Article, models.CASCADE)
lang = models.CharField(max_length=2)
title = models.CharField(max_length=100)
body = models.TextField()
abstract = models.TextField(null=True)
class Meta:
unique_together = ("article", "lang")
class ArticleTag(models.Model):
article = models.ForeignKey(
Article,
models.CASCADE,
related_name="tags",
related_query_name="tag",
)
name = models.CharField(max_length=255)
class ArticleIdea(models.Model):
articles = models.ManyToManyField(
Article,
related_name="ideas",
related_query_name="idea_things",
)
name = models.CharField(max_length=255)