FieldDoesNotExist с OneToOne
Я хочу сделать галерею для пользователей на основе Photologue
приложение. Чтобы подключить профили пользователей к моделям фотолога, я хочу использовать OneToOne
, Также я хочу... скажем, "переопределить" фотолога get_absolute_url
, который используется шаблонами.
# models
from photologue.models import Gallery
from profiles.models import UserProfile
class GalleryExtended(models.Model):
gallery = models.OneToOneField(Gallery)
user = models.ForeignKey(UserProfile, verbose_name=_('user'), on_delete=models.CASCADE)
def get_absolute_url(self):
return reverse('profiles_user:profiles_gallery-details', args=[self.user.user_url, self.gallery.slug])
# views
from photologue.views import Gallery
from profiles.models import UserProfile
from .models import GalleryExtended, PhotoExtended
def get_user_gallery_queryset(self):
user = get_object_or_404(UserProfile, user_url=self.kwargs['user_url'])
gallery = Gallery.objects.filter(galleryextended__user=user)
return gallery
class ProfileGalleryDateView(object):
date_field = 'date_added'
allow_empty = True
get_queryset = get_user_gallery_queryset
# site.com/username/gallery (shows photos + images with a filter by year)
class ProfileGalleryPhotoArchiveIndexView(ProfileGalleryDateView, ArchiveIndexView):
template_name = 'galleries/gallery_n_photo_archive.html'
Так что, если я делаю
gallery = Gallery.objects.filter(galleryextended__user=user)
шаблоны начинают использовать Photologue's get_absolute_url
(Я не использую ядроphotologue
с URL url(r'^photologue/', include('photologue.urls', namespace='photologue')),
как я интегрирую приложение в моей собственной схеме URL)
Можно ли вернуться к чему-то так
gallery = GalleryExtended.objects.filter(user=user).***(get fields from Gallery)***
и избегать django.core.exceptions.FieldDoesNotExist: GalleryExtended has no field named 'date_added'
для того, чтобы начать использовать get_absolute_url
от GalleryExtended
?
Я знаю, это может быть легко решено путем расширения photologue
с помощью наследования, но я хочу знать, возможно ли использовать OneToOne? потому что в некоторых источниках, которые я читал, рекомендуется использовать 1to1 вместо наследования.
1 ответ
Итак, я думаю, что теперь я понимаю, что вы хотите сделать. И это неправильно, хакерство и зло во всех отношениях.
Во-первых, наследовать модель нечего бояться, на самом деле все наоборот. Суета, которую вы испытываете сейчас, является отличным примером того, что ждет вас, если вы решите не следовать одному из самых важных принципов ООП. Аргументы типа "я читаю что-то откуда-то" не могут меня преобразовать, и я настоятельно рекомендую использовать наследование вместо отношений 1to1. Не говоря уже о том, что использование отношения 1to1 вместо наследования также создает дополнительный запрос к БД каждый раз, когда вам нужно использовать объекты в одном и том же месте.
Несмотря на то, что я не рекомендую продолжать эту настройку, я могу дать вам несколько возможных вариантов достижения того, чего вы хотите. Он не идеален, потому что не предназначен для использования таким образом.
Если мы сейчас на одной странице, у вас есть такая структура:
class Model1(models.Model):
name = models.CharField(max_length=128)
state = models.CharField(max_length=128)
def some_method(self):
return self.name
class Model2(models.Model):
first = models.OneToOneField(Model1, related_name='second')
name = models.CharField(max_length=128)
def some_method(self):
return self.name + '2345678'
Вы хотите запросить все Model2
и позвоните Model1
"s some_method()
на них (исправить, если не так).
Это может быть достигнуто с помощью хакерского решения при замене self
спор с другой моделью, которая соответствует критериям.
Т.е.
all_method_values = []
for obj in Model2.objects.all():
all_method_values.append(Model1.some_method(obj))
Так как же написать это более питонически и при этом сохранить отношение 1 к 1? Измените рассматриваемый метод на статический метод с аргументом, и если вам нужно вызывать его как связанный метод любой модели, заставьте их вызывать один и тот же статический метод с соответствующими аргументами. Но код говорит более 1000 слов:
# In the model
def get_absolute_url(self):
return GalleryExtended.get_gallery_url(self.user.user_url, self.gallery.slug)
@staticmethod
def get_gallery_url(user_url, slug):
return reverse('profiles_user:profiles_gallery-details', args=[self.user.user_url, self.gallery.slug])
Теперь вместо показанного выше уродства вы можете звонить без уродливого взлома:
all_method_values = []
for obj in Model2.objects.all():
all_method_values.append(Model1.get_gallery_url(obj.user.user_url, obj.gallery.slug))
Для протокола, я все еще рекомендую наследование, но это тоже хорошо работает. Выполнение этого небольшого шага устраняет путаницу при смешении двух отдельных моделей, связанных методов, и позволяет выяснить, откуда поступают данные.