Evgenii Legotckoi
Evgenii LegotckoiНаурыз 31, 2023, 6:32 Т.Ж.

Django - Lesson 063. Көптілді қолдауы бар бірнеше үлгілерді толық мәтінді сайттан іздеу

Ақырында, мен сайттағы сұраныстарды оңтайландыруды ескере отырып, бірнеше модельдер бойынша жеткілікті жылдам толық мәтінді іздеуді жүзеге асыра алдым, бұл маған сәйкес келетін және жобаның сапасына қойылатын талаптарыма жауап береді.

Егер сіз қазір сайтты іздеуді пайдалансаңыз, іздеу өте жылдам жұмыс істейтінін және бірнеше іздеу топтарын қайтаратынын көресіз: Мақалалар, Түсініктемелер, Форум тақырыптары, Форумға жауаптар, Тесттер.
Барлық іздеу топтарынан үш нәтиже таңдалады және әрбір топта табылған нәтижелердің жалпы саны үшін есептегіш болады және қалған нәтижелерді бөлек қойындыларда көру ұсынылады.

Нәтижесінде, мен мұндай бөлуді жасадым, өйткені барлық нәтижелермен бір тізім жасау ресурстар тұрғысынан өте қымбат және жеткілікті тиімді емес.

Сонымен, соңғы нәтиже келесідей көрінеді:

Кейіннен бұл тәсіл іздеу жүйесін икемді және оңай өзгертуге мүмкіндік береді, бұл сайттың басқа бөліктеріне қарамастан іздеуге кез келген мазмұнды қосуға мүмкіндік береді.

Ал енді мен мұны қалай жасағанымды нақты айтып беремін.

PostgreSQL жүйесінде толық мәтінді іздеу

PostgreSQL дерекқоры толық мәтінді іздеуді қолдайды, ал Django ORM оны жүзеге асыруға мүмкіндік береді.

Толық мәтінді іздеуді іске қосудың ең оңай жолы - Django құжаттамасында сипатталғандай үлгі өрісінде іздеу әдісін пайдалану.

Мысалы, осылай

Entry.objects.filter(text__search='Cheese')

Бұл жағдайда Енгізу үлгісінде кірістірілген іздеу функциясының көмегімен толық мәтінді іздеу шақырылатын мәтіндік өріс бар.

Толық мәтінді іздеуді орындаудың жетілдірілген жолы - SearchVector іздеу векторларын бірнеше өрістер бойынша пайдалану. Солай

from django.contrib.postgres.search import SearchVector

Entry.objects.annotate(search=SearchVector('text', 'tagline')).filter(search='Cheese')

Өкінішке орай, аннотация әдісін қолдану тиімсіз, себебі бұл әдіс кейде көп уақытты алады.
Өнімділікті жақсарту үшін Django құралдары PostgreSQL дерекқорымен индекстелген SearchVectorField арнайы өрісін пайдалануды ұсынады. Бұл сайтта іздеуді айтарлықтай жылдамдатуға мүмкіндік береді.

Үлгіге SearchVectorField және индекс қосу

Мысал ретінде мақала үлгісін пайдаланып SearchVectorField қосуды және индекстеуді көрсетемін.

from django.contrib.postgres.indexes import GinIndex
from django.contrib.postgres.search import SearchVectorField

class Article(models.Model):
    title = models.CharField('Title', max_length=200)
    content = models.TextField(verbose_name='Content', blank=True)

    # SearchVectorField for full-text search
    search_vector = SearchVectorField(null=True)

    class Meta:
        indexes = [GinIndex(fields=["search_vector",]),]

Көріп отырғаныңыздай, ұсынылған кодта Search_vector өрісі бар, ол мақала үлгісінің Meta сыныбында GinIndex спецификациясы арқылы индекстеледі.

SearchVectorField және осы өрісті индекстеуді қосқаннан кейін жаңа тасымалдауларды жасаңыз

python manage.py makemigrations

Жалпы, жаңа көші-қон осылай болады

# Generated by Django 3.2 on 2023-03-27 21:03

import django.contrib.postgres.indexes
import django.contrib.postgres.search
from django.db import migrations


