basic working search
This commit is contained in:
parent
d6ab46f44d
commit
201e6e1654
|
@ -12,3 +12,5 @@ class BlogPostAdmin(admin.ModelAdmin):
|
||||||
"""
|
"""
|
||||||
The admin model for BlogPost
|
The admin model for BlogPost
|
||||||
"""
|
"""
|
||||||
|
list_display = ["title_en", "subtitle_en", "title_de", "subtitle_de", "date", "category", "suburl"]
|
||||||
|
date_hierarchy = "date"
|
||||||
|
|
|
@ -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):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('start', '0002_auto_20230531_2254'),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
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,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
|
|
|
@ -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'),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -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',),
|
||||||
|
),
|
||||||
|
]
|
|
@ -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=''),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,6 +1,6 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
from start.models import AbstractSearchable
|
from start.models import Searchable
|
||||||
|
|
||||||
class Category(models.Model):
|
class Category(models.Model):
|
||||||
"""
|
"""
|
||||||
|
@ -9,15 +9,10 @@ class Category(models.Model):
|
||||||
name = models.CharField(max_length=50)
|
name = models.CharField(max_length=50)
|
||||||
slug = models.SlugField()
|
slug = models.SlugField()
|
||||||
|
|
||||||
class BlogPost(AbstractSearchable):
|
class BlogPost(Searchable):
|
||||||
"""
|
"""
|
||||||
Should contain a blogpost
|
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()
|
body = models.TextField()
|
||||||
date = models.DateField(blank=True)
|
|
||||||
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)
|
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)
|
||||||
thumbnail = models.ImageField(blank=True)
|
thumbnail = models.ImageField(blank=True)
|
||||||
slug = models.SlugField()
|
|
||||||
|
|
|
@ -1,3 +1,18 @@
|
||||||
from django.contrib import admin
|
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"]
|
||||||
|
|
|
@ -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):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
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()),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
|
|
|
@ -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',
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -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',),
|
||||||
|
),
|
||||||
|
]
|
|
@ -8,25 +8,26 @@ class Keyword(models.Model):
|
||||||
"""
|
"""
|
||||||
this is the model that should contain searchable keywords
|
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.
|
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.
|
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
|
title_de = models.CharField(max_length=50, default="Titel DE")
|
||||||
"""
|
title_en = models.CharField(max_length=50, default="title en")
|
||||||
abstract = True
|
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
|
@classmethod
|
||||||
def regenerate_all_entries(cls):
|
def regenerate_all_entries(cls):
|
||||||
|
@ -35,7 +36,7 @@ class AbstractSearchable(models.Model):
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
class StaticSite(AbstractSearchable):
|
class StaticSite(Searchable):
|
||||||
"""
|
"""
|
||||||
This model represents any static site, such as start:index,
|
This model represents any static site, such as start:index,
|
||||||
that should show up in search.
|
that should show up in search.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends 'start/base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% get_current_language as LANGUAGE_CODE %}
|
{% get_current_language as LANGUAGE_CODE %}
|
||||||
{% block languagecode %}{{ LANGUAGE_CODE }}{% endblock languagecode %}
|
{% block languagecode %}{{ LANGUAGE_CODE }}{% endblock languagecode %}
|
||||||
|
@ -8,4 +8,8 @@
|
||||||
<h1>{% translate "Bad request" %}</h1>
|
<h1>{% translate "Bad request" %}</h1>
|
||||||
<p>{% translate "You fucked up" %}</p>
|
<p>{% translate "You fucked up" %}</p>
|
||||||
</div>
|
</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 %}
|
{% endblock main %}
|
||||||
|
|
|
@ -6,12 +6,21 @@
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<div class="container-xxl">
|
<div class="container-xxl">
|
||||||
<div class="jumbotron text-center">
|
<div class="jumbotron text-center">
|
||||||
<h1>{% translate "Search for:" %} {{ searchstr }}</h1>
|
<h1>{% translate "Search for:" %} {{ request.GET }}</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="row text-center">
|
<div class="row">
|
||||||
<div class="col">
|
{% for result in object_list %}
|
||||||
I don't know what to put here
|
<div class="card m-2">
|
||||||
|
<div class="card-header">
|
||||||
|
{{ result.title_de }}
|
||||||
</div>
|
</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>
|
</div>
|
||||||
{% endblock main %}
|
{% endblock main %}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from http.client import HTTPResponse
|
from http.client import HTTPResponse
|
||||||
|
from typing import List
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.utils import translation
|
from django.utils import translation
|
||||||
from django.views.generic.base import View
|
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.template import Template, context, loader
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
|
from django.views.generic.list import QuerySet
|
||||||
|
from django.db.models import Q
|
||||||
|
|
||||||
from .forms import MainSearchForm
|
from .forms import MainSearchForm
|
||||||
from .models import AbstractSearchable
|
from .models import Searchable
|
||||||
|
|
||||||
from abc import ABC
|
from abc import ABC
|
||||||
|
|
||||||
|
@ -71,16 +74,22 @@ class MainSearch(ListView):
|
||||||
Search for anything.
|
Search for anything.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = AbstractSearchable
|
model = Searchable
|
||||||
object_list = [] # this is only declaration, the view breaks without it.
|
object_list = [] # this is only declaration, the view breaks without it.
|
||||||
template_name: str = "start/search.html"
|
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):
|
def get(self, request, *args, **kwargs):
|
||||||
form = MainSearchForm(request.GET)
|
form = MainSearchForm(request.GET)
|
||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
return render(request, "errors/bad_request.html")
|
return render(request, "errors/bad_request.html")
|
||||||
|
return super().get(request, *args, **kwargs)
|
||||||
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)
|
|
||||||
|
|
|
@ -3,3 +3,4 @@ psycopg2>=2.8
|
||||||
mysqlclient>=1.4.3
|
mysqlclient>=1.4.3
|
||||||
django_compressor>=2.2
|
django_compressor>=2.2
|
||||||
django-libsass>=0.7
|
django-libsass>=0.7
|
||||||
|
pillow>=9.0.0
|
||||||
|
|
Loading…
Reference in New Issue