Evgenii Legotckoi
Evgenii LegotckoiApril 8, 2017, 7:52 a.m.

Django - Tutorial 022. Adding a bookmark system (favorites) to the site

The site has the ability to mark articles, comments, topics and answers on the forum as favorites. However, marking as favorites does not provide a reload of the page, because for these actions the mechanism of AJAX-requests is used.

In order to implement the bookmark system, you need:

  • Add a table that implements the Many-to-Many relationship between the user and the article or comment.
  • Add a view that will handle this request.
  • Add url to handle the request to add or exclude an object from the favorites.
  • Write the html-code, which will be responsible for displaying the counter added to the bookmark.
  • Add a javascript handler that will call the AJAX request.

On this site, the icon of the star from Bootstrap is used as a counter icon.


Many-to-Many table for bookmarks

We will be able to add bookmarks for articles and comments. To do this, let's make a general abstract mode l, from which we will be inherited for a specific type of content on the site. In the abstract model, we create a user field that will be the same for all bookmarks.

class BookmarkBase(models.Model):
    class Meta:
        abstract = True

    user = models.ForeignKey(User, verbose_name="User")

    def __str__(self):
        return self.user.username

Next we inherit from this model to create two separate data models for comments and articles.

Here we add the obj field, which will be responsible for the foreign key on the content table: Article or Comment . It is important that the field is called the same in both models. Then you can write one view for all the bookmarks tables.

class BookmarkArticle(BookmarkBase):
    class Meta:
        db_table = "bookmark_article"

    obj = models.ForeignKey(Article, verbose_name="Article")


class BookmarkComment(BookmarkBase):
    class Meta:
        db_table = "bookmark_comment"

    obj = models.ForeignKey(Comment, verbose_name="Comment")

views.py

To process a request to add to or remove from bookmarks, create a view that can work with any table of bookmarks that will satisfy the general view presented above.

# -*- coding: utf-8 -*-

import json

from django.contrib import auth
from django.http import HttpResponse
from django.views import View


class BookmarkView(View):
    # This variable will set the bookmark model to be processed
    model = None

    def post(self, request, pk):
        # We need a user
        user = auth.get_user(request)
        # Trying to get a bookmark from the table, or create a new one
        bookmark, created = self.model.objects.get_or_create(user=user, obj_id=pk)
        # If no new bookmark has been created,
        # Then we believe that the request was to delete the bookmark
        if not created:
            bookmark.delete()

        return HttpResponse(
            json.dumps({
                "result": created,
                "count": self.model.objects.filter(obj_id=pk).count()
            }),
            content_type="application/json"
        )

Note that this code uses a comparison of obj_id=pk , which means that we are trying to find an entry in the table of bookmarks for the object's id. Since in all models - this field is the same, the problems should not arise with a similar syntax.

urls.py

And now let's see how the url looks like to handle requests to add content to the bookmarks.

# -*- coding: utf-8 -*-

from django.conf.urls import url
from django.contrib.auth.decorators import login_required

from . import views
from .models import BookmarkArticle, BookmarkComment

app_name = 'ajax'
urlpatterns = [
    url(r'^article/(?P<pk>\d+)/bookmark/$',
        login_required(views.BookmarkView.as_view(model=BookmarkArticle)),
        name='article_bookmark'),
    url(r'^comment/(?P<pk>\d+)/bookmark/$',
        login_required(views.BookmarkView.as_view(model=BookmarkComment)),
        name='comment_bookmark'),
]

To execute this request, the user must be authorized, for which the decorator login_required is responsible.

The URL in this case determines which type of content is added to the bookmarks, also determines the pk, of this content, and the action to be taken. After all, in addition to adding to the bookmarks, you can add a system of likes, reposts, etc. By the same principle.

html

In my case, the html-code looks like this:

<div data-id="{{ like_obj.id }}" data-type="article" data-action="bookmark" title="Favorites">
    <span class="glyphicon glyphicon-star"></span>
    <span data-count="bookmark">{{ like_obj.get_bookmark_count }}</span>
</div>

There are several custom attributes:

  • data-id - Responsible for pk content, which can be added to the bookmarks.
  • data-type - Type of content, the same name appears in the url.
  • data-action - The action to be taken, in this case adding to the bookmarks
  • data-count - Counter that shows how many users have added content to bookmarks