class Migration(migrations.Migration):

    dependencies = [
        # depends on 
    ]

    operations = [
        migrations.AddField(
            model_name='article',
            name='search_vector',
            field=django.contrib.postgres.search.SearchVectorField(null=True),
        ),
        migrations.AddIndex(
            model_name='article',
            index=django.contrib.postgres.indexes.GinIndex(fields=['search_vector'], name='knowledge_a_search__682520_gin'),
        ),
    ]

Бірақ бұл жеткіліксіз болады, өйткені әлі де SearchVectorField өрісін толтыру қажет, оны тасымалдау кезінде де жасауға болады. Сондықтан тасымалдауды келесідей өзгертеміз

# Generated by Django 3.2 on 2023-03-27 21:03

import django.contrib.postgres.indexes
import django.contrib.postgres.search
from django.db import migrations


def compute_search_vector(apps, schema_editor):
    Article = apps.get_model("knowledge", "Article")
    Article.objects.update(search_vector=django.contrib.postgres.search.SearchVector("title", "content"))


class Migration(migrations.Migration):

    dependencies = [
        # depends on 
    ]

    operations = [
        migrations.AddField(
            model_name='article',
            name='search_vector',
            field=django.contrib.postgres.search.SearchVectorField(null=True),
        ),
        migrations.AddIndex(
            model_name='article',
            index=django.contrib.postgres.indexes.GinIndex(fields=['search_vector'], name='knowledge_a_search__682520_gin'),
        ),
        migrations.RunPython(
            compute_search_vector, reverse_code=migrations.RunPython.noop
        ),
    ]

Бұл код SearchVectorField файлын дереу толтыру үшін орындалатын питон кодын қосатын қосымша қадамды, атап айтқанда compute_search_vector функциясын іске қосатын migrations.RunPython соңғы қадамын қосады.
SearchVectorField маңызды мүмкіндігі бар, оны SearchVector ішіне тікелей қосу мүмкін емес, бірақ оны үлгі менеджерінің жаңарту әдісі арқылы толтыруға болады. Сондықтан код осылай көрінеді

Article.objects.update(search_vector=django.contrib.postgres.search.SearchVector("title", "content"))

Содан кейін тасымалдауды іске қосыңыз

python manage.py migrate

Енді барлық мақалаларда индекстелген іздеу өрісі бар. Бірақ іс жүзінде бұл іздеу жүйесінің толыққанды жұмысы үшін жеткіліксіз, өйткені іздеу өрісі жаңа нысанды жасау жағдайында да, ескісін өңдеу жағдайында да толтырылуы керек. Ол үшін Django құжаттамасы PostgreSQL құжаттамасымен кеңесуді және триггерлерді жасауды ұсынады. Бұл жақсы және дұрыс, бірақ қандай да бір себептермен PostgreSQL-ге қайтадан кіріп, барлық қажетті триггерлерді қолмен жасағыңыз келмесе ше. Сонда қалай болу керек? Бұл жағдайда Джангоның сигнал/слот жүйесі бізді құтқарады.

Ол үшін мақала үлгісіне келесі кодты қосыңыз

    def update_search_vector(self):
        qs = Article.objects.filter(pk=self.pk)
        qs.update(search_vector=SearchVector("title", "content"))

Содан кейін post_save сигналына қосылыңыз.

from django.db.models.signals import post_save
from django.dispatch import receiver

@receiver(post_save, sender=Article)
def post_save_artcile(sender, instance, created, update_fields, **kwargs):
    instance.update_search_vector()

Осылайша, мақала нысаны сақталған сайын іздеу өрісі жаңартылып отырады.

Мазмұнның барлық түрлерін іздеуге арналған SearchView сыныбы

Ал енді мазмұнның бірнеше түрін іздеуге және қажетті нәтижені беруге мүмкіндік беретін SearchView жазамыз. Біздің жағдайда, біздің сайтта мақалалар («Мақалалар») және пікірлер («Пікірлер») бар делік.

class SearchView(View):
    template_name = 'search/index.html'

    def get(self, request, *args, **kwargs):
        query = request.GET.get('search', None)
            article_results = Article.objects.filter(search_vector=query)
            comment_results = Comment.objects.filter(search_vector=query)

        return render(
            request=request,
            template_name=self.template_name,
            context={
                'search': query or '',
                'article_results': article_results[:3],
                'article_results_count': article_results.count(),
                'comment_results': comment_results[:3],
                'comment_results_count': comment_results.count(),
            }
        )

