• Как сделать "компактную" пагинацию в django?

    winordie
    @winordie
    Лучшая документация -- исходники
    from django import template
    
    register = template.Library()
    
    
    @register.assignment_tag(takes_context=True)
    def page_range(context):
        c = 5
        if context['paginator'].num_pages < 2 * (c + 1):
            return list(range(1, context['paginator'].num_pages + 1))
        if context['page_obj'].number < c + 2:
            n = range(1, 12)
        elif context['page_obj'].number > context['paginator'].num_pages - (c + 1):
            n = range(context['paginator'].num_pages - 2 * c, context['paginator'].num_pages + 1)
        else:
            n = range(context['page_obj'].number - c, context['page_obj'].number + (c + 1))
        return list(n)

    <ul class="pager">
        {% if page_obj.has_previous %}
            <li class="previous"><a href="?page={{ page_obj.previous_page_number }}">{% trans "previous" %}</a></li>
        {% endif %}
        <li class="current">
            <ul class="pagination">
                {% page_range as page_range %}
                {% for page in page_range %}
                    {% if page == page_obj.number %}
                        <li class="active">
                            <a href="?page={{ page }}">
                                {{ page }} <span class="sr-only">(current)</span>
                            </a>
                        </li>
                    {% else %}
                        <li><a href="?page={{ page }}">
                            {{ page }}</a></li>
                    {% endif %}
                {% endfor %}
            </ul>
        </li>
        {% if page_obj.has_next %}
            <li class="next"><a href="?page={{ page_obj.next_page_number }}">{% trans "next" %}</a></li>
        {% endif %}
    </ul>
    Ответ написан
    1 комментарий
  • Как не повторять код функции upload_to?

    winordie
    @winordie
    Лучшая документация -- исходники
    def image(instance, filename, image_size_type):
      if image_size_type:
        size = '/{}'.format(image_size_type)
      else:
        size = ''
      return 'image/{0}{1}/{2}'.format(instance.am_id, size, filename)


    class MyImageField(ImageField):
      def __init__(self, image_size_type='', **kwargs):
        self.image_size_type = image_size_type
        super().__init__(**kwargs)
    
      def generate_filename(self, instance, filename):
        if callable(self.upload_to):
          directory_name, filename = os.path.split(self.upload_to(instance, filename, self.image_size_type))
          filename = self.storage.get_valid_name(filename)
          return os.path.normpath(os.path.join(directory_name, filename))
    
        return os.path.join(self.get_directory_name(), self.get_filename(filename))


    class Image(models.Model):
        image = MyImageField(upload_to=image, blank=True)
        image_xs = MyImageField(upload_to=image, blank=True, image_size_type='xs')
        image_sm = MyImageField(upload_to=image, blank=True, image_size_type='sm')
        image_md = MyImageField(upload_to=image, blank=True, image_size_type='md')
        am = models.ForeignKey(AnotherModel)
    Ответ написан
  • Django почему не работает url?

    winordie
    @winordie
    Лучшая документация -- исходники
    Подозреваю что с первой ссылкой все нормально, проблема с той ссылкой которая должна быть на странице с урлом /other/appliances/13/
    Ответ написан
  • Почему при сохранении formset появляется ошибка 'value must be an integer'?

    winordie
    @winordie
    Лучшая документация -- исходники
    Покажи шаблон
    Если формы вручную выводятся надо указывать form.id
    {{ formset_advance.management_form }}
      {% for form_advance in formset_advance %}
         {{ form_advance.id }}
         {{ form_advance.idpub_royalties_advances }}
         <tr class="ppradvtbl">
           <td>{{ form_advance.advance_num }}</td>
           <td>{{ form_advance.currency_amount }}</td>
           <td>{{ form_advance.home_currency_amount }}</td>
           <td><span class="datePicker">{{ form_advance.invoice_rec_date }}</span></td>
           <td>{{ form_advance.pay_question }}</td>
           <td>{{ form_advance.advance_note }}</td>
         </tr>
      {% endfor %}
    Ответ написан
  • Как запрограммировать кнопку в админке Django?

    winordie
    @winordie
    Лучшая документация -- исходники
    class MyModelAdmin(admin.ModelAdmin):
        def get_urls(self):
            urls = super().get_urls()
            shard_urls = [
                url(r'^get_shard/$', getShard),
                url(r'^refresh_shard/$', refreshShard),
            ]
            return shard_urls + urls
    Ответ написан
    Комментировать
  • Как запретить пользователю добавлять в фоловери более одного раза?

    winordie
    @winordie
    Лучшая документация -- исходники
    templatetags/follow_tags.py
    @register.simple_tag
    def in_follow(user, follower):
        return user.who_follows.filter(follower=follower).exists()

    urls.py
    url(r'^to_follow/(?P<user_id>\d+)/$', follow, name='add_to_follow'),

    template/user_page_blablabla.html
    {% load follow_tags %}
    ...
    {% if messages %}
        <ul class="messages">
            {% for message in messages %}
                <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
            {% endfor %}
        </ul>
    {% endif %}
    ...
    {% in_follow user current_user as user_in_follow %}
    {% if user_in_follow %}
      <span>{% trans "In follow" %}</span>
    {% else %}
      <a href="{% url "add_to_follow" user_id=current_user.id %}">Add to follow</a>
    {% endif %}

    views.py
    @login_required
    def follow(request,user_id):
        selected_user = User.objects.get(id=user_id)
        _, created = Followship.objects.get_or_create(following=request.user,
                                             follower=selected_user)
        if created:
            messages.success(request, 'ok')
        else:
            messages.error(request, 'User already following')
        return reverse('user_page_blablabla')

    models.py
    class Followship(models.Model):
        following = models.ForeignKey(User, related_name="who_follows")
        follower = models.ForeignKey(User, related_name="who_is_followed")
        class Meta:
            unique_together = ('following', 'follower')
    Ответ написан
    2 комментария
  • Как сохранить thumbnails при загрузке изображения?

    winordie
    @winordie
    Лучшая документация -- исходники
    И снова таки посмотрим код:
    def get_thumbnailer(obj, relative_name=None):
        if hasattr(obj, 'easy_thumbnails_thumbnailer'):
            return obj.easy_thumbnails_thumbnailer
        if isinstance(obj, Thumbnailer):
            return obj
        elif isinstance(obj, FieldFile):
            if not relative_name:
                relative_name = obj.name
            return ThumbnailerFieldFile(obj.instance, obj.field, relative_name)
    
        source_storage = None
    
        if isinstance(obj, six.string_types):
            relative_name = obj
            obj = None
    
        if not relative_name:
            raise ValueError(
                "If object is not a FieldFile or Thumbnailer instance, the "
                "relative name must be provided")
    
        if isinstance(obj, File):
            obj = obj.file
        if isinstance(obj, Storage) or obj == default_storage:
            source_storage = obj
            obj = None
    
        return Thumbnailer(
            file=obj, name=relative_name, source_storage=source_storage,
            remote_source=obj is not None)

    Попробуй так
    avatar = get_thumbnailer(avatar, relative_name=avatar.name)
    Ответ написан
  • Какой фильтр выборки последнего элемента предподчтительнее использовать?

    winordie
    @winordie
    Лучшая документация -- исходники
    Посмотрим что происходит в первом и втором случае
    def latest(self, field_name=None):
        return self._earliest_or_latest(field_name=field_name, direction="-")
    
    def _earliest_or_latest(self, field_name=None, direction="-"):
        ...
        obj = self._clone()
        obj.query.set_limits(high=1)
        obj.query.clear_ordering(force_empty=True)
        obj.query.add_ordering('%s%s' % (direction, order_by))
        return obj.get()


    def order_by(self, *field_names):
        ...
        obj = self._clone()
        obj.query.clear_ordering(force_empty=False)
        obj.query.add_ordering(*field_names)
        return obj
    
    def __getitem__(self, k):
        ...
        qs = self._clone()
        qs.query.set_limits(k, k + 1)
        return list(qs)[0]

    Т.е. в обоих случаях к query применяются методы set_limits, clear_ordering, add_ordering. Отличаются они лишь агрументом force_empty=False/True и полем по которому ты сортируешь (не понятно зачем ты сортируешь по user_link)
    Ответ написан
    Комментировать
  • Отзыв юзера, как сделать это правильно?

    winordie
    @winordie
    Лучшая документация -- исходники
    models.py
    class Creview(models.Model):
        ...
        def get_absolute_url(self):
            return reverse('course_review', kwargs={'pk': self.id})

    url.py
    ...
    url(r'^creview/(?P<pk>\d+)/$', DetailCourseReview.as_view(), name='course_review'),
    url(r'^creview/(?P<course_id>\d+)/create/$', login_required(CreateCourseReview.as_view()), name='create_course_review'),
    ...

    forms.py
    class CourseReviewForm(forms.ModelForm):
        class Meta:
            model = Creview
            fields = ['review']
    
        def __init__(self, user, course, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.instance.creview = course
            if user and user.is_authenticated():
                self.instance.userview = user

    views.py
    class DetailCourseReview(DetailView):
        model = Creview
    
    
    class CreateCourseReview(CreateView):
        model = Creview
        form_class = CourseReviewForm
        template_name = 'course_review.html'
    
        def dispatch(self, request, *args, **kwargs):
            course_id = kwargs.get('course_id')
            self.course = get_object_or_404(Course, pk=course_id)
    
            super().dispatch(request, *args, **kwargs)
    
        def get_form_kwargs(self):
            kwargs = super().get_form_kwargs()
    
            kwargs['user'] = self.request.user
            kwargs['course'] = self.course
    
            return kwargs

    course_review.html
    <form action="{% url "create_course_review" course_id=course.id %} method="post">
        {% csrf_token %}
        {{ form }}
        <input type="submit" value="{% trans "Send" %}">
    </form>
    Ответ написан
  • В чем отличие queryset от list?

    winordie
    @winordie
    Лучшая документация -- исходники
    Ясное дело по другому — ведь это же не список.
    Давай посмотрим как он работает:
    https://github.com/django/django/blob/master/djang...
    def __getitem__(self, k):
            if not isinstance(k, (slice,) + six.integer_types):
                raise TypeError
            assert ((not isinstance(k, slice) and (k >= 0)) or
                    (isinstance(k, slice) and (k.start is None or k.start >= 0) and
                     (k.stop is None or k.stop >= 0))), \
                "Negative indexing is not supported."
    
            if self._result_cache is not None:
                return self._result_cache[k]
    
            if isinstance(k, slice):
                qs = self._clone()
                if k.start is not None:
                    start = int(k.start)
                else:
                    start = None
                if k.stop is not None:
                    stop = int(k.stop)
                else:
                    stop = None
                qs.query.set_limits(start, stop)
                return list(qs)[::k.step] if k.step else qs
    
            qs = self._clone()
            qs.query.set_limits(k, k + 1)
            return list(qs)[0]

    По моему тут все предельно ясно:
    - передавать можно либо число, либо слайс
    - при этом число или начальное и конечное значения слайса должны быть не меньше нуля
    - если задан слайс — то делается копия текущего queryset'а и для объекта query копии устанавливаются low_mark и/или high_mark, которые в будующем превратятся в OFFSET и LIMIT запроса к бд.
    - далее возможно два варианта:
    * если шаг не задан — возвращается созданая копия queryset'а
    * если же шаг задан — то превращаем queryset в список и к нему уже применяем шаг

    При этом, если не был задан шаг, то ни одного запроса к бд выполнено не было.
    Ответ написан
    Комментировать
  • Как обуздать Django messages?

    winordie
    @winordie
    Лучшая документация -- исходники
    Давайте посмотрим как работает framework messages.

    https://github.com/django/django/blob/master/djang...
    def messages(request):
        return {
            'messages': get_messages(request),
            'DEFAULT_MESSAGE_LEVELS': DEFAULT_LEVELS,
        }
    ...
    def get_messages(request):
        if hasattr(request, '_messages'):
            return request._messages
        else:
            return []

    Так messages попадают на страницу. Т.е. они берутся из request._messages. Как же они туда попадают?

    https://github.com/django/django/blob/master/djang...
    class MessageMiddleware(MiddlewareMixin):
        def process_request(self, request):
            request._messages = default_storage(request)
    ...
    def default_storage(request):
        return import_string(settings.MESSAGE_STORAGE)(request)
    ...
    MESSAGE_STORAGE = 'django.contrib.messages.storage.fallback.FallbackStorage'

    Значит в request._messages у нас лежит FallbackStorage(request)

    Перейдем к нашему коду
    messages.error(request, 'Ваш диапазон дат занят для данного объекта.')

    Что тут происходит? Посмотрим:
    https://github.com/django/django/blob/master/djang...
    def error(request, message, extra_tags='', fail_silently=False):
        add_message(request, constants.ERROR, message, extra_tags=extra_tags,
                    fail_silently=fail_silently)
    ...
    def add_message(request, level, message, extra_tags='', fail_silently=False):
        if not isinstance(request, HttpRequest):
            raise TypeError("add_message() argument must be an HttpRequest object, "
                            "not '%s'." % request.__class__.__name__)
        if hasattr(request, '_messages'):
            return request._messages.add(level, message, extra_tags)  # *** THIS ***
        if not fail_silently:
            raise MessageFailure('You cannot add messages without installing '
                        'django.contrib.messages.middleware.MessageMiddleware')

    Ага, вызывается метод add знакомого нам объекта FallbackStorage.
    Ему передается в качестве параметров:
    - level = constants.ERROR = 40
    - message = 'Ваш диапазон дат занят для данного объекта.'
    - extra_tags = ''

    Посмотрим на этот метод
    https://github.com/django/django/blob/master/djang...
    def add(self, level, message, extra_tags=''):
            if not message:
                return
            level = int(level)
            if level < self.level:
                return
            # Add the message.
            self.added_new = True
            message = Message(level, message, extra_tags=extra_tags)
            self._queued_messages.append(message)
    ...
    def _get_level(self):
            if not hasattr(self, '_level'):
                self._level = getattr(settings, 'MESSAGE_LEVEL', constants.INFO)
            return self._level

    Из этого кода можно сделать вывод что сообщение попадает в очередь сообщений если его уровень более или равен тому который задан в settings.MESSAGE_LEVEL (по умолчанию = contants.INFO = 20)

    Таким образом чтобы добавлялись только наши сообщения необходимо:
    1) в settings.py установить
    # settings.py
    ...
    MY_SUPER_ERROR = 80
    MESSAGE_LEVEL = MY_SUPER_ERROR
    ...

    2) Во вью писать
    if not available_cars:
            carstoshow = None
            messages.add_message(request, settings.MY_SUPER_ERROR, 'Ваш диапазон дат занят для данного объекта.')
            return redirect('car_detail', pk=car_used_id)
    Ответ написан
    1 комментарий
  • Как вывести из модели связи с Foreign Key?

    winordie
    @winordie
    Лучшая документация -- исходники
    Snachala nado opredelit related_name dlya Vospitately.vospet_crushek
    class Vospitately(models.Model):
        fio = models.CharField(max_length=40)
        dolshnost = models.CharField(max_length=80, default='Должность..')
        image = models.ImageField()
        vospet_crushek = models.ForeignKey(Cruski', related_name='vospitately')
        def __str__(self):
            return self.fio

    Potom vo view mogno tak sdelat
    def kruzhki(request):
        q = Cruski.objects.all()
        return render(request,'krushki.html',{'kruzki':q})

    I nakonec v shablone pishem chto to po tipu takogo
    {% block kruzhki %}
    {% for krug in kruzki %}
    <p><b>{{ krug.name }}</b></p>
    {% for vospet in krug.vospitately.all %}
    <p> {{ vospet.fio }}</p>
    {% endfor %}
    <p>{{ krug.description }}</p>
    <p>{{ krug.price }}</p>
    {% endfor %}

    Vot i vse. Takim obrazom u nas vivoditsya krugki i vospitately kotorie v nis sostoyat.

    Kstati vam bi opredelitsya stoit kak pisat "кружки":
    - Cruski
    - vospet_crushek
    - kruzhki
    - kruzki
    - krushki.html
    Ответ написан
    3 комментария
  • Как вывести изображение в шаблон?

    winordie
    @winordie
    Лучшая документация -- исходники
    {% for im in image %}
      <img src="{{ im.imagearticle_image.url }}">
    {% endfor %}
    Ответ написан
    1 комментарий
  • Как в django перенаправить запрос на локальный html?

    winordie
    @winordie
    Лучшая документация -- исходники
    Django тут ни при чем, просто натрави nginx/apache на эту папку и дело с концом.
    Ответ написан
  • Как сделать выборку из нескольких таблиц с помощью Django ORM?

    winordie
    @winordie
    Лучшая документация -- исходники
    Person.objects.order_by(
      'id', '-transfer__data_transfer').distinct('id').values_list(
      'last_name', 'transfer__new_position__position_name', 'transfer__data_transfer')
    Ответ написан
    3 комментария
  • Как подгрузить данные из подвязки в django-admin?

    winordie
    @winordie
    Лучшая документация -- исходники
    Комментировать
  • Как в django сверстать письмо?

    winordie
    @winordie
    Лучшая документация -- исходники
    Посмотри синтаксис send_mail, вторым параметром идет plain_text
    def send_mail(subject, message, from_email, recipient_list,
                  fail_silently=False, auth_user=None, auth_password=None,
                  connection=None, html_message=None):


    context = {
      'order': order,
    }
    send_mail(
      'Thanks for order',
      'blablabla',
      email_from,
      [order.email],
      fail_silently=True,
      html_message=get_template('emails/confirmation.html').render(context)
    )
    Ответ написан
    1 комментарий
  • Как отправить сообщение в джанго админку?

    winordie
    @winordie
    Лучшая документация -- исходники
    Комментировать