As for the following code like_obj.get_bookmark_count , this is also a uniform method that is added to the content model, for example for articles it will look like this:

def get_bookmark_count(self):
    return self.bookmarkarticle_set.all().count()

javascript

AJAX requests for this function are created using the jQuery library.

When working with AJAX it is necessary to take into account several nuances:

  1. If you have a multilingual site that has a different url for the current language, it is better to make a separate api for AJAX, which will be independent of the language, otherwise you will need to consider the language in the url when creating the AJAX request. If you ignore the language, the AJAX-request will be redirected to the current url with the language taken into account, and the query will not work. That is, there should not be redirects.
  2. Django will not accept the AJAX request unless it is configured to use the CSRF token, which is used to combat fake cross-site requests. With each page request, Django mixes the CSRF token in the Cookies, from there it can be taken.

Configuring AJAX to use the CSRF token

The following code can be included in the script on every page of the site where you want to use AJAX. It will automatically configure AJAX to use the Token CSRF.

// Getting a cookie by name
function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}

// Setup AJAX
$(function () {
    $.ajaxSetup({
        headers: { "X-CSRFToken": getCookie("csrftoken") }
    });
});

Bookmark handlers and implementing of them

In the following code, an AJAX request is made to call adding or removing content from the bookmarks. In this case, the code will be universal for both articles and comments.

In the request url, you can see the following line "/api/" + type + "/" + pk + "/" + action + "/" , which means that the module for AJAX requests hangs on the prefix /api/ , that is to this Url it is connected in the main urls.py file of the project, then there is the content type, its primary key and the action to be performed. Since all this data is taken from the data attributes, the resulting url will look like this:

  • /api/article/112/bookmark/ - for articles
  • /api/comment/14/bookmark/ - for comments

In the handler of the successful result, you can add highlighting of the bookmark star for the current user, etc.

function to_bookmarks()
{
    var current = $(this);
    var type = current.data('type');
    var pk = current.data('id');
    var action = current.data('action');

    $.ajax({
        url : "/api/" + type + "/" + pk + "/" + action + "/",
        type : 'POST',
        data : { 'obj' : pk },

        success : function (json) {
            current.find("[data-count='" + action + "']").text(json.count);
        }
    });

    return false;
}

$(function() {
    $('[data-action="bookmark"]').click(to_bookmarks);
});

For Django I recommend VDS-server of Timeweb hoster .

We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.

Do you like it? Share on social networks!

ИМ
  • Feb. 3, 2018, 5:40 p.m.

Доброго времени суток Евгений. Не подскажете как сделать иконки (лайк-дизлайк) кликабельными?

ИМ
  • Dec. 1, 2018, 5:57 p.m.

Доброго времени суток Евгений. Не ясен метод:

def get_bookmark_count(self):
    return self.bookmarkarticle_set().all().count()

Не могли бы вы растолковать откуда моя модель статьи знает о этой функции?:

self.bookmarkarticle_set()

Когда применяю данный метод то выскакивает ошибка:

__call__() missing 1 required keyword-only argument: 'manager'

И второй вопрос каким образом можно подсвечивать закладку (допустим менять ее цвет когда она добавлена пользователем, ну как у вас на сайте)?

Добрый день, Игорь!

Вообще это стандартное поведение в моделях, если на данную модель какая-то иная модель имеет внешний ключ (ForeignKey)

В данном конкретном случае есть модель Article и BookmarkArticle , поскольку BookmarkArticle имеет внешний ключ на Article, то модель Article автоматически получает метод bookmarkarticle_set, который возвращает query set  всех закладок, которые имеют внешний ключ на конкретный объект статьи.

Здесь я по ходу допустил ошибку, напишите так

self.bookmarkarticle_set.all().count()

Для подсветки я использую фильтр в шаблоне, которые ищет пользователя в наборе

@register.filter
def user_in(objects, user):
    if user.is_authenticated:
        return objects.filter(user=user).exists()
    return False

а вот его применение

<span data-icon="favorite" class="mdi mdi-star mr-1 {% if obj.bookmarks.all|user_in:user %}text-success{% endif %}"></span>

self.bookmarkarticle_set.all().count()

Да, так все работает! Спасибо вам огромное.

Еще один вопрос:

Я подключил фильтр:

@register.filter
def user_in(objects, user):
    if user.is_authenticated:
        return objects.filter(user=user).exists()
    return False

в templatetags/movie_extras.py

в шаблоне:

{% load movie_extras %}
<span style="cursor: pointer" class="fa fa-bookmark-o fa-4x{% if movie.bookmarks.all|user_in:user %}fa-2x{% endif %}"></span>

При этом ошибка:

 File "/home/chunk/public/web-dev/testproj/movie/templatetags/movie_extras.py", line 8, in user_in
    return objects.filter(user=user).exists()
AttributeError: 'NoneType' object has no attribute 'filter'

что я делаю не так Евгений?







мне кажется, вы неправильно записали это

movie.bookmarks.all

Как у вас называется модель закладок для фильмов? BookmarkArticle? BookmarkMovie?

Я вам дал код из сайта, а здесь уже на десять раз всё переписано и выглядит иначе. У вас скорее всего как-то так должно быть.

movie.bookmarkmovie_set.all

Или что-то типо того

ИМ
  • Dec. 3, 2018, 1:10 p.m.

Все верно.

Я вам дал код из сайта, а здесь уже на десять раз всё переписано и выглядит иначе. У вас скорее всего как-то так должно быть.
self.bookmarkarticle_set.all().count()

Так все работает. Только у меня:

self.bookmarkmovie_set.all().count()

Фильтр к сожалению не работает.












так перепишите его так

{% if movie.bookmarkmovie_set.all|user_in:user %}fa-2x{% endif %}

Все работет Евгений. Спасибо вам.

ИМ
  • Dec. 5, 2018, 4:44 a.m.

Доброго времени суток Евгений. Можно поинтересоваться каким образом выводите закладки в профиле пользователя?

Добрый день, Игорь.

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

user.bookmarkmovie_set.all()



Спасибо Евгений, буду пробовать.

Ну с выводом кол-ва закладок пользователя разобрался успешно,  а вот с выводом содержимого закладок почему то не могу сообразить. Прошу помощи Евгений.

Покажите шаблон, где выводите закладки, но без контента

{% extends 'base/base.html' %}
{% block content %}
<div class="userprofile">
<div class="row">
    <div class="col-md-3">
		{% if user.avatar %}
			<img src="{{ user.avatar.url }}">
		{% else %}
			<img src="/static/img/noavatar.png">
		{% endif %}
	</div>
    <div class="col-md-9">
		{{ profile.username }}
		<ul class="nav nav-tabs" id="myTab" role="tablist">
  <li class="nav-item">
    <a class="nav-link active" id="home-tab" data-toggle="tab" href="#home" role="tab" aria-controls="home" aria-selected="true">Home</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" id="profile-tab" data-toggle="tab" href="#profile" role="tab" aria-controls="profile" aria-selected="false">Закладки {{ user.bookmarkmovie_set.all.count }}</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" id="contact-tab" data-toggle="tab" href="#contact" role="tab" aria-controls="contact" aria-selected="false">Contact</a>
  </li>
</ul>
<div class="tab-content" id="myTabContent">
  <div class="tab-pane fade show active" id="home" role="tabpanel" aria-labelledby="home-tab">...</div>
  <div class="tab-pane fade" id="profile" role="tabpanel" aria-labelledby="profile-tab">...</div>
  <div class="tab-pane fade" id="contact" role="tabpanel" aria-labelledby="contact-tab">...</div>
</div>
		<p></p>
	</div>
</div>
</div>
{% endblock %}
Evgenii Legotckoi
  • Dec. 5, 2018, 5:30 a.m.

хм.. для вывода тогда должно быть как-то так

{% for bookmark in user.bookmarkmovie_set.all %}
    {{ bookmark .movie.title }}
{% endfor %}

Думаю, что догадаетесь как вывести нужную информацию о фильме

bookmark.movie - означает, что вы берёте поле внешнего ключа на фильм, которое должно быть в закладке. полагаю, что онго должно называться movie

Ага цикл. Спасибо за разъяснение Евгений.

ab
  • Oct. 26, 2019, 2:02 a.m.

здраствуйте. У меня почему-то выходит так

ab
  • Oct. 26, 2019, 2:02 a.m.

здраствуйте. У меня почему-то выходит так

Evgenii Legotckoi
  • Oct. 26, 2019, 1:58 p.m.

url или не подключили, или подключили неправильно

progammist
  • April 29, 2020, 7:37 a.m.

Подскажите пожалуйста, что значит

#app_name = 'ajax'

в urls.py ??
Это надо новое приложение создать?

Evgenii Legotckoi
  • April 29, 2020, 7:46 a.m.

Да, для такого функционала лучше создать отдельное приложение. Причина предельно простая. Обычно, когда делают сайт на Django, то очень часто делают его мультиязычным. Поэтому всё, что касается ajax взаимодействия, лучше пускать мимо дистпечеризации urls с поддержкой мультиязычности. Такая проблема возникает вследствие того, что производится переадресация на url, который зависит от языка. Из-за переадресации неправильно работает js.

Тут два решения проблемы:

  1. Выковыривать язык из страницы, чтобы сформировать url и биться со следующими багами
  2. Пустить этот функционал в обход мультиязычности, что гораздо проще и с меньшим количеством последующих багов
progammist
  • April 29, 2020, 7:48 a.m.
  • (edited)

ок, понял, спасибо
А в новом приложении строку app_name = 'ajax' указывать в урл?

Evgenii Legotckoi
  • April 29, 2020, 7:51 a.m.

Да, нужно будет добавить файл urls, поскольку обычно при использование команды startapp это файл не создаётся, и потом в нём обязательно добавить app_name, можете присовить своё имя для него. app_name отвечает за контекс генерирования url

progammist
  • April 29, 2020, 8:01 a.m.
  • (edited)

подскажите еще пж, я правильно понимаю, что функцию:

def get_bookmark_count(self):
    return self.bookmarkarticle_set.all().count()

Нужно добавить в модель статьи?

И еще второй вопрос, вроде всё сделал, при клике на звездочку (кстати у меня она не отображется, просто пустое место, но при клике что-то срабатывает) ничего не происходит, в консоле: Not Found: /api/article//bookmark/

Evgenii Legotckoi
  • April 29, 2020, 8:06 a.m.
  1. Да
  2. У вас тут должен быть id статьи, то есть эта запись /api/article//bookmark/ должна выглядеть например так /api/article/666/bookmark/
    Так что ищите косяк где-то в js
progammist
  • April 29, 2020, 8:06 a.m.

Ок, а посмотреть добавленные закладки на каком урл можно будет после добавления?

Evgenii Legotckoi
  • April 29, 2020, 8:08 a.m.

на том, который сами наваяете, если на пользовательском фронтенде, а вообще добавляйте модель закладок в панель администрирования в файле admin.py, тогда сможете увидеть в админке, добавилось там что-нибудь или нет.

progammist
  • April 29, 2020, 1:34 p.m.

Не получилось у меня сделать с ajax, по всей видимости пробелма с получением ID поста. Попробовал без ajax, по сути таже ошбика(какие-то проблемы с id). Создал новый вопрос: https://evileg.com/ru/forum/topic/1329/ , не знаю как пофиксить.

progammist
  • April 30, 2020, 6:52 a.m.

Подскажите, а дейтсвие:

data-action - действие, которое нужно совершить, в данном случае добавление в закладки
data-action="bookmark"

В какой части кода описываем?

Evgenii Legotckoi
  • April 30, 2020, 7 a.m.
ction to_bookmarks()
{
    var current = $(this);
    var type = current.data('type');
    var pk = current.data('id');
    var action = current.data('action'); // ЗДЕСЬ

    $.ajax({
        url : "/api/" + type + "/" + pk + "/" + action + "/",
        type : 'POST',
        data : { 'obj' : pk },

        success : function (json) {
            current.find("[data-count='" + action + "']").text(json.count);
        }
    });

    return false;
}
progammist
  • April 30, 2020, 7:23 a.m.
  • (edited)

Вообщем решил сделать не по id, а по slug, что в итоге вышло:

urls.py

app_name = 'ajax'
urlpatterns = [ url('<slug:slug>/', login_required(views.BookmarkView.as_view(model=BookmarkArticle)), name='article_bookmark'),

в .js

function to_bookmarks()
{
    var current = $(this);
    var type = current.data('type');
    var pk = current.data('id');
    var action = current.data('action');

    $.ajax({
        url :   "/" + pk + "/" ,
        type : 'POST',
        data : { 'obj' : pk },

        success : function (json) {
            current.find("[data-count='" + action + "']").text(json.count);
        }
    });

    return false;
}

// Подключение обработчика
$(function() {
    $('[data-action="bookmark"]').click(to_bookmarks);
});

В шаблоне:

<div data-id="{{ post.slug }}" data-type="post" data-action="bookmark" title="Избранное">
    <span class="far fa-heart"></span>
    <span data-count="bookmark">{{ post.get_bookmark_count }}</span>
</div>

В итоге при клике на иконку в консоле получаю:

[30/Apr/2020 16:21:00] "POST /novayastatya/ HTTP/1.1" 200 7405

Счётчик при клике на иконку никак не обновляется 0 всегда, также в БД таблица bookmark_article пустая. Может быть с урлами что-то?

progammist
  • April 30, 2020, 7:29 a.m.
  • (edited)

Также попробовал нажать на иконку для неавторизованного пользователя, аналогично:

[30/Apr/2020 16:21:00] "POST /novayastatya/ HTTP/1.1" 200 7405

То есть @login_required не срабатывает

progammist
  • April 30, 2020, 7:17 p.m.
  • (edited)

Евгений, можете подсказать почему может быть так?

Evgenii Legotckoi
  • May 3, 2020, 5:22 p.m.

А вы js код где подключаете?

файл js с to_bookmarks можно загрузить в head теге, а вот этот код

$(function() {
    $('[data-action="bookmark"]').click(to_bookmarks);
});

должен вызываться в конце страницы, когда html загружен

progammist
  • May 3, 2020, 8:19 p.m.
  • (edited)

Загрузил в конце страницы - ситуация аналогичная. Клик нажимается, в консоле

 "POST /novayastatya/ HTTP/1.1" 200 7405

Но счетчик не обновляется и в базе нет записи. У меня подозрения, что не срабатаывает url.

urls.py

app_name = 'ajax'

urlpatterns = [
    url('/api/favourites/', login_required(views.BookmarkView.as_view(model=BookmarkArticle)),
        name='article_bookmark'),
]

Урл нигде не перподключал, создал новое app "ajax" в нём добавил urls.py и в него добавил код выше. Может быть надо где-то include url вставить?

И еще немного симптомов, если я убираю во views.py (ajax app) класс BookmarkView(View) , то ничего не меняется (никаких ошибок нет). Но в коносле POST запрос ("POST /novayastatya/ HTTP/1.1" 200 7405) при клике всё равно пишет. Получается урл не срабатывает или view, а может и с моделями что-то...

Evgenii Legotckoi
  • May 4, 2020, 2:54 a.m.

А вы эти urls вообще подключили в самом главном файле urls, который обычно находится рядом с файлом settings.py?

progammist
  • May 4, 2020, 3:05 a.m.

нет, а как?)

Evgenii Legotckoi
  • May 4, 2020, 3:25 a.m.

также, как подключили сами статьи в файле urls.py, который лежит рядом с settings.py. Статьи же у вас работают...

progammist
  • May 4, 2020, 3:36 a.m.
  • (edited)

я не понимаю, как нужно подкллючить url из ajax app. Сатьи у меня лежат в главном приложении

Статьи я подключил вот так:

path('<slug:slug>/', views.post_detail, name='post_detail')

А как подключить url'ы приложения ajax app ?

Evgenii Legotckoi
  • May 4, 2020, 3:47 a.m.
  • (edited)

боюсь, что вам это слабо поможет, но обычно url из других app подключают подобным образом

urlpatterns = [
    path('api/', include('ecore.urls')),
]

Постарайтесь разобраться с этим, а то у меня возникает ощущение, что вас за руку водить нужно. Поэтому я склоняюсь к тому, что вы рано начали решать свою задачу. Вам нужно поднабраться опыта с Django. Поэтому переключитесь на какие-нибудь другие задачи, а добавление в избранное реализуете позже.

progammist
  • May 7, 2020, 4:04 p.m.

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

Сейчас новый вопрос, как можно их вывывести?
Пытаюсь вывести в шаблоне:

{% for bookmark in user.bookmarkarticle_set.all %} 
{{ bookmark.post.title }} #модель статьи Post
{% endfor %}