get параметрі search іздеу фразасына жауап беретін сайт жолында берілетінін ескеріңіз. Сондай-ақ, дерекқор сұрауларын оңтайландыру үшін бірнеше түзетулер бар.

Django жалқау дерекқор сұрауларын пайдаланатындықтан, сұраулар дәл қажет болғанда орындалады. Осылайша сызық

article_results = Article.objects.filter(search_vector=query)

деректер базасына жалпы сұранысты ғана қояды, бірақ оны орындамайды, өйткені бастапқы іздеу беті үшін бізге табылған материалдардың жалпы саны және барлық табылған материалдардан тек алғашқы үш нысан қажет.
Сондықтан, көрсету контексті ретінде тек екі QuerySets беріледі.

    'article_results': article_results[:3],
    'article_results_count': article_results.count(),

article_results[:3] табылған жазбаларда шектеу әрекетін орындайды және тек үш нысанды қайтарады
article_results.count() барлық табылған жазбаларды санайды. Шын мәнінде, мұндай қосымша код сұрауларды орындауға кететін уақытты айтарлықтай қысқартуы мүмкін, бұл сайтта іздеуді айтарлықтай жылдамдатады.

Бейнелеу беті

Әрі қарай бет көрсетіледі. Мен өз бетімнің толық кодын бермеймін, бірақ оның қалай көрінетінін жалпы түрде көрсетемін

Бізде base.html жалпы үлгісінен мұраланған негізгі іздеу беті бар (Бұл үлгіні қарастырудың мағынасы жоқ).
Бірақ теңшелетін теголарға келетін болсақ, бұл жерде біз сәл ұзағырақ тоқтаймыз. Мұнда олардың бірнешеуі бар:

  • append_query_to_url - белгілі бір мазмұн үшін іздеу бетінің url мекенжайына сұрау параметрін қосуға арналған тег.
  • іздеу_өрісі - іздеу өрісін көрсетуге арналған тег
  • табылған_нысандар - мазмұн нәтижелерін шығаруға арналған тег
{% extends 'base.html' %}
{% block page %}
  {% load search %}
  {% url 'search:articles' as articles_search_url %}
  {% url 'search:comments' as comments_search_url %}

  {% append_query_to_url articles_search_url as articles_search_url_with_query %}
  {% append_query_to_url comments_search_url as comments_search_url_with_query %}

  {% search_field search %}

  {% block search_result %}
    {% found_objects article_results article_results_count 'Articles' 'Show all articles' articles_search_url_with_query  %}
    {% found_objects comment_results comment_results_count 'Comments' 'Show all comments' comments_search_url_with_query  %}
  {% endblock %}
{% endblock %}

"Үлгілер" каталогы

Кейбір мақалаларда, мысалы, Blocktranslate тегі сияқты қойындылар блогының шаблон тегін қалай жазу керек бөлімінде мен бұл каталогтың құрылымын және нені сипаттадым. үлгі тегтерін тіркеу үшін сол жерде болуы керек, сондықтан мен оған қайта тоқталмаймын.

Сонымен, templatetags/search.py файлының мазмұнын қарастырайық

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

from django import template
from django.template.defaultfilters import urlencode

register = template.Library()

@register.inclusion_tag('search/search_field.html', takes_context=True)
def search_field(context, value, **kwargs):
    context.update({'query_value': value})
    return context


@register.simple_tag(takes_context=True)
def append_query_to_url(context, url):
    return '{}?search={}'.format(url, urlencode(context.get('search', '')))

@register.inclusion_tag('search/found_objects.html', takes_context=True)
def found_objects(context, results, results_count, objects_title, all_search_message, search_url):
    context.update({
        'results': results,
        'results_count': results_count,
        'objects_title': objects_title,
        'all_search_message': all_search_message,
        'search_url': search_url
    })
    return context

Каталог "үлгілер/іздеу"

Әрі қарай, қосу тег үлгілері дегеніміз не екенін қарастырайық

"search/found_objects.html" файлы

Жалпы алғанда, іздеудегі бірнеше нысандар үшін үлгіні көрсету төмендегідей болады.
Көріп отырғаныңыздай, bootstrap-тен белгілеу мұнда пайдаланылады, сонымен қатар нысанның өзін көрсетудің мысалы жоқ. Егер сіз осы мақаланы оқып жатсаңыз, сізге қажет нәрсені өзіңіз жаза алатыныңызға сенімдімін, өйткені бұл мақала менің тәжірибемнің сипаттамасы болып табылады, бірақ ақылсыз көшіруге тікелей нұсқаулық емес.

