mirror of
https://github.com/seanmorley15/AdventureLog.git
synced 2025-07-24 15:29:36 +02:00
chore: Add created_at field to Adventure and Collection models
This commit is contained in:
parent
040d5a755f
commit
704eb6f6de
6 changed files with 87 additions and 4 deletions
|
@ -0,0 +1,26 @@
|
||||||
|
# Generated by Django 5.0.6 on 2024-07-18 19:27
|
||||||
|
|
||||||
|
import django.utils.timezone
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('adventures', '0009_alter_adventure_image'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='adventure',
|
||||||
|
name='created_at',
|
||||||
|
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='collection',
|
||||||
|
name='created_at',
|
||||||
|
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
|
@ -35,6 +35,7 @@ class Adventure(models.Model):
|
||||||
longitude = models.DecimalField(max_digits=9, decimal_places=6, null=True, blank=True)
|
longitude = models.DecimalField(max_digits=9, decimal_places=6, null=True, blank=True)
|
||||||
latitude = models.DecimalField(max_digits=9, decimal_places=6, null=True, blank=True)
|
latitude = models.DecimalField(max_digits=9, decimal_places=6, null=True, blank=True)
|
||||||
collection = models.ForeignKey('Collection', on_delete=models.CASCADE, blank=True, null=True)
|
collection = models.ForeignKey('Collection', on_delete=models.CASCADE, blank=True, null=True)
|
||||||
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
if self.collection:
|
if self.collection:
|
||||||
|
@ -53,6 +54,7 @@ class Collection(models.Model):
|
||||||
name = models.CharField(max_length=200)
|
name = models.CharField(max_length=200)
|
||||||
description = models.TextField(blank=True, null=True)
|
description = models.TextField(blank=True, null=True)
|
||||||
is_public = models.BooleanField(default=False)
|
is_public = models.BooleanField(default=False)
|
||||||
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
# if connected adventures are private and collection is public, raise an error
|
# if connected adventures are private and collection is public, raise an error
|
||||||
def clean(self):
|
def clean(self):
|
||||||
|
|
|
@ -31,11 +31,11 @@ class AdventureViewSet(viewsets.ModelViewSet):
|
||||||
pagination_class = StandardResultsSetPagination
|
pagination_class = StandardResultsSetPagination
|
||||||
|
|
||||||
def apply_sorting(self, queryset):
|
def apply_sorting(self, queryset):
|
||||||
order_by = self.request.query_params.get('order_by', 'name')
|
order_by = self.request.query_params.get('order_by', 'created_at')
|
||||||
order_direction = self.request.query_params.get('order_direction', 'asc')
|
order_direction = self.request.query_params.get('order_direction', 'asc')
|
||||||
include_collections = self.request.query_params.get('include_collections', 'true')
|
include_collections = self.request.query_params.get('include_collections', 'true')
|
||||||
|
|
||||||
valid_order_by = ['name', 'type', 'date', 'rating']
|
valid_order_by = ['name', 'type', 'date', 'rating', 'created_at']
|
||||||
if order_by not in valid_order_by:
|
if order_by not in valid_order_by:
|
||||||
order_by = 'name'
|
order_by = 'name'
|
||||||
|
|
||||||
|
@ -52,6 +52,13 @@ class AdventureViewSet(viewsets.ModelViewSet):
|
||||||
if order_direction == 'desc':
|
if order_direction == 'desc':
|
||||||
ordering = f'-{ordering}'
|
ordering = f'-{ordering}'
|
||||||
|
|
||||||
|
# reverse ordering for created_at field
|
||||||
|
if order_by == 'created_at':
|
||||||
|
if order_direction == 'asc':
|
||||||
|
ordering = '-created_at'
|
||||||
|
else:
|
||||||
|
ordering = 'created_at'
|
||||||
|
|
||||||
print(f"Ordering by: {ordering}") # For debugging
|
print(f"Ordering by: {ordering}") # For debugging
|
||||||
|
|
||||||
if include_collections == 'false':
|
if include_collections == 'false':
|
||||||
|
|
|
@ -25,6 +25,7 @@ export type Adventure = {
|
||||||
latitude: number | null;
|
latitude: number | null;
|
||||||
longitude: number | null;
|
longitude: number | null;
|
||||||
is_public: boolean;
|
is_public: boolean;
|
||||||
|
created_at?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Country = {
|
export type Country = {
|
||||||
|
@ -61,6 +62,7 @@ export type Collection = {
|
||||||
description: string;
|
description: string;
|
||||||
is_public: boolean;
|
is_public: boolean;
|
||||||
adventures: Adventure[];
|
adventures: Adventure[];
|
||||||
|
created_at?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type OpenStreetMapPlace = {
|
export type OpenStreetMapPlace = {
|
||||||
|
|
|
@ -300,6 +300,15 @@
|
||||||
/>
|
/>
|
||||||
<br />
|
<br />
|
||||||
<p class="text-md font-semibold mt-2 mb-2">Order By</p>
|
<p class="text-md font-semibold mt-2 mb-2">Order By</p>
|
||||||
|
<label for="name">Created At</label>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="order_by"
|
||||||
|
id="created_at"
|
||||||
|
class="radio radio-primary"
|
||||||
|
checked
|
||||||
|
value="created_at"
|
||||||
|
/>
|
||||||
<label for="name">Name</label>
|
<label for="name">Name</label>
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import AdventureCard from '$lib/components/AdventureCard.svelte';
|
import AdventureCard from '$lib/components/AdventureCard.svelte';
|
||||||
import NotFound from '$lib/components/NotFound.svelte';
|
import NotFound from '$lib/components/NotFound.svelte';
|
||||||
import type { Adventure } from '$lib/types';
|
import type { Adventure, OpenStreetMapPlace } from '$lib/types';
|
||||||
|
import { onMount } from 'svelte';
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
|
import { page } from '$app/stores';
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
|
|
||||||
|
@ -10,6 +12,29 @@
|
||||||
adventures = adventures.filter((adventure) => adventure.id !== event.detail);
|
adventures = adventures.filter((adventure) => adventure.id !== event.detail);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let osmResults: OpenStreetMapPlace[] = [];
|
||||||
|
|
||||||
|
let query: string | null = '';
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
query = urlParams.get('query');
|
||||||
|
|
||||||
|
fetchData();
|
||||||
|
});
|
||||||
|
|
||||||
|
async function fetchData() {
|
||||||
|
let res = await fetch(`https://nominatim.openstreetmap.org/search?q=${query}&format=jsonv2`);
|
||||||
|
const data = await res.json();
|
||||||
|
osmResults = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
let res = await fetch(`https://nominatim.openstreetmap.org/search?q=${query}&format=jsonv2`);
|
||||||
|
const data = await res.json();
|
||||||
|
osmResults = data;
|
||||||
|
});
|
||||||
|
|
||||||
console.log(data);
|
console.log(data);
|
||||||
let adventures: Adventure[] = [];
|
let adventures: Adventure[] = [];
|
||||||
if (data.props) {
|
if (data.props) {
|
||||||
|
@ -17,12 +42,24 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if adventures.length === 0}
|
{#if adventures.length === 0 && osmResults.length === 0}
|
||||||
<NotFound error={data.error} />
|
<NotFound error={data.error} />
|
||||||
{:else}
|
{:else}
|
||||||
|
<h2 class="text-center font-bold text-2xl mb-4">AdventureLog Results</h2>
|
||||||
<div class="flex flex-wrap gap-4 mr-4 justify-center content-center">
|
<div class="flex flex-wrap gap-4 mr-4 justify-center content-center">
|
||||||
{#each adventures as adventure}
|
{#each adventures as adventure}
|
||||||
<AdventureCard type={adventure.type} {adventure} on:delete={deleteAdventure} />
|
<AdventureCard type={adventure.type} {adventure} on:delete={deleteAdventure} />
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="divider"></div>
|
||||||
|
<h2 class="text-center font-bold text-2xl mb-4">Online Results</h2>
|
||||||
|
<div class="flex flex-wrap gap-4 mr-4 justify-center content-center">
|
||||||
|
{#each osmResults as result}
|
||||||
|
<div class="bg-base-300 rounded-lg shadow-md p-4 w-96">
|
||||||
|
<h2 class="text-xl font-bold">{result.display_name}</h2>
|
||||||
|
<p>{result.type}</p>
|
||||||
|
<p>{result.lat}, {result.lon}</p>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue