Страницы

Поиск по вопросам

Показаны сообщения с ярлыком django-orm. Показать все сообщения
Показаны сообщения с ярлыком django-orm. Показать все сообщения

воскресенье, 8 марта 2020 г.

TypeError: __init__() takes 2 positional arguments but 3 were given в Django

#python #django #django_orm


Есть вот такая система моделей

class NormalTag(models.Model):
    caption = models.CharField(max_length=1024, unique=True,
                                blank=False, default=None)
    def __init__(self, caption):
        super().__init__()
        self.caption = caption

    def __str__(self):
        return self.caption

class Tag(models.Model):
    caption = models.CharField(max_length=1024)

    def __init__(self, caption):
        super().__init__()
        self.caption = caption
        self.set_normaltag()

    def normalize(self):
        return self.caption.lower().replace(" ",'').replace("\"",'')

    def set_normaltag(self):
        try:
            normaltag = self.get_normaltag()
        except NormalTag.DoesNotExist:
            normaltag = NormalTag(self.normalize())
            normaltag.save()

    def get_normaltag(self):
        return NormalTag.objects.get(caption=self.normalize())

    def __str__(self):
        return self.caption


При вызове из шелла выдает ошибку:

[env]user ~/path/to/project > python manage.py shell
Python 3.5.2 (default, Jul  5 2016, 12:43:10) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from home.models import NormalTag, Tag
>>> t = Tag("ПроВеРка ТэГа")
Traceback (most recent call last):
  File "", line 1, in 
  File "/home/path/to/project/home/models.py", line 28, in __init__
    self.set_normaltag()
  File "/home/path/to/project/home/models.py", line 35, in set_normaltag
    normaltag = self.get_normaltag()
  File "/home/path/to/project/home/models.py", line 41, in get_normaltag
    return NormalTag.objects.get(caption=self.normalize())
  File "/home/path/to/env/lib/python3.5/site-packages/django/db/models/manager.py",
line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/home/path/to/env/lib/python3.5/site-packages/django/db/models/query.py",
line 379, in get
    num = len(clone)
  File "/home/path/to/env/lib/python3.5/site-packages/django/db/models/query.py",
line 238, in __len__
    self._fetch_all()
  File "/home/path/to/env/lib/python3.5/site-packages/django/db/models/query.py",
line 1087, in _fetch_all
    self._result_cache = list(self.iterator())
  File "/home/path/to/env/lib/python3.5/site-packages/django/db/models/query.py",
line 66, in __iter__
    obj = model_cls.from_db(db, init_list, row[model_fields_start:model_fields_end])
  File "/home/path/to/env/lib/python3.5/site-packages/django/db/models/base.py",
line 565, in from_db
    new = cls(*values)
TypeError: __init__() takes 2 positional arguments but 3 were given


Так и не понял, откуда она берется.
    


Ответы

Ответ 1



В джанге много чего происходит магическим образом. То есть во фреймворке не всё соотвествует питону, хотя и написано на нём. В данном случае вы передали позиционный аргумент в модель, а при создании моделей нужно передавать только именованные аргументы. В вашем случае нужно было написать: t = Tag(caption="ПроВеРка ТэГа") И да, в моделях переопределять метод __init__ надо с осторожностью, если нужно добавить какие-то дополнительные действия во время создания модели, то лучше использовать метод менеджера модели create(), он создан специально для этого.

Ответ 2



У моделей есть перегруженный метод create() для создания объектов. Не стоит пользоваться конструктором. https://docs.djangoproject.com/en/1.10/ref/models/instances/ - пример сразу тут.

вторник, 25 февраля 2020 г.

Отфильтровать по диапазону дат из связаной таблицы

#python #django #django_orm


Задача:

Есть 2 таблицы: Марка автомобиля и Модель автомобиля

class Manufacturer(models.Model):
    title = models.CharField(_("Full name"), max_length=255, blank=True)

class CarModel(models.Model):
    manufacturer = models.ForeignKey(Manufacturer, on_delete=models.PROTECT, related_name="models_car")
    production_start = models.DateField(null=True, blank=True)
    production_end = models.DateField(null=True, blank=True)


Для каждой модели авто есть год начала и окончания выпуска (конец не для всех есть).

От пользователя приходит год.

Необходимо вернуть марки автомобилей для которых есть хотя бы одна модель с годом
выпуска, полученным от пользователя.



Т.е. по сути необходима функция которая на вход получает число, а на выходе отдает
QuerySet из Manufacturer.



Пример:

Manufacturer:
    id    title
    ===========
    1     Audi
    2     BMW

Model:
    mfa_id     start      end
    =========================
    1          1932       1960
    1          1980       2001
    2          1977       2014
    2          2004       ----


От пользователя приходит год = 1954.

Нужно вернуть только Audi, тк у BMW нет модели 1954 года выпуска.
    


Ответы

Ответ 1



.Здравствуйте, почитайте про вложенные запросы , думаю все станет понятно. Кроме того с одного запроса можно обратиться к двум таблицам сразу.

Ответ 2