{% load i18n %}
<div class="card box-shadow m-2">
  <div class="card-header">{{ objects_title }} <span class="badge badge-primary">{{ results_count }}</span>
  </div>
    {% if results|length > 0 %}
      {% for object in results %}
        {# You custom render of object #}
      {% endfor %}
      <div class="card-footer border-0"><a href="{{ search_url }}" class="btn btn-sm btn-outline-secondary">{{ all_search_message }}</a></div>
    {% else %}
      <div class="card-body">
        {% trans 'Nothing found' %}
      </div>
    {% endif %}
</div>

"search/search_field.html" файлы

<form method="get" class="my-3 px-3">
  <div class="input-group bmd-form-group pt-0">
  {% load i18n %}
    <input class="form-control" name="search" placeholder="{% trans 'Search' %}" value="{{ query_value }}" title="" type="text">
    <div class="input-group-append">
      <button type="submit" class="btn btn-outline-secondary mdi mdi-magnify mdi-0"></button>
    </div>
  </div>
</form>

"urls.py" файлы

Содан кейін Django маршрутизаторына SearchView қосыңыз.

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

from django.urls import path

from search import views

app_name = 'search'
urlpatterns = [
    path('', views.SearchView.as_view(), name='index'),
]

Django толық мәтінді іздеу бетінің параметрі осылай болады, кез келген жағдайда негізгі іздеу беті осылай көрінеді. Бірақ мен жеке мазмұн бөліктері үшін іздеу беттерін де қостым, бұл да маңызды. Негізгі іздеу бетінде пайдаланушы оның сұрауы бойынша сайттан кем дегенде бірдеңе табуға болатын-болмайтынын көре алады, ал егжей-тегжейлі беттерде пайдаланушы сайтта табылған барлық жазбаларды көре алады.

"SearchViewByContent" сыныбы

Ал енді мазмұнның әртүрлі түрлерінде іздеуге арналған жалпылама класс жазайық. Ол үшін Жалпы класын ListView пайдалануға болады. Іздеу іздеу векторының өрісі бойынша жүргізіледі. Сондай-ақ, дұрыс беттеу үшін бізге беттеу URL мекенжайы қажет. Мұның бәрі осы кодта бар.

class SearchViewByContent(ListView):
    template_name = 'search/search_objects.html'
    paginate_by = 10

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context.update({
            'search': self.request.GET.get('search', None) or '',
            'last_question': self.get_pagination_url()
        })
        return context

    def get_pagination_url(self):
        return self.request.get_full_path().replace(self.request.path, '')

    def get_queryset(self):
        qs = super().get_queryset()
        query = self.request.GET.get('search', None)
        return qs.filter(search_vector=query)

Бетті көрсету

Бұрыннан бар үлгінің кодын қолданып, оның әрекетін кеңейтейік. Көріп отырғаныңыздай, бұл жерде django bootstrap 4 батарея үлгісінің тегі қолданылады. Алдыңғы мақалалардың бірінде мен батареяның ескі нұсқасын қалай қосу керектігін сипаттадым. Содан бері ештеңе өзгерген жоқ және мақала django bootstrap 5 соңғы нұсқасына да қатысты.

{% extends 'search/index.html' %}
{% block search_result %}
  <div id="object-list">
  {% load bootstrap_pagination from bootstrap4 %}
  {% for object in object_list %}
    {# Render your object here #}
  {% empty %}
    <div class="card card-body mb-3">{{ not_found_message|default:_("Nothing found") }}</div>
  {% endfor %}
  {% if object_list %}
    <div class="mt-3">{% bootstrap_pagination object_list pages_to_show="3" url=last_question justify_content='center' %}</div>
  {% endif %}
  </div>
{% endblock %}

"urls.py" файлына маршруттарды қосыңыз

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

from django.urls import path

from search import views
from articles.models import Article, Comment

app_name = 'earch'
urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),
    path('articles/', views.SearchView.as_view(queryset=Article.objects.all()), name='articles'),
    path('comments/', views.SearchView.as_view(queryset=Comment.objects.all()), name='comments'),
]

