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
|
||||
"""
|
||||
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):
|
||||
|
||||
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,
|
||||
},
|
||||
),
|
||||
]
|
||||
|
|
|
@ -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 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()
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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()),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
|
|
@ -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
|
||||
"""
|
||||
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.
|
||||
|
|
|
@ -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 %}
|
||||
|
|
|
@ -6,12 +6,21 @@
|
|||
{% block main %}
|
||||
<div class="container-xxl">
|
||||
<div class="jumbotron text-center">
|
||||
<h1>{% translate "Search for:" %} {{ searchstr }}</h1>
|
||||
<h1>{% translate "Search for:" %} {{ request.GET }}</h1>
|
||||
</div>
|
||||
<div class="row text-center">
|
||||
<div class="col">
|
||||
I don't know what to put here
|
||||
<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>
|
||||
{% endblock main %}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -3,3 +3,4 @@ psycopg2>=2.8
|
|||
mysqlclient>=1.4.3
|
||||
django_compressor>=2.2
|
||||
django-libsass>=0.7
|
||||
pillow>=9.0.0
|
||||
|
|
Loading…
Reference in New Issue