basic working search

This commit is contained in:
Christoph J. Scherr 2023-06-03 14:40:57 +02:00
parent d6ab46f44d
commit 201e6e1654
Signed by: PlexSheep
GPG Key ID: 25B4ACF7D88186CC
15 changed files with 159 additions and 185 deletions

View File

@ -12,3 +12,5 @@ class BlogPostAdmin(admin.ModelAdmin):
"""
The admin model for BlogPost
"""
list_display = ["title_en", "subtitle_en", "title_de", "subtitle_de", "date", "category", "suburl"]
date_hierarchy = "date"

View File

@ -1,31 +1,12 @@
# Generated by Django 3.2.19 on 2023-05-31 20:54
# Generated by Django 3.2.19 on 2023-06-03 12:03
from django.db import migrations, models
from django.db import migrations
class Migration(migrations.Migration):
initial = True
dependencies = [
('start', '0002_auto_20230531_2254'),
]
operations = [
migrations.CreateModel(
name='BlogPost',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=50)),
('subtitle', models.CharField(max_length=50)),
('desc', models.CharField(max_length=250, unique=True)),
('body', models.TextField()),
('date', models.DateField(blank=True)),
('slug', models.SlugField()),
('keywords', models.ManyToManyField(to='start.Keyword')),
],
options={
'abstract': False,
},
),
]

View File

@ -1,36 +0,0 @@
# Generated by Django 3.2.19 on 2023-06-02 10:00
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('start', '0002_auto_20230531_2254'),
('blog', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Category',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=50)),
('subtitle', models.CharField(max_length=50)),
('desc', models.CharField(max_length=250, unique=True)),
('date', models.DateField(blank=True)),
('name', models.CharField(max_length=50)),
('slug', models.SlugField()),
('keywords', models.ManyToManyField(to='start.Keyword')),
],
options={
'abstract': False,
},
),
migrations.AddField(
model_name='blogpost',
name='category',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='blog.category'),
),
]

View File

@ -0,0 +1,35 @@
# Generated by Django 3.2.19 on 2023-06-03 12:03
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('start', '0002_keyword_searchable_staticsite'),
('blog', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Category',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=50)),
('slug', models.SlugField()),
],
),
migrations.CreateModel(
name='BlogPost',
fields=[
('searchable_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='start.searchable')),
('body', models.TextField()),
('thumbnail', models.ImageField(blank=True, upload_to='')),
('category', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='blog.category')),
],
bases=('start.searchable',),
),
]

View File

@ -1,38 +0,0 @@
# Generated by Django 3.2.19 on 2023-06-02 22:09
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('blog', '0002_auto_20230602_1200'),
]
operations = [
migrations.RemoveField(
model_name='category',
name='date',
),
migrations.RemoveField(
model_name='category',
name='desc',
),
migrations.RemoveField(
model_name='category',
name='keywords',
),
migrations.RemoveField(
model_name='category',
name='subtitle',
),
migrations.RemoveField(
model_name='category',
name='title',
),
migrations.AddField(
model_name='blogpost',
name='thumbnail',
field=models.ImageField(blank=True, upload_to=''),
),
]

View File