Осылайша, сайттағы мазмұнның белгілі бір түрлерін іздеу жүзеге асырылатын болады.

Модельді аудару батареясы арқылы көп тілді қолдау

Django modeltranslation - үлгілеріңізге көптілділікті қосатын тамаша бума, бірақ өкінішке орай ол SearchVectorField өрісімен үйлесімді емес. Мұны істеу үшін сайтта қолдау көрсетілетін әрбір тіл үшін жаңа SearchVectorField өрістерін қолмен қосу керек. Бірақ бұл шынымен де көп жұмыс емес. Және ол осылай көрінуі мүмкін

Үлгі

class Article(models.Model):

    # Another code

    # Search vectors
    search_vector = SearchVectorField(null=True)
    search_vector_ru = SearchVectorField(null=True)
    search_vector_en = SearchVectorField(null=True)

    objects = ArticleManager()

    class Meta:
        ordering = ['-pub_date']
        verbose_name = _('Article')
        verbose_name_plural = _('Articles')
        indexes = [
            GinIndex(fields=[
                "search_vector", "search_vector_ru", "search_vector_en",
            ]),
        ]

Тиісінше, жаңа көшіруді әрбір жаңа өріс SearchVectorField үшін түзету қажет болады.

Іздеу көрінісі

Ал SearchView іздеуді келесідей түзетуге болады

class IndexView(View):
    template_name = 'evileg_search/index.html'

    def get(self, request, *args, **kwargs):
        query = request.GET.get('search', None)
        current_language = get_language()
        article_results = Article.objects.filter(
            Q(**{'search_vector_{}'.format(current_language): query}) |
            Q(search_vector=query)
        )
        comment_results = Comment.objects.filter(search_vector=query)

        return render(
            request=request,
            template_name=self.template_name,
            context={
                'search': query or '',
                'article_results': article_results[:3],
                'article_results_count': article_results.count(),
                'comment_results': comment_results[:3],
                'comment_results_count': comment_results.count(),
            }
        )

Бұл мақалалар үшін бөлек «Көру» үшін де қолданылады. Оны өзіңіз бөлек жазып көріңіз және сұрауды осы Көріністегідей өзгертіңіз.

Бұл жерде де маңызды жайт бар. Мен вектор бойынша тілмен де, тілсіз де іздеймін. Бұл менде белгілі бір мақаланың барлық тілдеріне аудармалары болмауы мүмкін екеніне байланысты және менің ойымша, аударма болмаса да, іздеу нәтижелері әрқашан қайтарылуы керек.

Қорытынды

Осылайша сіз мазмұнның әртүрлі түрлерін қарапайым іздеуді жасай аласыз, ол бәрінен бұрын сайттағы мазмұнның басқа түрлерімен іздеуді болашақта кеңейту үшін айтарлықтай өзгертілетін және қолдау көрсетілетін болады.

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Ол саған ұнайды ма? Әлеуметтік желілерде бөлісіңіз!

NSProject
  • Сәуір 6, 2023, 12:25 Т.Қ.

Замечательная статья где давольно подробно расписан поиск. Когда то я искал что то именно вот такое. И на самом деле вариантов использования очень и очень много.
Спасибо Евгений за статью.

Lissa
  • Сәуір 19, 2023, 11:02 Т.Ж.

Заметила, что в русском варианте сложно со stemming поиска. Добавила во view SearchQuery c config, стало отлавиливать (кот - котЫ). Буду признательная за инфу, как этого добиться другим способом.

Evgenii Legotckoi
  • Сәуір 19, 2023, 2:35 Т.Қ.

Пока не подскажу, не вставало такой задачи. Для меня Django/Python - это хобби, а не профессиональная область

Lissa
  • Сәуір 19, 2023, 3:47 Т.Қ.

В любом случае спасибо за ориентацию. Для моего сайта подойдёт такая логика.

Lissa
  • Сәуір 24, 2023, 5:34 Т.Ж.
  • (өңделген)

К своему удивлению обнаружила, что украинский язык не включён в postgres-e в full text search. Есть какие-то кустарные варианты с прикручиванием файлов с stopwords и т.д.Я наверное сделаю "наивный" поиск, если выбран украинский.
А вы сталкивались с этой проблемой? Спасибо.

Evgenii Legotckoi
  • Сәуір 24, 2023, 5:43 Т.Ж.