Сделал так: def get_mfa(year): year = date(int(year), 1, 1) cm = CarModel.objects.filter(Q(production_end__gte=d) | Q(production_end=None), production_start__lte=d) return Manufacturer.objects.filter(models_car__in=cm).distinct()

среда, 10 июля 2019 г.

ContentTypes. Обобщённые связи? Реализация отношений моделей

Предположим есть <Человек>. У него может быть только один(один_к_одному) транспорт. Транспортом может быть <Автомобиль>, <Самолёт>, <Лошадь>, то есть эти три класса совершенно разные.
Как реализовать модели? Смотрю в сторону ContentTypes. Читаю доку но не всё понятно пока, и поэтому я не совсем уверен в выборе направления.
Если contenttypes всё-таки правильный выбор, то можно пример для толчка, на основе задачи выше?


Ответ

ContentTypes позволяют действительно ссылаться на экземпляры разных моделей. Если вы хотите решить вашу задачу через них, то вы должны создать поля как описано в документации
from django.db import models from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType
class Car(models.Model): pass
class Plane(models.Model): pass
class Horse(models.Model): pass
class Human(models.Model): content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) object_id = models.PositiveIntegerField() transport = GenericForeignKey('content_type', 'object_id')
Ну и в дальнейшем можно присваивать экземплярам модели Human в качестве transport экземпляры любых моделей, зарегистрированных в django.
Но я бы на вашем месте обошёлся без них. Можно создать класс транспорт, а от него отнаследовать автомобиль, самолёт, лошадь:
from django.db import models
class Transport(models.Model): pass
class Car(Transport): pass
class Plane(Transport): pass
class Horse(Transport): pass
class Human(models.Model): transport = models.ForeignKey(Transport)
UPD:
Для примера доработаем наши модели следующим образом:
class Transport(models.Model): max_speed = models.IntegerField('Максимальная скорость') capacity = models.IntegerField('Вместимость')
class Car(Transport): doors = models.IntegerField('Количество дверей')
class Plane(Transport): wing_size = models.IntegerField('Размах крыла')
class Horse(Transport): date_birth = models.DateTimeField('Дата рождения')
class Human(models.Model): transport = models.OneToOneField(Transport)
То есть теперь у нас есть различные атрибуты в разных моделях. Все их перечислять не буду, они хорошо читаются в коде. Нужно лишь отметить, что у нас теперь есть общая модель Transport со специфическими для всех транспортных средств полями и наследуемые от неё типы транспорта, которые определяют свои атрибуты.
Как этим пользоваться? Давайте рассмотрим всё на примерах
>>> # Создадим по одному экземпляру каждой модели - авто, самолёта и лошади >>> Car.objects.create(doors=5, max_speed=130, capacity=5) >>> Plane.objects.create(wing_size=30, max_speed=1100, capacity=80) >>> import datetime >>> Horse.objects.create(date_birth=datetime.datetime.now() - datetime.timedelta(days=365), max_speed=10, capacity=1) >>> # теперь создадим 3 челокека, к которым сразу же привяжем транспорт >>> Human.objects.create(transport=Car.objects.first()) >>> Human.objects.create(transport=Plane.objects.first()) >>> Human.objects.create(transport=Horse.objects.first()) >>> # Выбрать все объекты транспорта можно через класс Transport >>> Transport.objects.all().values() [{'max_speed': 130, 'capacity': 5, u'id': 1}, {'max_speed': 1100, 'capacity': 80, u'id': 2}, {'max_speed': 10, 'capacity': 1, u'id': 3}] >>> # теперь рассмотрим как нам в модели человека получить его транспорт >>> human = Human.objects.first() >>> human.transport >>> # через Transport можно также получить и модели, которые наследуются от данного транспорта т.е. лошадь, самолёт или авто. Делается это через доступ к одноимённым атрибутам в экземпляре модели. Проверить какого типа данный транспорт можно воспользовавшись проверкой на hasattr по каждому наследуемому классу >>> hasattr(human.transport, 'car') True >>> hasattr(human.transport, 'car'), hasattr(human.transport, 'horse'), hasattr(human.transport, 'plane') (True, False, False) >>> # получить объект Car >>> human.transport.car >>> # выбрать всех владельцев авто >>> Human.objects.filter(transport__car__isnull=False) [] >>> # получить владельца авто >>> car = Car.objects.first() >>> car.human

понедельник, 8 июля 2019 г.

Django генерация фильра модели

Есть фильтр по полям модели:
queryset = queryset.filter( Q(title__icontains=search_text) | Q(description__icontains=search_text) | Q(name_icontains=search_text) )
Подскажите, как сделать, чтобы блок
Q(title__icontains=search_text) | Q(description__icontains=search_text)| Q(name_icontains=search_text)
Генерировался в зависимости от обстоятельств?
Например, в одном случае нужно, чтобы фильтр был такой:
Q(description__icontains=search_text) | Q(name_icontains=search_text)
В другом такой:
Q(title__icontains=search_text) | Q(description__icontains=search_text) |
Или даже такой:
Q(title__icontains=search_text)
Объекты Q я бы мог сгенерировать при помощи словаря, Например:
search_text = 'somthing text' fields_name = ['title', 'description', 'name']
queries = [ Q(**{field+'__icontains': search_text}) for field in fields_name]
Но как потом это:
[, , ]
Через OR засунуть в filter - не могу никак разобраться. Прошу помощи.