@ -1,6 +1,6 @@
from django.db import models
from start.models import AbstractSearchable
from start.models import Searchable
class Category(models.Model):
"""
@ -9,15 +9,10 @@ class Category(models.Model):
name = models.CharField(max_length=50)
slug = models.SlugField()
class BlogPost(AbstractSearchable):
class BlogPost(Searchable):
"""
Should contain a blogpost
"""
title = models.CharField(max_length=50)
subtitle = models.CharField(max_length=50)
desc = models.CharField(max_length=250, unique=True)
body = models.TextField()
date = models.DateField(blank=True)
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)
thumbnail = models.ImageField(blank=True)
slug = models.SlugField()

View File

@ -1,3 +1,18 @@
from django.contrib import admin
from django.db.models import CASCADE, AutoField, OneToOneField
from django.views.generic import View
from .models import *
# Register your models here.
@admin.register(Keyword)
class KeywordAdmin(admin.ModelAdmin):
"""
Admin Interface for Keyword
"""
list_display = ["text_en", "text_de"]
@admin.register(StaticSite)
class StaticSiteAdmin(admin.ModelAdmin):
"""
Admin Interface for StaticSite
"""
list_display = ["title_en", "subtitle_en", "title_de", "subtitle_de", "suburl"]

View File

@ -1,25 +1,12 @@
# Generated by Django 3.2.19 on 2023-05-30 17:08
# Generated by Django 3.2.19 on 2023-06-03 12:03
from django.db import migrations, models
from django.db import migrations
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='MainSearchEntry',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=50)),
('subtitle', models.CharField(max_length=50)),
('desc', models.CharField(max_length=250, unique=True)),
('date', models.DateField(blank=True)),
('link', models.URLField()),
],
),
]

View File

@ -1,37 +0,0 @@
# Generated by Django 3.2.19 on 2023-05-31 20:54
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('start', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Keyword',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('text', models.CharField(max_length=40)),
],
),
migrations.CreateModel(
name='StaticSite',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=50)),
('subtitle', models.CharField(max_length=50)),
('desc', models.CharField(max_length=250, unique=True)),
('date', models.DateField(blank=True)),
('keywords', models.ManyToManyField(to='start.Keyword')),
],
options={
'abstract': False,
},
),
migrations.DeleteModel(
name='MainSearchEntry',
),
]

View File

@ -0,0 +1,46 @@
# Generated by Django 3.2.19 on 2023-06-03 12:03
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('start', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Keyword',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('text_de', models.CharField(max_length=40)),
('text_en', models.CharField(max_length=40)),
],
),
migrations.CreateModel(
name='Searchable',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title_de', models.CharField(default='Titel DE', max_length=50)),
('title_en', models.CharField(default='title en', max_length=50)),
('subtitle_de', models.CharField(blank=True, max_length=50)),
('subtitle_en', models.CharField(blank=True, max_length=50)),
('desc_de', models.CharField(default='Beschreibung DE', max_length=250, unique=True)),
('desc_en', models.CharField(default='Description EN', max_length=250, unique=True)),
('date', models.DateField(blank=True, null=True)),
('suburl', models.CharField(blank=True, max_length=200, null=True)),
('keywords', models.ManyToManyField(to='start.Keyword')),
],
),
migrations.CreateModel(
name='StaticSite',
fields=[
('searchable_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='start.searchable')),
],
bases=('start.searchable',),
),
]

View File

@ -8,25 +8,26 @@ class Keyword(models.Model):
"""
this is the model that should contain searchable keywords
"""
text = models.CharField(max_length=40)
text_de = models.CharField(max_length=40)
text_en = models.CharField(max_length=40)
class AbstractSearchable(models.Model):
class Searchable(models.Model):
"""
Abstract class for any model that should be searchable.
This model will be searched for by the searchbox that is in every upper part of the website.
"""
title = models.CharField(max_length=50)
subtitle = models.CharField(max_length=50)
desc = models.CharField(max_length=250, unique=True)
# may be empty/blank for some entries
date = models.DateField(blank=True)
keywords = models.ManyToManyField(Keyword)
class Meta:
This class is not a real abstract class, I need to query it in the main search, so thats impossible
"""
AbstractSearchable is an abstract model
"""
abstract = True
title_de = models.CharField(max_length=50, default="Titel DE")
title_en = models.CharField(max_length=50, default="title en")
subtitle_de = models.CharField(max_length=50, blank=True)
subtitle_en = models.CharField(max_length=50, blank=True)
desc_de = models.CharField(max_length=250, unique=True, default="Beschreibung DE")
desc_en = models.CharField(max_length=250, unique=True, default="Description EN")
# may be empty/blank for some entries
date = models.DateField(blank=True, null=True)
keywords = models.ManyToManyField(Keyword)
suburl = models.CharField(max_length=200, blank=True, null=True)
@classmethod
def regenerate_all_entries(cls):
@ -35,7 +36,7 @@ class AbstractSearchable(models.Model):
"""
raise NotImplementedError
class StaticSite(AbstractSearchable):
class StaticSite(Searchable):
"""
This model represents any static site, such as start:index,
that should show up in search.

View File

@ -1,4 +1,4 @@
{% extends 'start/base.html' %}
{% extends 'base.html' %}
{% load i18n %}
{% get_current_language as LANGUAGE_CODE %}
{% block languagecode %}{{ LANGUAGE_CODE }}{% endblock languagecode %}
@ -8,4 +8,8 @@
<h1>{% translate "Bad request" %}</h1>
<p>{% translate "You fucked up" %}</p>
</div>
<div class="container text-center jumbotron my-5" py-5>
<h1 class="my-4">{% translate "Looking for anything specific?" %}</h1>
{% include 'main_search_form.html' %}
</div>
{% endblock main %}

View File

@ -5,13 +5,22 @@
{% block title %}{% translate "cscherr.de" %} - {% translate "startpage" %}{% endblock title %}
{% block main %}
<div class="container-xxl">
<div class="jumbotron text-center">
<h1>{% translate "Search for:" %} {{ searchstr }}</h1>
</div>
<div class="row text-center">
<div class="col">
I don't know what to put here
<div class="jumbotron text-center">
<h1>{% translate "Search for:" %} {{ request.GET }}</h1>
</div>
<div class="row">
{% for result in object_list %}
<div class="card m-2">
<div class="card-header">
{{ result.title_de }}
</div>
<div class="card-body">
<h5 class="card-title">{{ result.subtitle_de }}</h5>
<p class="card-text">{{result.desc_de}}</p>
<a href="/{{ LANGUAGE_CODE }}{{ result.suburl }}" class="btn btn-primary">Go somewhere</a>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
{% endblock main %}

View File

@ -1,4 +1,5 @@
from http.client import HTTPResponse
from typing import List
from django.shortcuts import redirect
from django.utils import translation
from django.views.generic.base import View
@ -10,9 +11,11 @@ from django.views import View
from django.template import Template, context, loader
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.views.generic.list import QuerySet
from django.db.models import Q
from .forms import MainSearchForm
from .models import AbstractSearchable
from .models import Searchable
from abc import ABC
@ -71,16 +74,22 @@ class MainSearch(ListView):
Search for anything.
"""
model = AbstractSearchable
model = Searchable
object_list = [] # this is only declaration, the view breaks without it.
template_name: str = "start/search.html"
def get_queryset(self) -> QuerySet:
search = self.request.GET.get("search")
object_list = Searchable.objects.filter(
Q(title_de__icontains=search) | Q(title_en__icontains=search) |
Q(subtitle_de__icontains=search) | Q(subtitle_en__icontains=search) |
Q(desc_de__icontains=search) | Q(desc_en__icontains=search)
)
print(object_list)
return object_list
def get(self, request, *args, **kwargs):
form = MainSearchForm(request.GET)
if not form.is_valid():
return render(request, "errors/bad_request.html")
context = self.get_context_data(**kwargs)
context["searchstr"] = form.cleaned_data['search']
#object_list = self.model.objects.filter("something")
return render(request=request, template_name=self.template_name, context=context)
return super().get(request, *args, **kwargs)

View File

@ -3,3 +3,4 @@ psycopg2>=2.8
mysqlclient>=1.4.3
django_compressor>=2.2
django-libsass>=0.7
pillow>=9.0.0