А в чём это выражается? У меня поиск срабатывает по все подключённым языкам, в том числе и по украинскому.

Lissa
  • Сәуір 24, 2023, 7:08 Т.Ж.
  • (өңделген)

stackoverflow
Я сделала триггеры для update полей и вектора:

# Generated by Django 4.1 on 2023-04-23 20:45

import django.contrib.postgres.search
from django.contrib.postgres.search import SearchVector
from django.db import migrations


def compute_search_vector_uk(apps, schema_editor):
    Post = apps.get_model("posts", "Post")
    vector = SearchVector("title_uk", weight="A", config="ukrainian") + SearchVector(
        "content_uk",
        weight="B",
        config="ukrainian"

    )
    Post.objects.update(vector_uk=vector)


class Migration(migrations.Migration):

    dependencies = [
        ("posts", "0005_post_vector"),
    ]

    operations = [
        migrations.AddField(
            model_name="post",
            name="vector_uk",
            field=django.contrib.postgres.search.SearchVectorField(
                blank=True, null=True
            ),
        ),
        migrations.RunSQL(
            sql="""
            CREATE TRIGGER vector_uk_trigger
            BEFORE INSERT OR UPDATE OF title_uk, content_uk, vector_uk
            ON posts_post
            FOR EACH ROW EXECUTE PROCEDURE
            tsvector_update_trigger(
                vector_uk, 'pg_catalog.ukrainian', title_uk, content_uk
            );
            UPDATE posts_post SET vector_uk = NULL;
            """,
            reverse_sql="""
            DROP TRIGGER IF EXISTS vector_uk_trigger
            ON posts_post;
            """,
        ),
        migrations.RunPython(
            compute_search_vector_uk, reverse_code=migrations.RunPython.noop
        ),
    ]

Ошибка выпадает на pg_catalog.ukrainian, жалуется, что нет такого.
p.s Сделала менеджер модели, к фильрует поле на украинском (без конфигураций, иначе тоже жалуется).

Lissa
  • Сәуір 28, 2023, 5:01 Т.Қ.
  • (өңделген)

Может быть пригодится тем, кто использует django-ckeditor-5 for admin + modeltranslation package. Поле для редактирования in models.py нужно прописывать как обычное текстовое. А вот в админ классе обозначать

formfield_overrides = {
        models.TextField: {"widget": CKEditor5Widget},
    }

Пікірлер

Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
Кіріңіз немесе Тіркеліңіз
OI
  • Ora Iro
  • Жел. 24, 2024, 5:38 Т.Қ.

C++ - Тест 001. Первая программа и типы данных

  • Нәтиже:40ұпай,
  • Бағалау ұпайлары-8
AD

C++ - Тест 004. Указатели, Массивы и Циклы

  • Нәтиже:50ұпай,
  • Бағалау ұпайлары-4
m
  • molni99
  • Қаз. 26, 2024, 11:37 Т.Ж.

C++ - Тест 004. Указатели, Массивы и Циклы

  • Нәтиже:80ұпай,
  • Бағалау ұпайлары4
Соңғы пікірлер
ИМ
Игорь МаксимовҚар. 22, 2024, 10:51 Т.Қ.
Django - Оқулық 017. Теңшелген Django кіру беті Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Evgenii Legotckoi
Evgenii LegotckoiҚар. 1, 2024, 12:37 Т.Ж.
Django - Сабақ 064. Python Markdown кеңейтімін қалай жазуға болады Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZEҚаз. 19, 2024, 6:19 Т.Қ.
Qt Creator көмегімен fb3 файл оқу құралы Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь МаксимовҚаз. 5, 2024, 5:51 Т.Қ.
Django - Сабақ 064. Python Markdown кеңейтімін қалай жазуға болады Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas5Шілде 5, 2024, 9:02 Т.Қ.
QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Енді форумда талқылаңыз
Evgenii Legotckoi
Evgenii LegotckoiМаусым 25, 2024, 1:11 Т.Ж.
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
t
tonypeachey1Қар. 15, 2024, 5:04 Т.Қ.
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
NSProject
NSProjectМаусым 4, 2022, 1:49 Т.Қ.
Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
9
9AnonimҚаз. 25, 2024, 7:10 Т.Қ.
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

Бізді әлеуметтік желілерде бақылаңыз