Ничего не выводится. Вьюху не создавал, не имею понятия как. Подскажите как вывести закладки юзера?

Evgenii Legotckoi
  • May 8, 2020, 10:12 a.m.

Добрый день.
То, что вы добавили как статью, следовало добавить как вопрос на форуме. ЭТо не статья, вы описали, что сделали и спрашивайте, что делать дальше. Поэтому задайте именно вопрос на форуме, в противном случае я не могу пропустить ту статью, чтобы другие пользователи имели к ней доступ. Она не соответсвует наименованию статьи.

Но суть вашей проблемы в том случае заключается в том, что вы не забираете список постов в соответствии с пользователем.
Поскольку никак не передаёте информацию о пользователе во view

progammist
  • May 9, 2020, 12:19 p.m.

ок, немного промазал при создании)
создал вопрос к статье: https://evileg.com/ru/forum/topic/1345/

progammist
  • May 9, 2020, 12:27 p.m.
  • (edited)
> Но суть вашей проблемы в том случае заключается в том, что вы не забираете список постов в соответствии с пользователем.
Поскольку никак не передаёте информацию о пользователе во view

Вы можете показать пример как это сделать?

progammist
  • May 10, 2020, 9:01 a.m.

всё, разобрался

progammist
  • May 10, 2020, 9:23 a.m.

Оставлю для тех, у кого возникнет подобный вопрос. Посты выводим циклом:

{% for bookmark in user.bookmarkarticle_set.all %} 
{{ bookmark.obj.title }} 
{% endfor %}

Так как мы ссылаемся на обьект статьи в модели BookmarkArticle через переменную obj , то и доступ к статье получаем через неё:

{{ bookmark.obj.title }} 
progammist
  • May 13, 2020, 7:20 a.m.
  • (edited)

Как я могу вывести добавленные посты в обратном порядке? сейчас выводятся новодобавленные в конец. Пыатюсь добавить order_by('-created_on') :

views.py

    object_list =  User.bookmarkarticle_set.all().order_by('-created_on')

Ошибка:

Cannot resolve keyword 'created_on' into field.
Evgenii Legotckoi
  • May 13, 2020, 7:24 a.m.

Может так?

object_list =  User.bookmarkarticle_set.all().order_by('-obj__created_on')
progammist
  • May 13, 2020, 7:30 a.m.

да, спасибо)

Comments

Only authorized users can post comments.
Please, Log in or Sign up
AD

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:50points,
  • Rating points-4
m

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:80points,
  • Rating points4
m

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:20points,
  • Rating points-10
Last comments
i
innorwallNov. 12, 2024, 9:12 a.m.
Django - Tutorial 055. How to write auto populate field functionality Freckles because of several brand names retin a, atralin buy generic priligy
i
innorwallNov. 12, 2024, 5:23 a.m.
QML - Tutorial 035. Using enumerations in QML without C ++ priligy cvs 24 Together with antibiotics such as amphotericin B 10, griseofulvin 11 and streptomycin 12, chloramphenicol 9 is in the World Health Organisation s List of Essential Medici…
i
innorwallNov. 12, 2024, 2:50 a.m.
Qt/C++ - Lesson 052. Customization Qt Audio player in the style of AIMP It decreases stress, supports hormone balance, and regulates and increases blood flow to the reproductive organs buy priligy online safe Promising data were reported in a PDX model re…
i
innorwallNov. 12, 2024, 1:19 a.m.
Heap sorting algorithm The role of raloxifene in preventing breast cancer priligy precio
i
innorwallNov. 12, 2024, 12:55 a.m.
PyQt5 - Lesson 006. Work with QTableWidget buy priligy 60 mg 53 have been reported by Javanovic Santa et al
Now discuss on the forum
i
innorwallNov. 12, 2024, 7:56 a.m.
добавить qlineseries в функции buy priligy senior brother Chu He, whom he had known for many years
i
innorwallNov. 11, 2024, 9:55 p.m.
Всё ещё разбираюсь с кешем. priligy walgreens levitra dulcolax carbs The third ring was found to be made up of ultra relativistic electrons, which are also present in both the outer and inner rings
9
9AnonimOct. 25, 2024, 7:10 p.m.
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

Follow us in social networks