Ответ

query = Q() for q in queries: query |= q
или
import operator query = reduce(operator.or_, queries)

вторник, 28 мая 2019 г.

TypeError: __init__() takes 2 positional arguments but 3 were given в Django

Есть вот такая система моделей
class NormalTag(models.Model): caption = models.CharField(max_length=1024, unique=True, blank=False, default=None) def __init__(self, caption): super().__init__() self.caption = caption
def __str__(self): return self.caption
class Tag(models.Model): caption = models.CharField(max_length=1024)
def __init__(self, caption): super().__init__() self.caption = caption self.set_normaltag()
def normalize(self): return self.caption.lower().replace(" ",'').replace("\"",'')
def set_normaltag(self): try: normaltag = self.get_normaltag() except NormalTag.DoesNotExist: normaltag = NormalTag(self.normalize()) normaltag.save()
def get_normaltag(self): return NormalTag.objects.get(caption=self.normalize())
def __str__(self): return self.caption
При вызове из шелла выдает ошибку:
[env]user ~/path/to/project > python manage.py shell Python 3.5.2 (default, Jul 5 2016, 12:43:10) [GCC 5.4.0 20160609] on linux Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) >>> from home.models import NormalTag, Tag >>> t = Tag("ПроВеРка ТэГа") Traceback (most recent call last): File "", line 1, in File "/home/path/to/project/home/models.py", line 28, in __init__ self.set_normaltag() File "/home/path/to/project/home/models.py", line 35, in set_normaltag normaltag = self.get_normaltag() File "/home/path/to/project/home/models.py", line 41, in get_normaltag return NormalTag.objects.get(caption=self.normalize()) File "/home/path/to/env/lib/python3.5/site-packages/django/db/models/manager.py", line 85, in manager_method return getattr(self.get_queryset(), name)(*args, **kwargs) File "/home/path/to/env/lib/python3.5/site-packages/django/db/models/query.py", line 379, in get num = len(clone) File "/home/path/to/env/lib/python3.5/site-packages/django/db/models/query.py", line 238, in __len__ self._fetch_all() File "/home/path/to/env/lib/python3.5/site-packages/django/db/models/query.py", line 1087, in _fetch_all self._result_cache = list(self.iterator()) File "/home/path/to/env/lib/python3.5/site-packages/django/db/models/query.py", line 66, in __iter__ obj = model_cls.from_db(db, init_list, row[model_fields_start:model_fields_end]) File "/home/path/to/env/lib/python3.5/site-packages/django/db/models/base.py", line 565, in from_db new = cls(*values) TypeError: __init__() takes 2 positional arguments but 3 were given
Так и не понял, откуда она берется.


Ответ

В джанге много чего происходит магическим образом. То есть во фреймворке не всё соотвествует питону, хотя и написано на нём.
В данном случае вы передали позиционный аргумент в модель, а при создании моделей нужно передавать только именованные аргументы.
В вашем случае нужно было написать:
t = Tag(caption="ПроВеРка ТэГа")
И да, в моделях переопределять метод __init__ надо с осторожностью, если нужно добавить какие-то дополнительные действия во время создания модели, то лучше использовать метод менеджера модели create(), он создан специально для этого.

воскресенье, 12 мая 2019 г.

Отфильтровать по диапазону дат из связаной таблицы

Задача:
Есть 2 таблицы: Марка автомобиля и Модель автомобиля
class Manufacturer(models.Model): title = models.CharField(_("Full name"), max_length=255, blank=True)
class CarModel(models.Model): manufacturer = models.ForeignKey(Manufacturer, on_delete=models.PROTECT, related_name="models_car") production_start = models.DateField(null=True, blank=True) production_end = models.DateField(null=True, blank=True)
Для каждой модели авто есть год начала и окончания выпуска (конец не для всех есть).
От пользователя приходит год.
Необходимо вернуть марки автомобилей для которых есть хотя бы одна модель с годом выпуска, полученным от пользователя.

Т.е. по сути необходима функция которая на вход получает число, а на выходе отдает QuerySet из Manufacturer.

Пример:
Manufacturer: id title =========== 1 Audi 2 BMW
Model: mfa_id start end ========================= 1 1932 1960 1 1980 2001 2 1977 2014 2 2004 ----
От пользователя приходит год = 1954
Нужно вернуть только Audi, тк у BMW нет модели 1954 года выпуска.


Ответ

Сделал так:
def get_mfa(year): year = date(int(year), 1, 1) cm = CarModel.objects.filter(Q(production_end__gte=d) | Q(production_end=None), production_start__lte=d)
return Manufacturer.objects.filter(models_car__in=cm).distinct()